<?xml version="1.0" encoding="UTF-8"?>

<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>joshlf.com</title>
  
  <subtitle>The homepage of Josh Liebow-Feeser</subtitle>
  
  <link rel="self" type="application/atom+xml" href="https://joshlf.com/atom.xml"/>
  <link rel="alternate" type="text/html" href="https://joshlf.com/posts/"/>
  <generator uri="https://www.getzola.org/">Zola</generator>
  
      
  <updated>2026-08-17T00:00:00+00:00</updated>
      
      
    
  <id>https://joshlf.com/atom.xml</id>
  <entry xml:lang="en">
    <title>Netstack.FM Interview</title>
    <published>2026-08-17T00:00:00+00:00</published>
    
    <updated>2026-08-17T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/netstack-fm-ep-10/"/>
    <id>https://joshlf.com/posts/netstack-fm-ep-10/</id>
    
      
    
    <content type="html" xml:base="https://joshlf.com/posts/netstack-fm-ep-10/">&lt;p&gt;&lt;em&gt;This is an edited transcript of my &lt;a rel=&quot;external&quot; href=&quot;https://netstack.fm/episodes/zerocopy-with-joshua-liebow-feeser&quot;&gt;October 21, 2025 interview&lt;/a&gt; on episode 10 of the Netstack.FM podcast, &quot;Zerocopy with Joshua Liebow-Feeser&quot;, hosted by Glen De Cauwsemaecker and produced by Plabayo BV. Published here with permission. The transcript has been lightly edited for clarity.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In this conversation, Glen and I discuss the origins and design of Netstack3 and zerocopy, along with zero-copy parsing, formal verification, and safe transmutation. We also discuss the broader philosophy behind my work: applying a mathematical standard of precision to systems engineering, distinguishing a fuzzy and intuitive understanding of a system from one strong enough to justify confidence, and using that deeper understanding to hide complexity behind simple, reliable abstractions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elizabeth (Plabayo)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is netstack.fm, your weekly podcast about networking, Rust, and everything in between. You are listening to episode 10, recorded on the 14th of October, 2025, where Glen has a conversation with Joshua, a software engineer at Google, where he drives adoption of zerocopy and similar design patterns forward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen (Plabayo)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hello, welcome to netstack.fm. This week I will have a conversation with Joshua. He&#39;s one of the original developers behind Netstack3 and he&#39;s also the creator of zerocopy, which is a crate that makes zero-cost memory manipulation effortless. It was originally built for Fuchsia, but zerocopy is now used by over 400 crates on crates.io with nearly 300 million downloads. So welcome, Joshua.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, thanks so much for having me. I&#39;m really looking forward to this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes, I&#39;m very happy with this conversation because we talked in episode 8 with your colleague Bruno a bit about Netstack3 and he mentioned a bit about zerocopy. He also mentioned a lot about Netstack3 but he was less familiar with the origins of it. So before we dive into that, could you tell me a bit more about your own origins, Joshua?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure. So, yeah, I got into the software world in a way that a lot of people do, I think, which is I was originally interested in middle school, so I was maybe 12, 13, in just making my computer do things that it did not want to do. And I got into it through necessity—necessity is the mother of invention. I would have to Google, &quot;How do I do this thing?&quot; And then, you know, you&#39;d find a blog post that says, you type this into the command line and I wouldn&#39;t really understand what I was doing, but, you know, and then it would break and whatever.&lt;/p&gt;
&lt;p&gt;And so I sort of got into computers that way, just sort of wanting to make my computers do, you know, like I got into, into, let&#39;s say, the IT side of things before I got into software, like into programming. And then I took a software engineering class, like a programming class, in my senior year of high school and just fell in love with it. I mean, for all of the reasons that all of us who are listening to this podcast, I&#39;m sure can empathize with.&lt;/p&gt;
&lt;p&gt;So I ended up majoring in computer science in college and then did a follow-on master&#39;s. Throughout that experience, I was interested in the mathematical side of computer science. I was never amazing at math, but I was pretty decent at discrete math, proofs, models of computation, Turing machines, and that sort of thing. But I also really, really enjoyed the system side. And obviously that&#39;s sort of where I ended up. And as we&#39;ll talk about in this episode, there&#39;s sort of a through line there of figuring out how you can make systems feel like math. I think that&#39;s sort of a theme in my career is really liking the nitty-gritty details but being bothered by how ugly they are and sort of feeling like, wouldn&#39;t it be cool if the networking code that you write could feel as clean and pretty as your CS 101 binary tree implementation or something like that.&lt;/p&gt;
&lt;p&gt;So that was my history. I focused earlier in my career on security for the most part. So in my first few jobs, I was at Cloudflare working on their security team for a bit. And then I moved to Google working on the Fuchsia operating system. And I was on the security team there for a while. And actually, Netstack3, which as you said, we&#39;ll talk about in a second, was just a side project for a while while I was on the security team. And then I worked on Netstack3 full-time for about four years.&lt;/p&gt;
&lt;p&gt;And then now I&#39;m back on the security team and focusing more on the programming language security side of things. You know, there&#39;s a whole world of, you know, being interested in cryptography and, you know, more hardcore sorts of stuff. I mean, I had a, you know, a stint at Cloudflare where I was even like mostly working with the lawyers on like, you know, corporate policy, you know, how many days does a message get to exist in our chat system before it&#39;s automatically removed as part of our data retention policy.&lt;/p&gt;
&lt;p&gt;So I had a previous life interested more in the sort of more real world, let&#39;s say, side of security, but those days are maybe behind me. We&#39;ll see. But that&#39;s not what I work on right now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, anyway, there&#39;s always a lot of connection with networking and systems and the real world. So, I mean, it&#39;s very cool. Not everybody who develops systems studied computer science. Do you think knowing particular areas of mathematics—discrete mathematics, for example—would help them?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, that&#39;s a really good question. I have seen this both ways. I tend to be biased toward the theoretical side of things. It&#39;s not that I ever actually think that your average systems engineer needs to do theory on a day-to-day basis, right? Even in my extremely weird niche job, which we&#39;ll talk about later, I rarely do proofs. I do them occasionally, but not often. The vast majority of software engineers and even of systems engineers are never going to be doing like abstract math.&lt;/p&gt;
&lt;p&gt;The point is not that it&#39;s actually a job skill in the way that like learning calculus is a job skill for an engineer or something like that, right? For like a mechanical engineer. Rather it&#39;s about training yourself to think precisely. You know, thinking precisely is not something humans do naturally. It&#39;s not something that we&#39;re born to be very good at. And so you really have to train that intuition. And I happen to think that formal math training is one of the fastest ways of practicing precise thinking.&lt;/p&gt;
&lt;p&gt;So the recommendation that I usually give to people who are early in their CS careers, they&#39;re doing a boot camp or they&#39;re in college or something like that, is: at least take a discrete math class, learn to do proofs, and take it really seriously. It&#39;s not that you&#39;re going to be using induction or set theory or something like that in your actual job. You probably won&#39;t. But the ability to think precisely is one of the characteristics that separates the great systems engineers from the good systems engineers. I basically don&#39;t know anyone who is in charge of large-scale systems or really, really challenging, really advanced systems who doesn&#39;t have that ability, whether they learned it formally or not. I know a lot of people who are extremely good at software engineering who do not have undergraduate degrees, but all of them have the ability to think precisely and clearly.&lt;/p&gt;
&lt;p&gt;And all of them had to learn that at some point because it&#39;s not something that comes naturally. So however you get that, practice thinking clearly and precisely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay, that&#39;s a very precise answer. Thank you very much. So Rust helps us a lot because it has a very rich type system. It also has a borrow checker and all kinds of nice tools, but it doesn&#39;t help with all kinds of logic bugs, like bugs in your system logic. Of course it couldn&#39;t. Then, next to that, sometimes you need to do unsafe actions. Later we will talk about zerocopy, which claims it does the unsafe for you so that we don&#39;t have to do it.&lt;/p&gt;
&lt;p&gt;And we will also talk a bit about how you can apply this methodology to your own projects or your own libraries. Now as part of proving that you are safely doing unsafe, you make use of formal verification tools like Kani. Does using Kani require mathematical knowledge, or is the mindset of precise thinking enough? How much mathematics is actually involved? I know a little about Coq—C-O-Q—but not much about Kani. How closely related are they, and how does mathematics help?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, the answer in terms of something like Kani is that it probably helps to have a little bit of sense of the math, but it is not necessary. Now, the work the people building Kani are doing is super hardcore and theory-heavy. I mean, they&#39;re basically building on top of a theorem prover. I don&#39;t remember which theorem prover they&#39;re building on top of, but they&#39;re building on top of like a SAT solver or an SMT solver or something like that, so apologies for the word soup there.&lt;/p&gt;
&lt;p&gt;But basically they&#39;re building on top of tools that are very math heavy. And so if you&#39;re developing the internals of Kani, you probably need to have a pretty solid grasp of the theory there. To build on top of it, to use Kani, I have not found it to be super necessary. But again, you don&#39;t need to know the theory, you just need to be able to think precisely. The Kani developers will yell at me for oversimplifying, but a rough example is that you give it a program resembling a test.&lt;/p&gt;
&lt;p&gt;So if you think about, I have a function and I want to confirm that it is correct, I&#39;m going to write a test and I&#39;ll provide a few different example inputs and I&#39;ll make sure that I get the output that I wanted. Kani basically allows you to do that for every possible input. Instead of testing a few selected inputs—or fuzzing with randomly generated inputs—Kani constructs a mathematical proof over every possible input. It asks: across the abstract space of every input this function could receive, can it prove that the output has the expected properties?&lt;/p&gt;
&lt;p&gt;What that really means is that it has a list of properties, like whether your code will ever panic or exhibit undefined behavior. So it has a few specific things that it means when it says &quot;correct&quot;. But basically that&#39;s the idea. It&#39;s thinking very precisely. So again, you don&#39;t need to actually necessarily understand the theory, but it&#39;s useful to be able to understand and sort of work with in your head a statement like, for all possible inputs, the program behaves correctly, right? It&#39;s a very sort of discrete math proof sort of statement.&lt;/p&gt;
&lt;p&gt;So tools like that are, they&#39;re super helpful. You don&#39;t necessarily need to understand the rigor underneath them, but it does help to be able to think precisely in order to know what it is that they are giving you, like the power that they&#39;re giving you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, I understand. Thank you very much. Now, we talked a bit about your background and I would like to shift our attention a bit to the start of Netstack3. You discussed or you said before that it got started as a side project. Is this one of those things that you&#39;re allowed to work on some personal interests within Google? Is that how it got started?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so basically the history here is I joined the Fuchsia team in April of 2018. At that point, Fuchsia was a very research-oriented project. So at that point in its history, there were a lot of people who were thinking very deep philosophical thoughts about how to design an operating system. The existing networking stack at the time was this thing called Netstack2. I won&#39;t go too much into the history here because Bruno is in your previous episode, I think it&#39;s episode eight. Bruno already went into a lot of the background here for Netstack2, but basically it was a networking stack borrowed from another team at Google—&quot;forked&quot; is not quite the right term. It&#39;s not forked because they were still, you know, they were contributing upstream patches and all that.&lt;/p&gt;
&lt;p&gt;It was written in Go. And there was a desire to move to a new networking stack that was (A) written in a different language. So there was a lot of Rust in the Fuchsia operating system at the time. And so the thinking was, if we do this in Rust, then it&#39;ll be better from a performance standpoint. It will be more predictable, right? Garbage collected languages tend to be unpredictable in terms of their performance. They tend to introduce latency spikes at different points.&lt;/p&gt;
&lt;p&gt;It&#39;ll be better on memory usage because you can more tightly control when you allocate on the heap as opposed to the stack and how eagerly resources are freed. So all of those things were in the air. People were thinking about this, but no one was taking the idea seriously or no one was actively working on it. Since I have the platform of a podcast, I&#39;ll use it as a bit of a soapbox. This was a classic example of—I&#39;m going to say that the phrase is, like, ask for forgiveness, not permission. That&#39;s a bit glib. It wasn&#39;t like I went off and did something that people didn&#39;t want me to do.&lt;/p&gt;
&lt;p&gt;But I was this junior engineer, right? I was only about two years into my career at that point. It was sort of absurd for me to claim I&#39;m going to go build this networking stack. But I did it. I just went to one of the people on the networking team and I said, hey, I want to do a networking stack from scratch in Rust. And this guy, Tim, Tim is still on the team. Tim&#39;s a great guy.&lt;/p&gt;
&lt;p&gt;Tim, to his credit, was like, sure, kid, go ahead. Like, you know, like, I support you. I think this is going to be awesome. Let&#39;s see what happens. And just to give a sense of the hubris, when Tim first asked me, he said, OK, like, how long do you think it&#39;s going to take us to get to like TCP? My previous networking experience at this point, I had worked like, you know, on networking software in general, but I had not worked in the networking stack itself except for an academic context.&lt;/p&gt;
&lt;p&gt;So I had implemented TCP/IP. I had implemented a networking stack as part of a course in college, and then I actually TA&#39;d that course, so I implemented it again. So I had done it before, but in an academic context. And those of you who are professional software engineers will know those are very different things. And so Tim said, when do you think you&#39;re going to get TCP? And I said, ah, three months from now maybe. I think it ended up taking us like four years to even start working on TCP.&lt;/p&gt;
&lt;p&gt;So it was definitely the sort of thing where a lot of it was just me being like just sort of naive, right? Thinking, &quot;This will be easy.&quot; Well, you know, I&#39;ve done a net stack twice before, right? Like how hard could it be? But again, to Tim&#39;s credit, he was willing to sort of, you know, take a chance and, you know, as we now know, Netstack3 ended up being very successful. And so, you know, it was definitely the right call, I think, to invest in it. So, yeah, to get back to your specific question about the history, it was a side project for me for about a year.&lt;/p&gt;
&lt;p&gt;So I was working on it, you know, at first it was literally a 20% project, which is like a formal Google thing where, as you said, you can work on a project of your own interest. And then it switched to being sort of more like a 50% project where my boss on the security team was letting me work a little bit more on it. We ended up having external contributors during that year. So that was how Bruno came on as one of the people who was working on the project within its first, I don&#39;t know, maybe six months, nine months, something like that. We had a few other people who were interested in it. I was very lucky that a net stack is a very sort of like... you know, sexy project to work on, right?&lt;/p&gt;
&lt;p&gt;And so we had a lot of interest from other people at the company who were really excited to donate their time to it. But that was sort of the history. It was just sort of a scrappy, like, you know, us-in-our-free-time sort of thing for about the first year. And then within a year, it became very clear that it was not going to be possible for me to give it the amount of attention that it deserved as just sort of this like part-time thing.&lt;/p&gt;
&lt;p&gt;So I actually switched in early 2019. I switched to working on the networking team. So I actually moved bosses and all that jazz and then worked on it for, I guess it would have been another three years. So I think I worked on it in total for about four years. And yeah, so I was working on it for that time. And then when I moved back to the security team, which is where I am now, and back to working on zerocopy, which we&#39;ll talk about later, Bruno took over leadership from me at that point. And Bruno has been the tech lead of that project since then.&lt;/p&gt;
&lt;p&gt;And so, you know, all of the cool shit that they&#39;ve done over the past few years is, you know, credit to him and the current team. And they&#39;ve done some very, very, very impressive things, which I&#39;m sure we&#39;ll talk about. So he deserves a huge amount of credit for shepherding that project to where it is now. And we&#39;ve just had a really, really good, really talented set of engineers who have worked on it. But anyway, yeah, so that was sort of the history. As Bruno mentioned, it&#39;s now at the point where we&#39;re mostly transitioned, Fuchsia is mostly transitioned from Netstack2 to Netstack3. I don&#39;t know that, again, I&#39;m not on the team anymore, so I don&#39;t know the exact details.&lt;/p&gt;
&lt;p&gt;I don&#39;t keep like, you know, super, super good tabs on it. But I think they&#39;re a good chunk of the way through that transition, is my rough understanding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, that&#39;s also what I got more or less. Now, in your own words, would you be able to tell me like why they believed in it so much that they allowed this project to be worked on more and more because, okay, first it was just a little side project and Tim believed in you so far, I get it. But at some point they do need to see something that they think like, okay, okay, this is definitely even though it&#39;s like a kid doing it, like clearly this is something like—would you be able to know why that was that they certainly believed in it so much?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So that&#39;s a really good question. The honest answer is I don&#39;t know. I can speak to the virtues of the project, and I&#39;m happy to talk about that. What was their actual calculus? Impossible to know what&#39;s in somebody else&#39;s head. You should have Tim on the podcast. He would be a good guest.&lt;/p&gt;
&lt;p&gt;I think, I don&#39;t know, do you feel like this is maybe a good opportunity to talk about some of the project? We were talking beforehand about, you know, some of the interesting things we did. I think that&#39;s maybe a way of answering that question without actually speculating about what was in Tim&#39;s head at the time. Maybe that is a thing we should transition to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, yeah, that&#39;s fair enough. We definitely don&#39;t want to start speculating.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay. Yeah, exactly. Again, you should have Tim on. He&#39;s a cool guy. So, yeah, basically, I mentioned before that a theme in my career has been really enjoying systems software, but being bothered by how messy it is. And I think, again, this dovetails really nicely with the thing we were talking about before about thinking precisely. One of the things that I have always really valued, and this sort of comes from the security world, I think, is that in the security world, especially in math and when you&#39;re doing cryptography, for example, right, the very sort of like mathy side of security, you are taught to never, never be confident that something is the case unless you can completely prove formally, rigorously that it is actually the case.&lt;/p&gt;
&lt;p&gt;Right? So, you know, the history of cryptography is littered with, I think the Bruce Schneier quote is, &quot;any person is smart enough to construct a system that is clever enough that they are not smart enough to figure out how to break.&quot; So it&#39;s very tempting to feel like you have designed something that is perfectly secure that is not actually secure. And it contains, you know, a vulnerability that you didn&#39;t think of.&lt;/p&gt;
&lt;p&gt;And so you are constantly trained to be adversarial towards your own designs and to really understand what it feels like, the sort of emotional, psychological feeling of being certain and to distinguish “this feels basically true” from “no, I am 100% confident that this is true.” And so that cryptographic experience, like learning cryptography and taking cryptography classes and working through exercises and things like that, really gave me this sort of appreciation for the difference between &quot;I understand how this works&quot; and &quot;I &lt;em&gt;really&lt;/em&gt; understand how this works.&quot; I think that was one of the really useful parts of my education for the work that I do now was being able to distinguish between &quot;I understand how this works&quot; and &quot;I &lt;em&gt;really&lt;/em&gt; understand how this works.&quot; And so, as I said, the theme in my career has been trying to marry these two things, right?&lt;/p&gt;
&lt;p&gt;Enjoying systems programming, but wanting to get back that cryptographic type of feeling of, &quot;I &lt;em&gt;really&lt;/em&gt; understand how this system works.&quot; And systems programming in general has historically encouraged you to live more in the former domain. It&#39;s just often not possible to so completely understand the details of the system that you have that level of certainty about how it behaves. And so maybe there are some super hardcore kernel hackers, blah, blah, people who really, really understand the system.&lt;/p&gt;
&lt;p&gt;But in general, there&#39;s a lot of sort of like, look, you understand it as well as you can, and then you make progress. It&#39;s sort of a pragmatic thing. And so when I started working on Netstack3, I wanted to have that feeling, right? I wanted to be able to say that I actually understood how the system worked. And the thing that I love about Rust is that it basically turns what normally is a systems programming type of problem, where you just kind of have to like vaguely understand what&#39;s happening and it&#39;s going to give you access to lots of low level system details and just sort of, you know, in a C or C++ style, trust that you&#39;re holding it correctly. It basically in the type system encourages you to think more precisely and say, no, I need you to tell me exactly the behavior of this program, right? If the lifetimes don&#39;t match up, I&#39;m not going to compile. If the ownership isn&#39;t perfect, I&#39;m not going to compile, right? It&#39;s forcing you to think very precisely about the behavior of your program and encode that behavior in a way that is legible to the compiler.&lt;/p&gt;
&lt;p&gt;And so that is a lot of philosophy. But there&#39;s a question then of how you actually turn that into practice. And so in Netstack3, what that looked like was basically saying: every time there is some form of correctness, some sort of property that we might want the netstack to have, we&#39;re going to try to figure out how to actually represent that as a first-class abstraction with its own types and its own representation. And then we sort of pushed that very far. One of the things that&#39;s really nice about working in the networking world, and I think I&#39;ve been in some sense spoiled by this, is it is completely unambiguous what a correct program looks like.&lt;/p&gt;
&lt;p&gt;If you were building a video game, there is no sense in which you have built the correct or incorrect video game, right? Maybe you&#39;ve built a better video game or a worse video game or something like that. There&#39;s no definition of correctness. In the networking world, the definition of correctness is: &quot;Did you implement the RFC correctly?&quot; And so artists talk all the time about how requirements and restrictions can actually be very freeing because they sort of free you from the paralysis of choice. The same is true in the software world. Having a very precise specification of what you&#39;re supposed to be building is very freeing because it lets you innovate not on what you&#39;re building, but how you&#39;re building it.&lt;/p&gt;
&lt;p&gt;And that was sort of one of the things that we experienced in Netstack3 was that having such a precise constraint about what we were supposed to build, let us focus all of our creative energies on the software engineering aspect of things instead. And that was really sort of how I conceived of Netstack3. I thought of it as this, like the main challenge was the software engineering, right? How do you, if you&#39;ve taken a networking class, you may have seen the five layer model or the seven layer OSI model or whatever, and you have this very clean abstraction boundary, Ethernet sits there and doesn&#39;t know anything about how IP works and IP sits above ethernet and doesn&#39;t know anything about how ethernet works. And TCP sits above IP and doesn&#39;t know how IP works. It doesn&#39;t even know that ethernet exists.&lt;/p&gt;
&lt;p&gt;That is a complete lie. That is a beautiful, nice, simple picture to provide a mental model that we can teach to students. But if you&#39;ve worked in the real networking world, you know that we violate those abstraction boundaries all the time. So there are instances in which TCP actually needs to reach down not just into IP but actually through IP into the boundary layer between IP and Ethernet in order to muck with the neighbor table entries in IPv6, if that&#39;s a term that the listeners are familiar with. If you&#39;re not familiar with it, it doesn&#39;t matter. The high-level point is just that the clean modular picture that you were given of a network stack is a complete lie. These things are complected together to high heaven.&lt;/p&gt;
&lt;p&gt;And so your natural inclination, if you&#39;re going to read all of these RFCs and then sit down and ask, &quot;How do I actually implement this?&quot; You&#39;re basically given what is sort of like the RFC equivalent of spaghetti code. And so your natural inclination is to write spaghetti code. The most natural, obvious way of implementing a networking stack is just to have every piece of the stack call directly into every other piece of the stack and all be complected together. And there&#39;s no way for you to pull apart an individual component in order to reason about its behavior in isolation. And so, as I said, the benefit of working on a net stack is that the requirements are specified for you so you can aim your creativity at the software implementation.&lt;/p&gt;
&lt;p&gt;And what we did in Netstack3 was we aimed our creativity at the question, how do you recover good software engineering practices and principles out of a world that is just trying so hard to make you implement an ugly spaghetti code mess? How do you basically push back against that and say, no, we&#39;re going to do it right. We&#39;re going to do it in a way that is testable and modular and easy to reason about and so on and so forth.&lt;/p&gt;
&lt;p&gt;And so that was the main challenge. And Rust&#39;s type system was so, so, so helpful in achieving that goal. Because basically there are so many instances in which one part of the stack needs to reason about what another part of the stack is doing. And if you were writing in a language that either didn&#39;t give you the rich type system of Rust, or even if you&#39;re writing in Rust, but just not making use of the rich type system, you would be really tempted to just go ahead and do that, right? TCP is going to call directly into NDP. That&#39;s just going to happen. And if you want to reason about the behavior of that interaction, you just kind of have to understand how the whole system works.&lt;/p&gt;
&lt;p&gt;What Rust lets you do instead is say, okay, TCP is going to call into NDP. That is unavoidable. But we can very carefully shape the API in such a way that what it means for that interaction to be correct is completely expressed in the type system. And so if we hold that interaction incorrectly, it will not compile. So yes, there is complexity. These things are calling into one another. That is unavoidable.&lt;/p&gt;
&lt;p&gt;But all of that complexity is made explicit in the type system. And what that lets me do is anytime I want to change things or experiment with different ways of expressing that complexity, I am sure that if I get it wrong, my program won&#39;t compile. And that is so much more pleasant of a developer experience. And it makes building complicated APIs and complicated interactions actually feasible because I can just iterate quickly. I can trust that if I made a mistake, I&#39;ll catch it immediately as opposed to the experience that I think a lot of us have had in large code bases where you say, &quot;Boy, I could do that, but I would have no way of convincing myself that it was correct.&quot;&lt;/p&gt;
&lt;p&gt;And so I&#39;m just not going to do it. There is an engineering virtue in simplicity. There is an engineering virtue in holding yourself back and saying, I am going to sort of exercise humility and not do the crazy optimization because I can&#39;t trust that it&#39;s correct. What Rust says is, &quot;No, go ahead, try it. As long as you encoded it in the type system, I&#39;ll tell you whether you got it correct or not.&quot; And so, in some sense, Rust is like a language of hubris, right? It&#39;s a language that says, &quot;go ahead, try your crazy idea. I&#39;ll stop you if you got it wrong.&quot;&lt;/p&gt;
&lt;p&gt;And so that was really what we did in Netstack3 was to say, let&#39;s actually go ahead and try all the crazy optimizations, but we&#39;ll be very careful to encode correctness in the type system so that we know when we got it wrong. That attitude is the origin of many of our abstractions, including zerocopy, which we&#39;ll discuss later of saying, let&#39;s push this as hard as we can. But at every single step, make sure we&#39;re doing good software engineering and never getting out over our skis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hmm, that&#39;s very cool. And I totally agree. I mean, my original background is C++ and compared to that developing Rust is a world of difference. Now we are also the developers of Rama. It&#39;s like an open source network framework and it&#39;s also there where we also really think in these layers and where we like, and it&#39;s nice because like you said, when you implement these RFCs, which is a very pleasant experience because you can really, as you say yourself, think about how you implement it. Then it&#39;s very nice. And the way we implement this is that we can very abstractly, okay, let&#39;s say we implement the SOCKS5 RFCs or we implement the HTTP RFCs.&lt;/p&gt;
&lt;p&gt;Well, there are many HTTP RFCs, but like we can really think about it and implement them in a way that&#39;s very abstract. Like, let&#39;s say SOCKS5 needs to work with some kind of byte stream. It doesn&#39;t really matter which byte stream. You don&#39;t need to worry about whether it&#39;s on TCP or not. It also affects the way you stack it. Are you familiar with the Tower system and the Tower &lt;code&gt;Service&lt;/code&gt; trait?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have heard of it. I know a very small amount about it, so basically no.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so to introduce you a bit to it, it&#39;s basically a very simple trait, which was inspired by an original framework from Twitter back in the day, which was called Finagle if I&#39;m correct. And it revolves around one single service trait, which takes an input and needs to produce an output, which can either be like, okay, or like an error. And that&#39;s basically it. And that&#39;s how you would like in a framework like Rama, like stack your layers because you would basically start with like something which may be like a TCP server and it needs something that can serve TCP streams.&lt;/p&gt;
&lt;p&gt;So that could be like some kind of TLS acceptor or it could not be, it could be like a SOCKS5 and you kind of like just stack these things on top of each other because they just wrap each other or they stack on top of each other like a turtle, however you want to think about it. And it&#39;s very nice and that&#39;s one example where I like it a lot and where we already make very good use of the type system, whereas I feel that it&#39;s much harder sometimes, it&#39;s like where you have to work with dynamic states. And I have a feeling that in Netstack3 you have a lot of clever tricks to work around this.&lt;/p&gt;
&lt;p&gt;So examples of this are things like, I don&#39;t know, let&#39;s say the TCP acceptor accepted something and it injects socket information into kind of extensions of your input because we, like I said, the service trait accepts inputs, which could be a request, but could also be like a TCP stream with some extensions, or basically just you can inject anything into it. And so in order to access those, you always have to kind of check, &quot;Is it there or not?&quot; And sometimes you might assume, &quot;This is always there,&quot; because let&#39;s say I can always assume that it&#39;s socket information, but still you have to do an unwrap there or you could just say it&#39;s fallible.&lt;/p&gt;
&lt;p&gt;And then another example of things where you kind of have to—yeah, I don&#39;t know, like those are things like all those dynamic states, I find that a lot harder to make very good use of a type system because you don&#39;t have static verification of like, yeah, this is always there in the flow. And at the same time, sometimes, for example, in our case, we have these stacks and then you can have like a giant mountain of generics, which stack and stack up, like it wraps, it wraps. And so at some point you might just choose to box or something because yeah, it&#39;s just easier.&lt;/p&gt;
&lt;p&gt;But then again, also you erase your type. Yeah, like, because I know from like a talk with Bruno that you had some clever tricks, according to Bruno, where, for example, you might change behavior based on whether it&#39;s IPv4 or IPv6. And for example, we also deal with IPv4 and IPv6, but in our case, we just use match statements, right? Like we check, okay, it&#39;s an IP address. We know that; that&#39;s what the type system says. The type system also allows us to match in an exhaustive way. We do have that and we could even use it there, but I wonder: do you ever have to work in that stack with dynamic state or do you always get away with like somehow, I don&#39;t know, not having to inject such states?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so I think in general, the philosophy that we tried to push towards was the only things that are going to be dynamic are the things that are actually dynamic. And what I mean by that is like, you know, the protocol defines them to be dynamic, right? So for example, a UDP packet is allowed to have a missing source port if memory serves. I&#39;m pretty sure that&#39;s true. There&#39;s one of the fields that&#39;s allowed to be optional. I think it&#39;s the source port. And people listening can go confirm that I&#39;m right about that.&lt;/p&gt;
&lt;p&gt;But there&#39;s one of the fields that&#39;s allowed to be optional. And so that&#39;s an instance of inherent dynamism. There&#39;s just no choice. Your netstack has to be able to handle the case that there&#39;s a missing source port. And so in those cases, what we do is we try to encode that in the type system. So we&#39;ll say, you know, I think if memory serves the UDP packet parser that we wrote, if you want to extract the source port, the source port is represented as a &lt;code&gt;NonZeroU16&lt;/code&gt;, and the getter for that field returns an &lt;code&gt;Option&amp;lt;NonZeroU16&amp;gt;&lt;/code&gt;. The caller is forced to deal with that – what do I do if there&#39;s no source port here?&lt;/p&gt;
&lt;p&gt;By contrast, if there are things that are guaranteed to be present, and it&#39;s just a limitation of the type system, then we try as hard as we can to figure out how to introduce new APIs that actually guarantee the presence of that thing. So I&#39;m trying to think of a good example of this, but basically, there are instances where you know that the RFC requires a particular thing.&lt;/p&gt;
&lt;p&gt;And so in, let&#39;s say, like parsing a packet, you might say, &quot;If this field is missing, then that&#39;s a parse error.&quot; So we&#39;re never going to parse and produce a parsed representation of this packet where the field is missing. And so that becomes an internal invariant. And then your APIs to access the fields of the packet can be infallible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The reason why I brought it up is because you were talking about when you&#39;re parsing and that&#39;s within a single layer and I feel there it&#39;s a lot easier and also in the case of something missing, once you&#39;ve developed long enough in Rust you would quite quickly think about making an option for that, so far so clear. What for me is much harder is like, and I&#39;m sure you have that same problem set in netstack, is where you cross boundaries. Because between, let&#39;s say, a TCP socket, which you accepted, and your application layers, let&#39;s say, HTTP, there are a lot of different layers, and sometimes there could be more, sometimes could be less.&lt;/p&gt;
&lt;p&gt;For example, in like a very extreme case, you could end up with eight layers in between. Right? Because you&#39;re dealing with SOCKS5, you&#39;re dealing with TLS, you&#39;re dealing with all kinds of stuff. Maybe also like HAProxy. I mean, you can, you know, you can think of a lot of them. And so there lies the problem, because if I would just deal with, &quot;Okay, my service is accepting a TCP stream.&quot; So that&#39;s one layer.&lt;/p&gt;
&lt;p&gt;Then I can guarantee very easily like, yeah, I can, I can get from that my client address or my server address or whatever, or my peer or whatever you call it. But once I get to, &quot;Okay, now I have a service accepting, let&#39;s say, an HTTP request.&quot; I&#39;m already very, very far in the app structure. And at that point, it&#39;s a lot harder to still, even though like conceptually, you know for certain that this comes from like a TCP packet. I mean, it somehow has a connection to that, right? Like, okay, somewhere is some task parsing this and whatever, and dealing with an actual TCP socket.&lt;/p&gt;
&lt;p&gt;But I find it much harder at that point to guarantee that you can always get socket information from this without placing a huge burden or restrictions on the system, unless I would put that kind of information directly into an HTTP request, but that doesn&#39;t seem to really fit there either.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So I think that a big answer that we have in the Netstack3 code base is just that we use types a lot. Like a lot a lot. And so I do think this is one of the limitations. So a point of philosophy here is the concept of using types. Compare and contrast that with Python or assembly or something like that, where you don&#39;t have any typing. The concept of introducing a type system tends to be really good at reasoning about properties that are local. As in, you have, if you have a function that takes an integer and returns a bool, and if I have an integer, then I can call that function and I get a bool back. It&#39;s a lot less good, in general, at talking about global program properties, right? It&#39;s a lot less good at expressing the idea that, you know, the—what&#39;s a good example of this? You know, an instance we ran into in Netstack3 is that you have interfaces and then you have sockets that can be bound to those interfaces. Those live in very different parts of the code base, but they&#39;re actually related to one another.&lt;/p&gt;
&lt;p&gt;So in theory, if the interface goes up or down, then, so let&#39;s say you have an interface, you have a TCP socket bound to that interface. If the interface goes down, the TCP socket, the correct behavior might be to close the TCP socket. That&#39;s a sort of configuration thing. But let&#39;s say, just for the sake of argument, that you want to close the TCP socket because the interface went down. How do you express that in the type system? How do you express the idea that this is a TCP socket and that it has an interface, and that the interface that it is on is definitely up because the TCP socket exists? That&#39;s actually really hard.&lt;/p&gt;
&lt;p&gt;And I will say, this is one of the things that Netstack3 didn&#39;t have a good answer for the entire time that I was there. After I left, this was one of the things that they tackled. I know that Bruno, I think, mentioned in his episode that they ended up with a fancy Arc-based system in order to track resources like this where you need to have multiple references throughout the stack to, for example, a particular interface. I don&#39;t know the exact answer of how they deal with this, but it&#39;s actually genuinely hard. And I think the Rust type system lets you encode information that is non-local more powerfully than other type systems do, but it is not perfect. Right, the Rust type system is Turing-complete. In theory, you can do anything you want in the Rust type system. That doesn&#39;t mean that it&#39;s going to be ergonomic and it doesn&#39;t mean that it&#39;s a good idea.&lt;/p&gt;
&lt;p&gt;And so in theory, you could imagine structuring a system where somehow you encode the information in the type system of like the liveness of every interface. That&#39;s probably going to make your type signatures on every single part of the stack like awful. And so partially the answer to your question is we didn&#39;t have a great answer for this. It was like an open area of research. Again, I think Rust makes it easier to encode non-local information or at least to encode more complex information. And I can talk in a second about an example of that.&lt;/p&gt;
&lt;p&gt;But yeah, I think it&#39;s a really hard problem. And I don&#39;t think we had a great answer for it. I think that being able to encode the local information alone is such a win compared to C/C++ that it&#39;s still a big difference, but that does not mean that the effort is done. We still have a long ways to go in figuring out how to develop large system software in Rust in a way that is completely infallible, in a way that if it compiles then it works. If it compiles then it works is true in Rust way more than it is in other languages, but it&#39;s not 100% true.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, yeah, for sure. And anyway, in the end, you&#39;re forced to deal with the fact that it&#39;s there or not there and you can fail it. And in the end, I learned to live with it. Like in the beginning, I tried to do everything with static states and it was, it became after three years of development, such a disaster that recently we switched away from that. And at some locations it makes sense and you can do it. And other layers, most of the layers, you actually just learn to deal with the fact that some things are just dynamic. And given the fallible nature of networking, that&#39;s fine as long as you do use, like you said, locally, the Rust type system very well to deal with those things and not just panic or assume; you do deal with the possibility, even if you know most likely it&#39;s not because you want to make sure that depending on how you stack it, it works.&lt;/p&gt;
&lt;p&gt;So, I mean, I learned to live with it, but yeah, sometimes I do wish like a lot more could be done, but yeah, it&#39;s a trade-off and okay. So we talked a lot about systems already. We talked a bit about designs. We talked about how Rust helped you. We talked about your background. Now, what is not clear to me and which also allows us to segue into zerocopy is at what point zerocopy became a thing, how it was conceptualized, and at what point you started to work on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so zerocopy was like a classic necessity as the mother of invention project. We actually started it probably within a month of starting Netstack3. So Netstack3 dates to maybe May of 2018, if memory serves, and zerocopy, I think I wrote the first lines of code in like June of 2018. So super, super early on. Basically, the problem that we were trying to solve was that we wanted to do zero-copy parsing. So I should clarify here, zerocopy as a phrase is the name of this crate. Zero-copy, which unfortunately is pronounced identically, refers to a style of parsing.&lt;/p&gt;
&lt;p&gt;So if you receive a message from a network or you&#39;ve read in a file format off of the disk or something like that, and you want to parse it, for performance reasons, you would like to not have to allocate more memory elsewhere. You would like to be able to reuse the existing buffer that you have and just sort of operate on it in place. That&#39;s what zero-copy parsing refers to: the idea that you&#39;re not making copies from the buffer into another location.&lt;/p&gt;
&lt;p&gt;So we wanted to do that style of parsing, and in C/C++ this would be fairly straightforward, right? You would define a struct whose memory layout happens to be the same as the memory layout of the packet format that you&#39;re trying to parse. And then you would take your pointer, right? You would have like a &lt;code&gt;char *&lt;/code&gt; or something like that. And you would do a cast into your struct type, right? So let&#39;s say you&#39;re trying to parse a UDP packet. You might say, &quot;Okay, I&#39;m going to cast my &lt;code&gt;char *&lt;/code&gt; pointer into something like a &lt;code&gt;udp_header *&lt;/code&gt;,&quot; right?&lt;/p&gt;
&lt;p&gt;And now I have a pointer that is typed, right? It&#39;s a struct pointer. And I can just go do field access, right? So I can take my pointer and I can do, you know, &lt;code&gt;packet-&amp;gt;src_port&lt;/code&gt; or something like that. So that was roughly what we wanted to do in Netstack3. Of course, doing that in Rust is unsafe. And, you know, if you&#39;ve worked with this stuff, you&#39;ll know.&lt;/p&gt;
&lt;p&gt;And if you haven&#39;t worked with it, then you can just take my word for it. It&#39;s extremely, extremely subtle. There are many, many, many edge cases that you have to consider in order to determine whether this is sound at all. And I&#39;m not talking about edge cases at runtime that your code has to handle. I mean, edge cases in order to figure out whether it&#39;s even correct to make this program at all. So edge cases in the type system, basically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, no, I mean, I&#39;m very familiar with it because, mean, originally I come from the game industry and we did a lot of that as well. And it&#39;s also probably why in the RFCs, a lot of them, I mean, I feel the layout is often made with the exact structure in mind and some RFCs even explicitly mention the structure. And it does work, except of course, where you deal with flags. mean, if you... Maybe my memory is a bit vague here, but as far as I know, once you deal with flags you do have to at least do some kind of bitwise operation to turn it into some kind of boolean, because there is no way, even in C as far as I know, that you can just turn it directly into a struct, or am I wrong?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, in C I&#39;m not exactly sure. I don&#39;t know off the top of my head. Something tells me that there are subfields, yada yada, but I&#39;m speaking out of turn there. In Rust, the answer is no. We don&#39;t have any types in Rust that are less than one byte in size, except for types that are zero bytes in size, but that&#39;s a separate thing. There are crates out there, like the bitflags crate, or bitfields or something like that that will handle this for you, but it&#39;s a little bit higher level than we needed because we need to be able to precisely control the memory layout. I may be speaking out of turn there, maybe that is something that they support, but for whatever reason, it wasn&#39;t something we ended up reaching for.&lt;/p&gt;
&lt;p&gt;Luckily, it&#39;s not that big of a deal to do the bit manipulation stuff. It&#39;s a bit of a pain to write some manual code. Luckily, it&#39;s not a memory safety thing. The thing that really mattered for us was the memory safety aspect. The big things that you have to deal with here are you have to make sure you&#39;ve done bounds checks, right?&lt;/p&gt;
&lt;p&gt;So if I give you eight bytes and you try to cast a pointer to eight bytes, or a slice reference, right? A &lt;code&gt;u8&lt;/code&gt; slice reference that&#39;s eight bytes long, and then you convert that into a reference to some struct type that is longer than eight bytes, then that&#39;s undefined behavior, right? Because it&#39;ll allow you to read off the end into some other garbage memory. The other thing you have to deal with is alignment, right? A lot of types in Rust have some form of alignment requirement where they have to only exist at even byte addresses or byte addresses that are a multiple of four or multiple of eight or something like that. In general, if you have a slice of &lt;code&gt;u8&lt;/code&gt;, you don&#39;t know where in memory that lives, right? It might live at any arbitrary byte offset.&lt;/p&gt;
&lt;p&gt;And so even if you&#39;ve already checked the size, you also have to check the alignment. We realized that repeating all of this for every packet parser would be a persistent source of bugs. And it was also just going to be really annoying to deal with. It was like, even if we got it right, it would take a lot of effort every single time that we wanted to get it right. And so what the zerocopy library gives you is a type-level representation of properties that your type satisfies.&lt;/p&gt;
&lt;p&gt;So it&#39;s a bunch of traits, basically, and if your type implements one of those traits, that tells us something about the memory layout of your type. One of the base traits is &lt;code&gt;FromBytes&lt;/code&gt;, which basically says any bit pattern is valid for this particular type. So any pair of two &lt;code&gt;u8&lt;/code&gt;s is going to be a valid instance of a &lt;code&gt;u16&lt;/code&gt;, for example. Any bit pattern is okay for &lt;code&gt;u16&lt;/code&gt;. This is not true for all types, right? So a boolean, right, a &lt;code&gt;bool&lt;/code&gt; in Rust can only be 0 or 1. If you try to interpret the byte 2 as a &lt;code&gt;bool&lt;/code&gt; in Rust, that&#39;s undefined behavior in your program that&#39;s going to be arbitrarily wrong.&lt;/p&gt;
&lt;p&gt;So basically that&#39;s the idea, is we have these traits in zerocopy that encode the idea of... whether your types have certain properties. And then we have a bunch of functions that will do these conversions for you and use those trait bounds to force you, the user, to prove that this is actually going to be an okay conversion to do. So for example, if you want to convert a reference to a slice of &lt;code&gt;u8&lt;/code&gt;s into a reference to your type, you&#39;re going to have to prove that your type is &lt;code&gt;FromBytes&lt;/code&gt;, right? That any possible bit pattern is acceptable for your type. And you&#39;re going to have to prove that it is unaligned or that it has no alignment requirement.&lt;/p&gt;
&lt;p&gt;If you do those things, then we will provide to you an API that will at runtime check the size. We&#39;ll make sure that you&#39;ve actually given us the correct number of bytes. And then if the size check passes, then we&#39;ll do that reference conversion internally and we&#39;ll give you back a reference to your type.&lt;/p&gt;
&lt;p&gt;So that&#39;s the basic premise. It&#39;s this very low-level little like Swiss Army knife type of thing, right? It&#39;s very low-level utilities, but the point is that the API is 100% safe and you can build up much larger abstractions on top of that. All of the packet parsing in Netstack3 is built on top of zerocopy, right? So it&#39;s all you give me a buffer, I&#39;m going to convert in place the type of the buffer into a type that represents the memory layout of the particular packet format that I&#39;m trying to parse. And then I&#39;m just going to go on my way using normal Rust operations.&lt;/p&gt;
&lt;p&gt;So that&#39;s sort of what zerocopy does. It has grown a ton over time. Like it was very small in the beginning. Now it&#39;s a much, much larger crate. It&#39;s the full-time job of two different engineers. So it&#39;s grown a lot since then, but it originated with that basic need for zero-copy parsing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, I mean, it&#39;s awesome because I feel I was like I was reading through the source code of zerocopy earlier this week as I knew we would or actually last week because it&#39;s just Tuesday. Yeah, sometimes the week boundaries are unclear to me. I have three small kids, so they flow so quickly. So the last couple of days I was reading a bit through it. And yeah, it seems like then you have the &lt;code&gt;zerocopy-derive&lt;/code&gt; crate and there, I mean...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, sure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It seems that you are doing all the hard work that otherwise you would have to do manually because you&#39;re putting the correct annotations, you&#39;re putting the correct operations and checks, and you also make use of the type system to verify statically what you can verify statically. I mean... Is that like a fair summary? That it is just instead of doing it like all manually, like now you can just use like your procedural macros and the type system that you get the system of types that you build around it so that you don&#39;t have to do all that work yourself each time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, that&#39;s exactly right. Basically, there are two steps here. The second step, I&#39;ll say the second one first. The second step is if you have proven that your type satisfies these properties and that that proof is carried by the type system in the form of one of these trait implementations, then we&#39;ll provide for you all of these runtime functions that will do various operations that would normally be dangerous. Then that raises the question, how do you actually prove that your type satisfies these properties? And that&#39;s where the derives come in. Most of these properties are recursive.&lt;/p&gt;
&lt;p&gt;So basically a struct can be &lt;code&gt;FromBytes&lt;/code&gt; if all of its fields are &lt;code&gt;FromBytes&lt;/code&gt;. And so what that means is that it bottoms out at the core primitive types. So we basically just hand-wrote in the library implementations of these traits for all of the built-in types. So, you know, &lt;code&gt;u8&lt;/code&gt;, &lt;code&gt;u16&lt;/code&gt;, &lt;code&gt;u32&lt;/code&gt;, &lt;code&gt;i64&lt;/code&gt;, et cetera. We have implemented the appropriate traits for all of those built-in primitives. And then the custom derive will allow you to automatically derive an implementation of these traits for your type. And that derive will either fail during the processing of the derive itself, or it will emit code that will fail to compile if your type doesn&#39;t actually satisfy these requirements.&lt;/p&gt;
&lt;p&gt;So for example, if you have a struct that has a boolean in it and you run the derive, then the emitted code from the derive will say, &quot;Sure, your type can be from bytes if &lt;code&gt;bool&lt;/code&gt; is &lt;code&gt;FromBytes&lt;/code&gt;. But &lt;code&gt;bool&lt;/code&gt; is not &lt;code&gt;FromBytes&lt;/code&gt;,&quot; so it fails. And then in addition to that, there are extra constraints that we have where in the derive itself, we can check for other conditions and sometimes we fail during that pass as well.&lt;/p&gt;
&lt;p&gt;But yeah, your high-level description is exactly right. The derive lets us determine whether your type satisfies certain properties. And if it does, then we turn those properties into trait implementations and then zerocopy itself, the runtime code consumes those traits as a bound in order to prove that we can do certain operations soundly at runtime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, very cool. In a way, I feel, let&#39;s for example, within the framework Rama for now I&#39;m not using zerocopy myself. I feel I could definitely make use of it because for now I&#39;m doing a lot of that work myself. At the same time, I do wonder because like, okay, it&#39;s nice to do zero-copy and that&#39;s possible because you&#39;re borrowing from the memory of the slice, or you are just basically viewing it through another lens. Well, I suppose that sometimes it also just means that you are copying, you are copying, right? It&#39;s just on the stack. No, I mean, in the end, it&#39;s not like you are literally just, I suppose you just mean you don&#39;t make any allocation on the heap, but you are copying it to another, like on your stack.&lt;/p&gt;
&lt;p&gt;No, am I wrong there? Like if you, for example, would interpret a byte slice as some kind of, I don&#39;t know, TCP header or any kind of other protocol. In the end, you are copying it, but like on the stack, right?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so basically the thing that is getting copied here is the pointer, right, or is the reference. So if you have a TCP packet that you read in as a slice of &lt;code&gt;u8&lt;/code&gt; in a buffer, that is represented as a &lt;code&gt;u8&lt;/code&gt; slice, right? When you do a zero-copy conversion, you&#39;re not actually moving the bytes that are the referent of that reference. You are leaving those where they are, but the reference itself is going to be a stack variable, right?&lt;/p&gt;
&lt;p&gt;So that the reference, as in the ampersand thing, is going to live on your stack. What zerocopy is letting you do is just change your mind about the type of that reference. So it&#39;s going from a slice-of-&lt;code&gt;u8&lt;/code&gt; reference to a UDP header reference or a TCP segment header reference or something like that. The bytes themselves that are live somewhere else, maybe they live in somebody else&#39;s stack frame, maybe they live on the heap, those stay where they are and they don&#39;t get copied around.&lt;/p&gt;
&lt;p&gt;But the reference to those bytes, that is going to get moved and copied and passed around and all that jazz. And it&#39;s just a matter of changing the type system&#39;s mind about what type lives on the heap or in somebody else&#39;s stack frame or wherever it is that you&#39;re pointing to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Does that mean that you have an opaque struct and to get those properties you need to call methods and it&#39;s only then that you copy to the stack, or how does it work? I just want to figure it out. Yeah, yeah, yeah.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Right, exactly. Yeah, so let&#39;s say, I mean, it doesn&#39;t have to be opaque necessarily, but the idea would be, let&#39;s say that I want to operate on the destination port of a UDP packet. What I&#39;m gonna do is I&#39;m gonna take my slice of bytes, I&#39;m gonna convert it into a reference to a UDP packet header. Let&#39;s say that&#39;s the name of the type. That type is going to have fields, right? So it&#39;ll be a struct that has a source port, destination port, length, and checksum—the four UDP header fields. When you actually access one of those fields, let&#39;s say you do &lt;code&gt;packet.dest_port&lt;/code&gt; and you pull that out, the compiled code that Rust generates is going to be copying those two bytes from somewhere in memory into your stack, maybe into a register or maybe your stack, whatever, and then you can operate on it like normal.&lt;/p&gt;
&lt;p&gt;But basically the idea is it should generate the same machine code as if somebody had passed to your function a reference to a UDP packet header. That&#39;s sort of the idea, right? Let&#39;s imagine what would have happened if we had been operating on a reference to a UDP packet header this entire time. Ideally, that&#39;s gonna be exactly the same machine code that gets generated as if you&#39;re using zerocopy. There is a slight asterisk there, which is that we&#39;re always going to have to do a length check at runtime, so it&#39;s not going to be identical, identical, but it&#39;ll be pretty close.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That also probably means that let&#39;s say you have a function and you access that address 10 times, I suppose you want to just call that method once and then just always use the final version, right? Because you wouldn&#39;t want to do that work 10 times, I suppose, in a single function. Yeah, yeah, yeah.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Right, like you wouldn&#39;t want to do the length check 10 times. And so yeah, usually you will just do this conversion once and then you&#39;ll operate on the typed reference once you have it. You&#39;ll just operate on that from then on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay, cool. And then a lot of these protocols, also... I mean, it&#39;s very nice if everything is like in a fixed location for, like, the metadata, ports, and flags. And so that&#39;s usually the case, but then usually you also have like optional parts or, or length, like, like let&#39;s say string values or something like that. It could be like a domain name. And then usually they encode like the length in the first two bytes. Then maybe, I mean, they go even fancy to maybe they even do something like where, if it was a small value, it&#39;s like one byte; if it&#39;s a big value, it&#39;s three bytes of length and then you know the other length amount of bytes is your string value.&lt;/p&gt;
&lt;p&gt;Does zerocopy deal with that kind of stuff too?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so this has been a huge headache for us, is the answer. Basically, zerocopy today is capable of supporting any byte pattern that can be represented as a native Rust type. So if you can build a struct or an enum or a union whose memory layout is the same as the memory layout that you&#39;re trying to parse, then you&#39;re golden and zerocopy can help. But there are certain things, there are certain memory layouts that just don&#39;t correspond to any native Rust type.&lt;/p&gt;
&lt;p&gt;So the format that you were just describing, which is called TLV, or type-length-value, is basically a variable-length number of objects. And the way that you parse them is you have to sort of chomp them one at a time, where you look at the header and that tells you how many bytes to eat. And then you eat that number and then you parse to the end, and then you look at the next thing&#39;s header and that tells you how many bytes to eat and you iterate that process over and over again.&lt;/p&gt;
&lt;p&gt;There is no native Rust type whose layout is equivalent to that thing. And so zerocopy can&#39;t really help you. It could maybe help you parse an individual one of those things, right? So it could maybe help you parse like a single instance of the TLV format, a single record in the TLV sequence of records, but it can&#39;t help you parse the whole thing. And so what we did in Netstack3 is we have a crate called packet.&lt;/p&gt;
&lt;p&gt;So generally speaking, there are three sort of utility crates here that we talk about a lot. There is &lt;code&gt;net-types&lt;/code&gt;, which contains a bunch of our low-level networking primitives. This is like IP addresses and MAC addresses and stuff like that. There is &lt;code&gt;packet&lt;/code&gt;, which is low-level utilities for packet parsing. So it builds on top of zerocopy and gives you a framework for doing packet parsing, but it doesn&#39;t actually implement any specific protocol. And then we have &lt;code&gt;packet-formats&lt;/code&gt;, which is all the packet formats. So TCP, UDP, IPv4, IPv6, MLD, IGMP. The list goes on. It&#39;s an absolute alphabet soup of different packet formats.&lt;/p&gt;
&lt;p&gt;So in the packet crate itself, which is just this framework, we have a set of helpers for parsing repeated records. It turns out that in the networking world, there are many different formats for repeated records. TLV—type-length-value—is just one of the instances of that. So TLV-style parsing tends to show up in IPv4. It shows up in TCP. Both of those have like optional variable-length options fields. IPv6 uses this like crazy thing called extension headers, which can be nested. So you can have multiple different extension headers that follow after the main IPv6 header. And then inside each extension header, you can have variable-length options. It&#39;s crazy. The amount of code that we had to write to parse IPv6 packet headers is insane. It&#39;s like thousands of lines of code because of how complex the format is.&lt;/p&gt;
&lt;p&gt;So zerocopy can only help so much with these things. As I said, it&#39;ll help you do like a single struct, a single union, something like that. But you can&#39;t just magically generate code that does all of that—the entirety of IPv4 options or IPv6 extension headers. We would love to move in that direction at some point, but it&#39;s an open research problem of how you actually represent that.&lt;/p&gt;
&lt;p&gt;What we do in the packet crate is we have utilities that will at least help you structure your code when you are parsing iterated records. So generally speaking, what this looks like is you give us a slice of bytes, a slice of &lt;code&gt;u8&lt;/code&gt;, and then you also have to give us some amount of code that tells us how to parse an individual record. And then out of that, we will give you back an iterator over all of the records. So for really bespoke things like IPv6 extension headers, it&#39;s fairly low level. We&#39;ll just say, like, listen, if you can parse an individual IPv6 extension header, then we&#39;ll let you parse multiple of them one after another. We&#39;ll sort of like... structure—we&#39;ll scaffold all of the code around that. For some more common types like TLV, we actually have a native TLV parser in the packet crate, but that is not in zerocopy.&lt;/p&gt;
&lt;p&gt;For those of you who are interested in using these things, zerocopy is on crates.io. You can use it right now. &lt;code&gt;net-types&lt;/code&gt;, &lt;code&gt;packet&lt;/code&gt;, and &lt;code&gt;packet-formats&lt;/code&gt; are not published on crates.io. It would be super cool to do that at some point, but we&#39;re not sure when we will or what it would entail to do that. You are more than welcome to just copy-paste the code out of the Fuchsia repository. It&#39;s all there. It&#39;s open source.&lt;/p&gt;
&lt;p&gt;You can read the license and determine whether the license is acceptable for you. But it&#39;s not like on crates.io. So it&#39;s not super nice and easy to use. But yeah, so all of the record stuff that I was talking about is in packet. So it&#39;s in the Fuchsia code base. You can go copy-paste it, but there&#39;s no crates.io package you can just take a dependency on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, cool, no, I&#39;m definitely going to at least study it. It&#39;s always interesting to read other people&#39;s code. It&#39;s one of my things I like to do next to reading RFCs. I used to read the newspaper more, but nowadays I&#39;m reading mostly RFCs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RFCs are a lot less depressing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, yeah, you learn a lot from it and nice to read. Anyway, so that&#39;s one thing. Okay, cool.&lt;/p&gt;
&lt;p&gt;So sadly not in zerocopy, but at least you solve it in a different way.&lt;/p&gt;
&lt;p&gt;And it&#39;s an open research problem, so the future is bright, who knows. Okay, another issue I have, or not really issue, like problem space I maybe create for myself is this, which deals with the function coloring problem. And, for example, the Rama framework is heavily async. And sometimes it&#39;s not clear, okay, when you want to make things async and when not. And so for clarity, a lot of stuff we do is async just because, depending on how you implement a trait, you might anyway want to have some kind of async behavior because I don&#39;t know, maybe you need to validate something, but you need to check something in I/O or some kind of database or whatever. Having it async first helps a lot there, but it does mean that you cannot really as easily make use of something like zerocopy.&lt;/p&gt;
&lt;p&gt;I would think, because like I couldn&#39;t just hold a reference to a slice and then move it over like you&#39;re requiring &lt;code&gt;Send&lt;/code&gt; + &lt;code&gt;Sync&lt;/code&gt; trait bounds or whatever; I couldn&#39;t just move it over because it wouldn&#39;t work. I mean, but I think within Netstack3, I don&#39;t think you have those issues. Yeah, actually, do you have those issues there? I suppose maybe you&#39;re Arc-ing the bytes there or something, and that&#39;s how you get away with it. I don&#39;t know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so I&#39;ll say a few things. First of all, I&#39;m not intimately familiar with these issues. I have not done much async programming myself. So I may be speaking out of turn. My general feeling about powerful frameworks for systems code is I try to avoid them as much as I can unless I really need them. My view on async is that the Rust async solution—the whole async system—is an engineering marvel that you should try to avoid if you can.&lt;/p&gt;
&lt;p&gt;I work with Tyler Mandry, who is one of the core designers of the async system. He has done amazing work. The Rust folks have done amazing work on designing async. It is a beauty. But it&#39;s really complicated. It is necessarily solving an extremely complicated problem. And it makes it difficult for you to reason about the behavior of your code. And so you should use it if you need it, right? If you&#39;re writing some highly parallel web server and it makes natural sense to use async, like go ahead and use it obviously.&lt;/p&gt;
&lt;p&gt;We tried to avoid it in Netstack3 as much as possible because of how tight a control we need over the execution model of the code, right? I need to know not just: when the code runs, what does it do? I also need to know: when does the code run? And what does the control flow look like? And async makes it difficult to reason about what the control flow is going to be.&lt;/p&gt;
&lt;p&gt;So Bruno talked about this in the previous episode, which listeners should definitely go listen to. It&#39;ll provide a lot of extra context for what we&#39;re talking about here. But I&#39;ll repeat briefly what he said, which is that 90-ish percent of the code in Netstack3, by lines of code, is in a crate called the core—or a part of the code base called the core. It was a single crate at some point. Maybe they split it up since then.&lt;/p&gt;
&lt;p&gt;But the idea is that philosophically, there&#39;s this region of the code base that is completely platform agnostic. So if you go and you read that source code, you won&#39;t see anything specific to Fuchsia. And in that code, that&#39;s where all of the actual protocol implementations live. That&#39;s TCP, IPv4, IPv6, yada yada yada yada. The whole protocol soup lives in there. Inside of that part of the code base, there is no async. It&#39;s all just straight-line functions.&lt;/p&gt;
&lt;p&gt;So you call in and the code executes to completion and then it returns. In the course of executing, it might call back out into the external system. We basically have a dependency injection mechanism so that code that lives outside, in what we call the bindings—which is the thing that binds the core to the specific system—can interact with the core. So the bindings are where the Fuchsia-specific code lives. We have a mechanism for the bindings to call into the core and then a dependency injection mechanism that allows the core to call back out into the bindings.&lt;/p&gt;
&lt;p&gt;This is what lets you do something like send a UDP packet. You can call from the bindings into the core and say, &quot;I would like to send this packet.&quot; And then once the core bottoms out at like ethernet and needs to send a message to, you know, an Ethernet driver, it then calls back into the bindings and says, &quot;Hey, I need to talk to the driver. Here&#39;s the Ethernet frame that I want to send.&quot; So we can call into the core and the core can call back out into the bindings.&lt;/p&gt;
&lt;p&gt;But that whole system is entirely synchronous. There&#39;s no async involved. It&#39;s just straight-line code. In that UDP example, the bindings would call into the core and it would just go straight through all the way through. At some point, the core would call back out into the bindings and say, hey, I want to send this ethernet frame to the driver. That call would happen, right? Either inline, the bindings would actually do the communication with the driver, or maybe it would just queue that work for later.&lt;/p&gt;
&lt;p&gt;And then it would return and the function call would return all the way through the core and back out into the bindings where it was originally initiated. The bindings do have async. For various reasons, it&#39;s important to have async there because there&#39;s a lot more asynchronous stuff going on. The communication mechanism that Fuchsia uses to communicate between processes is very naturally asynchronous. And so it makes a lot more sense for there to be async code there.&lt;/p&gt;
&lt;p&gt;So there&#39;s async code initiating synchronous calls into the core; that&#39;s basically the way to think about it. But inside of the core, there is no async. And again, just to reiterate, the reason is that we wanted to be able to have a very clear mental model of how control is flowing through the core so that we can reason about performance and like resource liveness, right? When are certain resources live or dead? What is the possibility of, you know, deadlocks and stuff like that? And generally speaking, I have found that it is a useful, you know, sort of rule of thumb to avoid async until you actually need it.&lt;/p&gt;
&lt;p&gt;Once you need it, Rust async is super cool. And I don&#39;t want this to come off as like me denigrating the folks who did async. Async is absolute magic. It&#39;s so, so, so cool, but it is a very sharp tool and you should only use it once you know that you actually need it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay, that&#39;s fair enough. But then I do wonder, as you said, the driver or whatever, like the bindings call the core and the core can call back into the bindings. Like how do they then make sure that, for example, that stuff doesn&#39;t block everything else? Because then, I think—is it because they give it an entire thread to do what it wants, or how does that work?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay, so the most accurate answer is: I don&#39;t know. Most of this stuff was written after I left. My rough understanding from having talked to Bruno since he took over the project is that basically they have a queuing mechanism where they will queue packets or frames to be sent to the driver at some point in the future. Now, naturally a thing you might imagine, and I don&#39;t know whether they do this, this is me just speculating.&lt;/p&gt;
&lt;p&gt;But naturally, a thing you can imagine is you could do a fast path. You can say, if there is room in the buffer that I share with the driver at the point at which the core calls into the bindings and says, please send this frame, maybe they opportunistically, as a fast path, go ahead and write into the buffer. I don&#39;t actually know whether they do that. You can imagine them doing that. Certainly, they&#39;re not going to block. You&#39;re definitely not going to block on that operation. You&#39;re going to queue it for later and then immediately return up through the core.&lt;/p&gt;
&lt;p&gt;Just to give a sense of numbers here, Netstack3 aims to be a general-purpose networking stack. You want it to be able to use on any system. And Fuchsia is a general-purpose operating system. You want to be able to use it on any system. And so you want to be able to have this stuff be as performant as possible so that someone in the future, let&#39;s say there&#39;s some like—I don&#39;t know, this is complete speculation. I&#39;m making this up. This is not like real, you know, this is not a real-world example. But like, let&#39;s say that a decade from now, someone says, &quot;You know what? I want to build a router. I want to use Fuchsia to build it.&quot; Well, if you&#39;re going to do that, if you&#39;re going to use Fuchsia to build a router, then you would need to be able to turn around a packet in, I think the numbers are something like a microsecond, right? Like a modern, you know, take your random, you know, Netgear router that you have in your home networking setup or whatever. You have about a microsecond, right? A millionth of a second to receive a packet, parse it, decide what you&#39;re gonna do with it, decide where you&#39;re gonna forward it, turn around, serialize the new version of that packet, forward it out.&lt;/p&gt;
&lt;p&gt;You have about a millionth of a second budget to do that entire thing, right? That entire operation. So the point is that if Netstack3 has the goal of just being like a general-purpose networking stack that people can use for general-purpose networking stuff, then you need to be able to like hit those performance goals, right? And so if you have a millionth of a second to turn around a packet in the most extreme case, then you definitely cannot be blocking in the core.&lt;/p&gt;
&lt;p&gt;And so the idea is that, yeah, you want all of the extra scaffolding around that sort of stuff to happen in the bindings, where you can have more opinions about what sorts of performance trade-offs are acceptable, but you definitely do not want to be blocking the core. And you might say, &quot;Well, maybe if this thing blocks in the core, then that&#39;s fine.&quot; Like it blocks trying to send to the driver, but that&#39;s fine because a different thread could come in and do work at the same time. True, but what if the core has like, you know, locked a mutex in the interim, right?&lt;/p&gt;
&lt;p&gt;And so in fact, you&#39;re blocking like other resources at the same time. So generally speaking, the core tries to be as much of a “get in, do your work, and get out” system as possible. This, by the way, for those of you who are interested in like networking optimization stuff, is generally speaking the direction that high-performance networking has gone over the past decade. If you read design docs from the Linux kernel, for example, there&#39;s a really great text file. There&#39;s a &lt;a rel=&quot;external&quot; href=&quot;https://www.kernel.org/doc/Documentation/networking/scaling.txt&quot;&gt;really great design doc&lt;/a&gt; that someone wrote that just describes all of the high performance stuff that the Linux net stack does.&lt;/p&gt;
&lt;p&gt;And a lot of it basically entails, how can we be as dumb as possible? That&#39;s basically the idea, right? Like stop trying to synchronize between different cores and different threads. Stop trying to be fancy about stuff. Just do the dumbest possible thing—no work at all. Get in, do your work, get out as quickly as possible. There are various things that this looks like where you can like pin different sockets to different cores and you can like do, you know, hash-based bucketing so you know a priori which core you&#39;re going to send the packet to.&lt;/p&gt;
&lt;p&gt;There&#39;s all sorts of fancy stuff. But all of it boils down to get in, do your work, get out as quickly as possible. And so for that reason, async is a bit antithetical to that because it just robs you of the ability to make your own decisions about what that execution flow is going to look like. Again, this is a very niche case. The netstack use case is very niche, especially from a performance standpoint. So there are lots of other cases where async is a very appropriate tool for the job. As I said before, if you&#39;re doing a web server and you&#39;re just going to have a bunch of people coming in and your web requests are very I/O-bound, someone makes a request and then you need to issue a read to the database and that&#39;s going to block for a while and yada, yada, yada, async is the obvious choice there.&lt;/p&gt;
&lt;p&gt;But if you&#39;re doing low-level system stuff, it is probably a good idea to think very deeply about the control flow inside of your application, in which case async is something you should think carefully about. I&#39;m not saying don&#39;t use it, but just make sure you understand how it&#39;s going to affect your control flow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, for sure. I mean, first of all, it&#39;s very exciting to talk about this. Like it always makes me feel very warm. But yeah, it&#39;s a...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, Rust is a good... Rust is a warm and fuzzy language. That&#39;s why I like it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, but even the networking world, I mean, it&#39;s kind of like for me until like eight years ago or seven years ago, networking was always an abstract concept. Like I was using it when I had to and I knew how to open sockets and I knew how to manipulate them. I knew how to write to them. I knew a lot about like all even writing our own protocols for the games because that&#39;s what they did. I don&#39;t know why, but everybody was inventing their protocols.&lt;/p&gt;
&lt;p&gt;So I have a lot of experience with that, but it&#39;s only once I really got into, I don&#39;t know, security and data extraction and the web world and all those kinds of stuff and then proxies and yeah, again, security in another kind of capacity that I really got into the networking world. Yeah, but still, talking to someone with your experience working in those kinds of systems, I feel like there&#39;s still a whole world to explore where I definitely haven&#39;t scratched the surface yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It never ends. I mean, despite the fact that, you know, I was able to spend nearly half a decade working on this stuff. In my time there, I never got to touch a lot of the higher performance stuff. I never actually—you know, the current synchronization model is basically just mutex-based for Netstack3. I was always really excited about some hypothetical future in which we could go like super hardcore and do the core pinning stuff and like, map sockets to different threads and whatever.&lt;/p&gt;
&lt;p&gt;We actually wrote up a design doc for that once and basically just, there were so many correctness edge cases that it just, we ended up deciding that it was too complicated to justify it in the short term. But man, you can go so deep. At least while I was there, we never did any of the hardware offload stuff, having the hardware do the checksumming for you or like coalesce TCP segments for you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mm-hmm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I mean, man, yeah, it&#39;s easy to understand how you could make an entire career in this industry and never actually, never get to the bottom. It&#39;s very cool.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I mean, yeah, I mean, that&#39;s what I live for. I love to learn. I soak it like a sponge. Now, we already mentioned it a bit before and it&#39;s also written in your README, which by the way, I mean, in one respect, I love the README of zerocopy. Like it&#39;s very beautiful. At the same time—and maybe it&#39;s just me, but I feel as an outsider, if I hadn&#39;t read the actual code, I would still find it very difficult to know how to apply it because it doesn&#39;t really contain any examples—or examples I could easily find like for example one might expect, yeah, this is like a struct and that&#39;s coming from this kind of slice and that&#39;s how it&#39;s... And then you see all these concepts coming together.&lt;/p&gt;
&lt;p&gt;Well, now I feel it&#39;s like a laundry list of concepts, and then it&#39;s a lot of work on the reader I find to then put it together. Maybe that&#39;s part of it because you need to read and understand that. By doing that work, kind of like it&#39;s maybe it&#39;s like a mathematical proof where you have to go through the proof yourself and only then you understand it. You couldn&#39;t just read it. Is it like that or is it just because no time?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You were being very kind. No, I mean, the answer there is twofold, right? I mean, a large part of it is just like, zerocopy is two engineers and we don&#39;t have time is the real answer. I would love to invest more time in documentation. And certainly, hey, let this be a call. Those of you who are still with us an hour and a half into this podcast or however much this gets edited down to, I&#39;m seeing an hour and a half on my screen here. Those of you who are with us this far in the podcast, we would love open-source contributions.&lt;/p&gt;
&lt;p&gt;At zerocopy, we love, love, love it when people come and contribute. We&#39;re always looking for open-source contributors, always looking for people to use it in new contexts and give us feedback, all that jazz. Yeah, the documentation thing is largely just a lack of time. There is somewhat of a challenge here. It&#39;s not entirely just a lack of time. There&#39;s a little bit of this, which is just that it is a new way of thinking about how to do systems programming that a lot of people aren&#39;t really used to.&lt;/p&gt;
&lt;p&gt;And so we oftentimes find that people come in and they are... It&#39;s not just, &quot;Do I do X?&quot; But fundamentally, I don&#39;t even understand what it would mean to solve my problem. And so zerocopy really does have this sort of like... &quot;We will give you the tools,&quot; but we can&#39;t just document what tools we&#39;re giving you, because oftentimes people don&#39;t know what tools they need. Zerocopy really is a very powerful Swiss Army knife. It&#39;s very powerful.&lt;/p&gt;
&lt;p&gt;It&#39;ll let you do really cool stuff. But it&#39;s not a high-level framework. It&#39;s not a high-level network packet parsing framework or something like that. We have aspirations to build such a thing on top of zerocopy at some point in the future. But right now, our time has been entirely taken up just building the Swiss Army knife, basically—not even using it to build higher-level stuff.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, I mean, definitely reach out to me if you get to that. Maybe it could be like a partnership, I wouldn&#39;t mind.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, I mean, yeah, certainly if there are people out there who are interested in helping to build a high-level framework, that is certainly something we are interested in. As I said, we are I/O-bound, so to speak. We are not limited by a lack of ideas. We are limited by a lack of time. So yeah, If anyone&#39;s interested—if you have some crazy idea for a feature you could add or high-level framework we could build, please, please, please, please come talk to us. I would love to talk to you.&lt;/p&gt;
&lt;p&gt;There&#39;s a Discord link on our &lt;code&gt;docs.rs&lt;/code&gt; homepage, so that&#39;s a good way of getting in touch. Yeah, generally speaking, I think people are just not quite familiar with what tool they want to be reaching for. And so one of the big challenges is deciding how much we document what it is that we provide and how much do we try to be prescriptive about if this is your problem, here&#39;s what you should reach for. If this is your problem, here&#39;s what you should reach for for different problems. And part of that is it&#39;s actually kind of difficult to enumerate the entire space of possible things that people could use zerocopy for because it&#39;s extremely diverse. At a high level, it&#39;s basically just anytime you care about like the exact shape of what&#39;s happening in your memory, zerocopy might help you.&lt;/p&gt;
&lt;p&gt;And so that&#39;s a pretty wide, you know, that&#39;s a pretty wide problem definition. I remember once I was giving a talk internally about zerocopy and someone came up to me and said, &quot;Hey, I want to add an example to your list of example use cases.&quot; This person was doing video game hacking. So they basically had a video game and they wanted to hack it in order to get extra statistics about their own gameplay. And so they were reaching into the memory of this video game and pulling stuff out. And they were using zerocopy to make sure that they were parsing the memory of the video game correctly. It&#39;s not something that had ever occurred to me that was a possible use case, but it sort of makes sense.&lt;/p&gt;
&lt;p&gt;So that&#39;s a big problem for us: it&#39;s not super feasible for us to just list all the possible use cases, because it would sort of be like saying, you know, &quot;What are all the use cases for a for loop?&quot; It&#39;s like, &quot;I don&#39;t know, man. It&#39;s a for loop; you use it for a bunch of stuff.&quot; So that&#39;s sort of the challenge, but also, as I said at the beginning, that&#39;s not an excuse. We should have more documentation, but it&#39;s, you know, there&#39;s never enough.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah. And then there is like Project Safe Transmute. And you say it&#39;s kind of like about moving zerocopy into the Rust compiler. Would it ever be the goal for this not to be distributed as a crate—zerocopy—and instead just be in the compiler?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so... Yeah, so I suspect that we are... Well, let me give some background. The short answer to your question is there&#39;s probably not a future in which zerocopy and crates like it—&lt;code&gt;bytemuck&lt;/code&gt; is another big one here—go away entirely, but there is hopefully a future in which they get much smaller.&lt;/p&gt;
&lt;p&gt;So basically zerocopy and crates like it, for the most part, solve the problem of having a pile of bytes and wanting to convert it into a particular type, or having a particular type and wanting to look at its bytes. So it&#39;s a bidirectional transformation between bytes and some other type.&lt;/p&gt;
&lt;p&gt;It turns out that you might want to do more powerful things than that. So you might actually want to go from a particular type, like some particular type &lt;code&gt;T&lt;/code&gt;, and convert it into some other type &lt;code&gt;U&lt;/code&gt;. And that is something that zerocopy is not good at reasoning about, because it&#39;s no longer a piecewise operation. So zerocopy today will let you go from &lt;code&gt;T&lt;/code&gt; to &lt;code&gt;U&lt;/code&gt;, but only if you can intermediate by going to a pile of bytes.&lt;/p&gt;
&lt;p&gt;So if you can go from &lt;code&gt;T&lt;/code&gt; to a pile of bytes, and then from a pile of bytes to &lt;code&gt;U&lt;/code&gt;, then zerocopy will let you compose those two operations and just do them together as just &lt;code&gt;T&lt;/code&gt; to &lt;code&gt;U&lt;/code&gt;. But there are a lot of pairs of types where that&#39;s not valid. So for example, if you have like an enum that has three variants, and you want to go from bool to that enum, that should be allowed, right? A bool can be either 0 or 1, and then maybe I have some enum that is also one byte long that can be 0 or 1 or 2. In principle, I should be able to go from a bool to this enum type. The problem is, zerocopy, the only way that it knows how to reason about that operation is to go from bool to a pile of bytes.&lt;/p&gt;
&lt;p&gt;Once you have a pile of bytes, now you just have a &lt;code&gt;u8&lt;/code&gt;. And from zerocopy&#39;s perspective, if you try to go from a &lt;code&gt;u8&lt;/code&gt; to this enum, you&#39;re basically telling it, hey, can I take any &lt;code&gt;u8&lt;/code&gt; at all and convert it into this enum? And the answer is no. What if it&#39;s the value four or five or 27 or 38 or whatever? So, just saying I can go from &lt;code&gt;T&lt;/code&gt; to a pile of bytes and a pile of bytes to &lt;code&gt;U&lt;/code&gt; limits the number of types that you can actually support, the number of conversions that you can support.&lt;/p&gt;
&lt;p&gt;So that&#39;s the reason that zerocopy and crates like it are limited. So the Safe Transmute project is a project that attempts to support that more powerful class of transmutations in the compiler itself. Basically the way that we do this is we have a representation inside of the compiler of the layout of a type. So there&#39;s a way that the compiler can reason about what is the set of every possible bit pattern that I might actually see for this particular type. And then it has a way of asking basically a subset question, it&#39;s doing a subset query. If I have a &lt;code&gt;T&lt;/code&gt; and I&#39;m trying to transmute it into a &lt;code&gt;U&lt;/code&gt;, is the set of possible bit patterns in the &lt;code&gt;T&lt;/code&gt; a subset of the set of possible bit patterns in &lt;code&gt;U&lt;/code&gt;, right? Is it guaranteed that no matter what &lt;code&gt;T&lt;/code&gt; I have, it&#39;s going to also be a valid instance of &lt;code&gt;U&lt;/code&gt; if I just convert the bytes from a &lt;code&gt;T&lt;/code&gt; to a &lt;code&gt;U&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;We&#39;re building a way in the compiler to do that transformation, right? To ask queries of that form. It turns out that is actually like a very interesting CS theory problem. We&#39;ve had to develop some novel algorithms and there&#39;s been some really interesting engineering there. So it&#39;s a long-term effort. But the goal is that eventually the compiler will be able to answer questions of this form for you. Once it has done that, then you can rip out all of the analysis part of zerocopy, right?&lt;/p&gt;
&lt;p&gt;So the custom derives can basically just go away and be replaced by this built-in compiler analysis. Now the high-level stuff in zerocopy still stays there, right? So basically what the compiler does is give you this trait implementation that you could use to say, &quot;is this a valid transmutation?&quot; But then you actually still have to write the code that does the transmutation. So all of the stuff in zerocopy that says, if this is a valid transmutation, then here&#39;s a bunch of extra stuff you can build on top. That stuff is gonna stick around probably, right? That stuff could in principle be moved into the compiler or at least into the standard library, but there&#39;s a large set of features there and we&#39;re probably not gonna move all of it. Certainly not anytime soon.&lt;/p&gt;
&lt;p&gt;So more likely the short-term world is going to be, we add this analysis to the compiler and then we remove or strip down zerocopy-derive, but the zerocopy crate itself stays largely the same and maybe gets to grow new fancy features that are built on top of this.&lt;/p&gt;
&lt;p&gt;But that&#39;s sort of the future that we expect.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay, yeah, that makes sense and still very exciting. So is this like for now a very theoretical working group or is this something like, no, this is getting very concrete and soon we will land these kind of things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, so it&#39;s concrete in the sense that we have an existing experimental implementation. So you can go to nightly Rust today and find, in the &lt;code&gt;mem&lt;/code&gt; module, a trait called, I think it&#39;s currently called &lt;code&gt;TransmuteFrom&lt;/code&gt;. We have renamed it at various points. I can go there right now while we&#39;re talking and answer that question. But basically there&#39;s an existing nightly feature that provides this query. So it&#39;s in the compiler, but the short answer is that it&#39;s unstable. There&#39;s a good amount of...&lt;/p&gt;
&lt;p&gt;Okay, here we go. I looked it up, yes, its current name is &lt;code&gt;mem::TransmuteFrom&lt;/code&gt;. So it&#39;s unstable, but there is a fairly full-featured implementation in the compiler. But there are a lot of edge cases. So currently we don&#39;t handle like non-zero types, for example. That should be a relatively easy fix. Again, anyone who is interested in open-source contributions, we&#39;d love to have you. There&#39;s a lot of like pretty easy low-hanging fruit for people who are already familiar with contributing to the compiler to add extra features.&lt;/p&gt;
&lt;p&gt;Then there are optimizations that we would like to do. So currently, if you represent an array spanning a gigabyte of memory or something like that, you would hope that the representation would basically just be like, you know, the representation of a &lt;code&gt;u8&lt;/code&gt; followed by a number that says there are a billion of these.&lt;/p&gt;
&lt;p&gt;That is not what we do. Currently, if you give us an array of a billion &lt;code&gt;u8&lt;/code&gt;s, we are going to instantiate in the compiler a billion representations of &lt;code&gt;u8&lt;/code&gt;, which is very stupid. So there&#39;s like low-hanging optimization fruit like that that we just need to like, you know, do the obvious optimizations. Eventually, the goal, of course, is to actually put this forward and try to stabilize it and all that jazz. We&#39;re not quite there yet, but we&#39;re hoping to get there. It is something you can experiment with today. If you are using Nightly Rust, you can try to play around with this with your types.&lt;/p&gt;
&lt;p&gt;As I said, you may run into edge cases and stuff, but that&#39;s exactly what we want to see. We&#39;d love people to experiment with it and give us bug reports. So yeah, the long-term goal is to put this forward formally for stabilization. But there&#39;s a good amount of engineering work between here and stabilization—&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay, very cool. And then I feel we covered a lot of ground. I also feel we could talk a lot more, but I do think we should wrap up soon. Is there something that we didn&#39;t discuss yet or maybe we touched on it, but you think you might want to go a bit deeper into it before we leave?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure. Yeah, so I think, like, I would say that I had a few notes written down of just like stuff I wanted to touch on at some point. These are gonna be somewhat disconnected from one another, but it&#39;s just sort of the grab bag at the end. One thing is if you are interested in systems programming and you want to go deeper on stuff, I happen to think that writing a network stack is one of the most interesting and challenging systems-programming hobby projects that you can do. You would be surprised by how tractable and approachable it is to implement IPv4 and TCP for yourself. Buy a networking textbook that has an explanation of those things. Read the RFCs.&lt;/p&gt;
&lt;p&gt;They are not the world&#39;s most readable documents, but they&#39;re not extremely arcane. Try to implement it for yourself. It is... It&#39;s a wonderful challenge in how to build large-scale software. I think one of the most educational experiences I had during college was being tasked with implementing this, even in an academic context. So if you&#39;re interested in systems projects, I highly, highly recommend it. It&#39;s a lot of fun.&lt;/p&gt;
&lt;p&gt;The other thing I get asked a lot is whether there is a sort of high-level philosophy or attitude behind the work that I&#39;ve done, like in Netstack3 and zerocopy and Safe Transmute and stuff like that. Like, how can I take a similar sort of engineering approach to my own work? The answer that I usually give—and this is definitely something that I recommend to a lot of people—is that Rust in particular, but this is applicable in theory to lots of other languages, gives you the ability to be extremely ambitious about how nice your software is.&lt;/p&gt;
&lt;p&gt;And so what I would say is whatever you&#39;re doing—whether abstraction design or writing a library—let yourself be motivated by the functions and the features you need to provide, obviously, but also let yourself dream big about how nice it could be to use your API, right? Let yourself sort of engage in daydreaming about, man, wouldn&#39;t it be nice if I had a system that let me do this? If it were just this easy, right? If it just worked out of the box or it were just this straightforward to do this particular operation. Let yourself have that dream. And then the challenge to you as an abstraction designer is to connect the two things, right? To say, is there some way for me to provide the functionality that I need to provide, but in an API that is actually this nice?&lt;/p&gt;
&lt;p&gt;Rob Pike has talked a lot about this in talks he&#39;s given at various conferences. One of my favorite talks that he&#39;s given is called “Simplicity Is Complicated.” He has one of my favorite quotes: “Simplicity is the art of hiding complexity.” Basically the idea is your job as an abstraction designer is to understand the thing that you are implementing so well that it&#39;s possible for you to provide a simple API. The simpler the API, the more deeply you have to understand the problem in order to be able to produce that API.&lt;/p&gt;
&lt;p&gt;And so that&#39;s really my advice: let yourself be ambitious about how simple your APIs can be and about how easy and pleasant to use they can be and understand that in order to satisfy that ambition, you are going to have to just sit there and think deep thoughts about the problem for a long time and like mull it over in your head and really, really get to the point of deeply understanding how you could possibly shape an API that is as nice as you want it to be, basically. So that&#39;s sort of the— like, you know, I encourage people to be as ambitious as possible on that front. And if you get there, then that&#39;s how you end up with something like zerocopy that you&#39;re sort of scratching your own itch.&lt;/p&gt;
&lt;p&gt;But then eventually you end up solving a problem that other people also have and, to use a somewhat overused phrase from the product design world, you delight your users or whatever, right? I think that... That phrase gets a lot of poo-pooing from more hardcore systems-engineer types. But I do think there&#39;s something there. The idea that you use a product that you really like and you just have this sort of emotional feeling of relief, right? You&#39;re just like, it&#39;s so nice. I don&#39;t have to think about this anymore.&lt;/p&gt;
&lt;p&gt;That&#39;s the feeling you want your users to have. You want them to just sort of have that like, this is the thing I&#39;ve been wanting to use my whole life, but now it&#39;s here and now I can just relax. Let yourself be ambitious about that. I think that&#39;s... That&#39;s all I got.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, only that. It&#39;s wonderful advice. Yeah, and I feel especially in a language like Rust, this is definitely a place where you can be ambitious because for example, if we think about the framework Rama, which I was mostly writing alone but now has more and more contributors, I would never have built that if not for Rust, especially not on my own because...&lt;/p&gt;
&lt;p&gt;So one thing I often say to people is like, Rust, they often focus on like performance, et cetera. But what I really like about Rust, thanks to the type system and many other things, is how I can refactor things and change things. And I&#39;m not scared to change it because it will, like, it will really just work out. I&#39;ve done several large refactors and it just worked out like no scary surprises. If I think back to my long history in C++. Despite liking the language and liking to work in it, I would never have pulled that off.&lt;/p&gt;
&lt;p&gt;Like I would have introduced so many bugs, so many segfaults, so many kinds of problems. Like it just wouldn&#39;t have worked. And so yeah, I like your advice a lot because it&#39;s something you can actually do in a language like Rust, for sure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, no, exactly. I mean, this is something that I have seen. It&#39;s a very powerful philosophy because I say that specifically in the sense that I have seen other people take that philosophy and run with it. So we had this guy, Alex, who worked on Netstack3 for a while, and he did one of the coolest projects I&#39;ve ever seen where he basically figured out a way to encode lock ordering in the type system. So basically the idea is like you have a bunch of mutexes and what is the order in which you acquire those mutexes, right? He figured out a way to put that in the type system and prevent the Netstack3 code from ever deadlocking.&lt;/p&gt;
&lt;p&gt;Basically, if you attempt to acquire locks in an order that could result in a deadlock, it will cause a compilation failure. So cool. That was just an example of basically someone on the team who had seen this philosophy of trying to be really aggressive about how nice your APIs can be. And he was like, yeah, I bet we can do this. And again, it was that same, what&#39;s the goal? The goal is I want this to be a magical experience. I want to be delighted by how easy it is to use.&lt;/p&gt;
&lt;p&gt;And he just sat there and he banged his head against it for a while. And then he came up with this really clever trick that now means that Netstack3 is never going to have a deadlock. And if you want, by the way, for the sort of like more business-minded people in the room or in the audience, if you are interested yourself or you&#39;re interested in arguing to leadership at your company that this is something that&#39;s worth doing, Netstack3 has this crazy statistic that I think really encapsulates just how this is not just a thing engineers do because we like correctness for its own sake and it makes us happy or whatever. It&#39;s not just like a nerd snipe thing. It actually really translates into business value.&lt;/p&gt;
&lt;p&gt;In the first year and a half of Netstack3 being dogfooded—that is, used internally by the team as a real networking stack by people on real devices, sitting in their homes and using it to do development. Normally, the goal of rolling out something for dogfooding is that you expect to find a bunch of bugs that you had not found during testing. You&#39;d expect that to be in the order of hundreds or something. Over the course of a year and a half, you&#39;re going to see this long stream of bugs, you&#39;re going to burn them down, yada yada yada. In the year and a half that Netstack3 was in dogfooding, and again, this is after I left, I&#39;ll sort of refer to them in the third person here—the team encountered four bugs in the field. Four. Which is just a stupidly low number, an absurdly low number.&lt;/p&gt;
&lt;p&gt;And if you think about the cost from a business standpoint, especially for a networking stack, right, I mean, you know, if you have a device in the field, and its networking stack has a catastrophic bug, that device is effectively bricked because it can&#39;t connect to the internet to take a software update. That&#39;s how important a net stack is. So getting it right the first time is crucial. And you think about the amount of developer time that is saved by not having to do debugging, you think about the normal lifecycle of a product. If you are a software engineer, especially if you&#39;ve worked on a C or C++ code base, how much of your time do you spend fixing old bugs as opposed to writing new code? Imagine what it would be like if most of your time was just spent writing new code.&lt;/p&gt;
&lt;p&gt;That&#39;s the value proposition from a business standpoint of moving slowly and carefully in a language like Rust, you know, to use the phrase that the Marines have, slow is smooth and smooth is fast, right? If you measure on the order of lines of code written, maybe you&#39;re moving more slowly, but that&#39;s not actually the right measurement, right? The right measurement is like features shipped stably to production. And my thesis, which is not based on actual numbers because people haven&#39;t studied this yet, but my experience intuitively is that if you measure over a longer time horizon, Rust is not just a safer, more precise, more careful language, it&#39;s also a much faster language because you don&#39;t waste time in development fixing problems that you introduced earlier in development.&lt;/p&gt;
&lt;p&gt;So if you&#39;re trying to sell this to leadership at your company, give them that quote, four bugs in a year and a half of dogfooding, with a small team that had not been working on it that long. Rust is a really special thing and it translates into dollars and cents. It&#39;s not just nerd sniping for nerd sniping&#39;s sake.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Glen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, I couldn&#39;t agree more and I will definitely use that quote. Thanks for that. So, with that being said, I want to thank you very much for your time and I wish you a very good life ahead of you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Josh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, of course. Thanks, Glen. This has been an absolute pleasure. Anyone else who&#39;s thinking of doing this, take Glen up on his invitation. It&#39;s been a great time. Appreciate it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elizabeth&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Netstack.fm is brought to you by Plabayo, building secure, open, and resilient infrastructure with Rust, protocols, and purpose. This show is also made possible by Rama, the open source networking framework. Plabayo offers service contracts and welcomes sponsorships to keep building and supporting its ecosystem. The theme music of this podcast was composed by DJ Mailbox. If you enjoyed this episode, don&#39;t forget to subscribe on your favorite podcast platform and leave a five-star review. It really helps others discover the show. Thanks for tuning in.&lt;/p&gt;
&lt;p&gt;We&#39;ll see you next time for the next handshake.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Safety in an `unsafe { world }`</title>
    <published>2026-07-27T00:00:00+00:00</published>
    
    <updated>2026-07-27T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/safety-unsafe-world/"/>
    <id>https://joshlf.com/posts/safety-unsafe-world/</id>
    
      
    <category term="Rust"/>
      
    <category term="Unsafe"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/safety-unsafe-world/">&lt;p&gt;&lt;em&gt;This post is a nearly verbatim adaptation of my RustConf 2024 talk. I&#39;ve kept everything in the present tense as it was in September 2024. Towards the end, I&#39;ve also included a bit of content that I had planned on presenting but had to skip during the presentation for time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.youtube.com/watch?v=qd3x5MCUrhw&quot;&gt;Watch the talk&lt;/a&gt; · &lt;a rel=&quot;external&quot; href=&quot;https://joshlf.com/files/talks/Safety%20in%20an%20Unsafe%20World.pdf&quot;&gt;See the slides&lt;/a&gt; · &lt;a rel=&quot;external&quot; href=&quot;https://gist.github.com/joshlf/65ccb20e034445a0fc6595f3a270653d&quot;&gt;See the full references&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;netstack3&quot;&gt;Netstack3&lt;/h2&gt;
&lt;p&gt;So what is this talk about? Well, I&#39;m going to bury the lede a bit.&lt;/p&gt;
&lt;p&gt;First, let&#39;s talk about Netstack3. Netstack3 is Fuchsia&#39;s next-generation, pure-Rust networking stack. It aims to replace Netstack2, which is written in Go.&lt;/p&gt;
&lt;p&gt;I started Netstack3 about six years ago, and led its development for four years, and then for the past two years it&#39;s been led by a different team. I haven&#39;t been on the project for two years, so obviously this is beyond me now – it&#39;s a huge team effort – I&#39;m going to be bragging a lot about those folks. There are some really good engineers who work on that now.&lt;/p&gt;
&lt;p&gt;Writing a networking stack is a serious undertaking. It&#39;s responsible for almost all network traffic in the entire operating system. It implements dozens of protocols, each of which is specified in documents that can run into the hundreds of pages. And it&#39;s the first line of defense against any attacker who isn&#39;t physically sitting in front of a device.&lt;/p&gt;
&lt;p&gt;It&#39;s also just &lt;em&gt;big&lt;/em&gt;. As I said a second ago, it&#39;s taken us six years to get to this point, there have been plus or minus ten developers that whole time, and it&#39;s split across 63 crates totaling 192,000 lines of code. That&#39;s more code than the top ten crates on crates.io combined.&lt;/p&gt;
&lt;p&gt;Over the past year, the team has been preparing to launch Netstack3. Those of you with networking backgrounds will know that you don&#39;t &lt;em&gt;just&lt;/em&gt; deploy networking code into production.&lt;/p&gt;
&lt;p&gt;Networking code is famously difficult to test, and so you have to assume that, despite your best efforts, your code is riddled with bugs.&lt;/p&gt;
&lt;p&gt;For a project of this scale — deploying an entirely new, ground-up rewrite of a netstack — you would expect to dogfood in the field for months or maybe even years before shipping to real users. In that time, you would expect to uncover tens to hundreds of bugs that you hadn&#39;t seen during development. And only once you had burned down most of those bugs and seen relatively stable behavior for a while, only then would you finally deploy to real users.&lt;/p&gt;
&lt;p&gt;So let&#39;s talk about what the process has looked like for Netstack3. For 11 months, the team has been ramping up a dogfooding program. At peak, that program has seen about 60 devices running nearly 24/7 in developers&#39; homes.&lt;/p&gt;
&lt;p&gt;Again, if this were any other netstack, we would have expected to uncover a giant mountain of bugs in that time. So, over the past year, how many bugs did the team uncover in the field?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note from the future&lt;/strong&gt;: As of posting, Netstack3 is now in production, running on millions of devices. Immediately after its first deployment, the team observed a ~20x lower rate of crashes per million devices per day and a 50% reduction in memory usage compared to its predecessor, Netstack2.&lt;/p&gt;
&lt;p&gt;The three dogfooding bugs (actually four – the last observed failure was due to two separate bugs) were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=419219829&quot;&gt;419219829&lt;/a&gt;, fixed in &lt;a rel=&quot;external&quot; href=&quot;https://fuchsia-review.googlesource.com/c/fuchsia/+/1282284&quot;&gt;1282284&lt;/a&gt;: An operator-precedence mistake defined &lt;code&gt;WindowSize::MAX&lt;/code&gt; as &lt;code&gt;1 &amp;lt;&amp;lt; (30 - 1)&lt;/code&gt; rather than &lt;code&gt;(1 &amp;lt;&amp;lt; 30) - 1&lt;/code&gt;. Netstack3 therefore imposed an artificially low TCP receive-window maximum and could panic on connections with windows above roughly 500 MB.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=420719068&quot;&gt;420719068&lt;/a&gt;, fixed in &lt;a rel=&quot;external&quot; href=&quot;https://fuchsia-review.googlesource.com/c/fuchsia/+/1286767&quot;&gt;1286767&lt;/a&gt;: The DHCP client treated &lt;code&gt;ENOBUFS&lt;/code&gt; as an impossible out-of-memory condition and panicked. On a packet socket, however, &lt;code&gt;ENOBUFS&lt;/code&gt; can legitimately occur when the network device’s transmit queue is full.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=422307328&quot;&gt;422307328&lt;/a&gt; was one observed failure caused by two bugs:
&lt;ul&gt;
&lt;li&gt;Fixed in &lt;a rel=&quot;external&quot; href=&quot;https://fuchsia-review.googlesource.com/c/fuchsia/+/1334968&quot;&gt;1334968&lt;/a&gt;: Netstack3 discarded IPv6 Neighbor Advertisements that omitted the Target Link-Layer Address option, even though RFC 4861 permits the omission in some unicast cases. This prevented otherwise valid reachability signals from updating the cached neighbor state.&lt;/li&gt;
&lt;li&gt;Fixed in &lt;a rel=&quot;external&quot; href=&quot;https://fuchsia-review.googlesource.com/c/fuchsia/+/1335018&quot;&gt;1335018&lt;/a&gt;: Netstack3 propagated a Path-MTU error to TCP only when the error changed the PMTU cache. Repeated Packet Too Big or Fragmentation Required errors were therefore suppressed after the first cache update, preventing TCP from updating its MSS correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;So this talk is going to be something of a flashback.&lt;/p&gt;
&lt;p&gt;Netstack3 was designed around a particular methodology for how to architect robust systems. Hopefully I&#39;ve convinced you that we did at least &lt;em&gt;something&lt;/em&gt; right on the robustness front.&lt;/p&gt;
&lt;p&gt;In a sentence, that methodology says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Buggy programs don&#39;t compile.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Obviously, I am far from the first person to suggest this methodology. Here is just a small sample of crates that use this methodology somewhere in their APIs:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ghost-cell&lt;/code&gt;, &lt;code&gt;session_types&lt;/code&gt;, &lt;code&gt;nalgebra&lt;/code&gt;, &lt;code&gt;mundane&lt;/code&gt;, &lt;code&gt;indexing&lt;/code&gt;, &lt;code&gt;zerocopy&lt;/code&gt;, and &lt;code&gt;bytemuck&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And here is a small sample of what has been written on the topic, both about Rust and about other languages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://without.boats/blog/references-are-like-jumps/&quot;&gt;References are like jumps&lt;/a&gt;, by withoutboats&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot;&gt;Parse, don&#39;t validate&lt;/a&gt;, by Alexis King&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.parsonsmatt.org/2017/10/11/type_safety_back_and_forth.html&quot;&gt;Type Safety Back and Forth&lt;/a&gt;, by Matt Parsons&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.iog.io/papers/ghosts-of-departed-proofs-functional-pearls&quot;&gt;Ghosts of Departed Proofs&lt;/a&gt;, by Matt Noonan&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cliffle.com/blog/rust-typestate/&quot;&gt;The Typestate Pattern in Rust&lt;/a&gt;, by Cliff Biffle&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.youtube.com/watch?v=Kdpfhj3VM04&quot;&gt;Compiler-Driven Development in Rust&lt;/a&gt;, by No Boilerplate&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://graydon2.dreamwidth.org/312681.html&quot;&gt;Some notes on Rust, mutable aliasing and formal verification&lt;/a&gt;, by Graydon Hoare&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So my goal for this talk is not to introduce a new idea.&lt;/p&gt;
&lt;p&gt;Instead, my goals are:&lt;/p&gt;
&lt;p&gt;First, I&#39;m going to propose a concrete but general framework that attempts to unify all of the different ways this methodology shows up in practice, and explain them in terms of the same basic concepts.&lt;/p&gt;
&lt;p&gt;Second, I&#39;m going to walk through two examples — one from the standard library and one from Netstack3 — and show how we can explain them in terms of this framework.&lt;/p&gt;
&lt;p&gt;Unfortunately 25 minutes isn&#39;t enough time to present more than two examples in the depth I&#39;d like. I had to leave a lot on the cutting-room floor when I was writing this talk. But I promise that these two examples only scratch the surface of what&#39;s possible. The &lt;a rel=&quot;external&quot; href=&quot;https://gist.github.com/joshlf/65ccb20e034445a0fc6595f3a270653d&quot;&gt;full list of references&lt;/a&gt; contains a surprising diversity of problems  which this methodology has already been applied to.&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-mean-by-buggy-programs-don-t-compile&quot;&gt;What do we mean by “buggy programs don&#39;t compile”?&lt;/h2&gt;
&lt;p&gt;On its website, Rust advertises three properties: performance, reliability, and productivity. Let&#39;s zoom in on reliability.&lt;/p&gt;
&lt;p&gt;The website says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rust&#39;s rich type system and ownership model guarantee memory-safety and thread-safety.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, out of the box, Rust guarantees that &quot;buggy programs don&#39;t compile,&quot; but only if we restrict our definition of &quot;bug&quot; to memory bugs or threading bugs.&lt;/p&gt;
&lt;p&gt;Don&#39;t get me wrong: memory safety and thread safety are huge on their own. For example, Netstack3 is able to pull all sorts of crazy buffer-sharing tricks in the name of performance that would be wildly dangerous in C or C++. I &lt;a rel=&quot;external&quot; href=&quot;https://www.youtube.com/watch?v=UfMOOxOGCmA&amp;amp;list=PLgC1L0fKd7UlpVTHVfLYVtudVx8CzbSxW&quot;&gt;gave a talk on those techniques&lt;/a&gt; at Rust Belt Rust in 2018 if you&#39;re curious about the details.&lt;/p&gt;
&lt;p&gt;But that&#39;s only half the story.&lt;/p&gt;
&lt;p&gt;Many critical bugs that we&#39;d like to prevent are neither memory bugs nor threading bugs.&lt;/p&gt;
&lt;p&gt;Take TCP, for example. If you want to implement what &lt;a rel=&quot;external&quot; href=&quot;https://www.rfc-editor.org/info/rfc4614&quot;&gt;RFC 4614&lt;/a&gt; refers to as &quot;basic functionality&quot; for TCP, you need to implement six different standards that run a combined 270 pages.&lt;/p&gt;
&lt;p&gt;Add in the &quot;recommended enhancements&quot; and you&#39;re up to a total of 18 standards spanning 476 pages.&lt;/p&gt;
&lt;p&gt;And that&#39;s just one protocol. Add Ethernet, ARP, NDP, IPv4, IPv6, ICMP, IGMP, MLD, UDP, and a host of others, and all the subtle interactions between them, and you start to realize that memory and threading bugs are just the tip of the iceberg of all the fun and exciting ways that you could fuck it up.&lt;/p&gt;
&lt;p&gt;That&#39;s why uncovering only three bugs in almost a year of dogfooding is so surprising. There&#39;s just no way that memory safety or thread safety alone would get you that level of robustness.&lt;/p&gt;
&lt;p&gt;So the points I&#39;m trying to make are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Out of the box, Rust guarantees that &quot;buggy programs don&#39;t compile&quot; only with respect to a small subset of the bugs we actually care about.&lt;/li&gt;
&lt;li&gt;Netstack3 would not have been able to achieve the level of robustness that it has by relying only on what the language provides out of the box.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, what Netstack3 has done — and what I believe any project can do — is to extend the Rust language to guarantee freedom from &lt;em&gt;almost any class of bugs&lt;/em&gt;, not just memory or threading bugs.&lt;/p&gt;
&lt;p&gt;This is what I mean by &quot;X-safety&quot; in the talk&#39;s abstract.&lt;/p&gt;
&lt;p&gt;As it stands today, Rust provides a core set of abstractions — lifetimes, references, RAII, traits, etc — and guarantees various safety properties related to those abstractions.&lt;/p&gt;
&lt;p&gt;But the majority of abstractions in the ecosystem are provided by libraries: JSON, random-number generators, cryptography, regular expressions, logging, time, TCP, PNG, SQL, command-line interfaces, linear algebra, browser APIs, and so on. Those libraries generally don&#39;t provide the same degree of safety with respect to their abstractions that we might expect from the language.&lt;/p&gt;
&lt;p&gt;But it doesn&#39;t have to be that way.&lt;/p&gt;
&lt;p&gt;As we&#39;ll see in the following examples, Rust&#39;s core abstractions alone are sufficient to express almost any safety property that we might care about. &lt;strong&gt;I claim that every library can and should provide the same level of safety with respect to its abstractions that we already expect of the language itself.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-general-framework-for-safety&quot;&gt;A general framework for safety&lt;/h2&gt;
&lt;p&gt;To explain the framework, we&#39;re going to turn to the humble binary tree:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    left&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Option&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    right&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Option&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    value&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For our binary tree to be correct, we of course need memory safety, but we need another safety property as well. We have to ensure that the tree is ordered: every value in the left subtree is less than our node&#39;s value, and our node&#39;s value is less than every value in the right subtree.&lt;/p&gt;
&lt;p&gt;Rust can guarantee memory safety, but it has no visibility into this ordering requirement, and so it can&#39;t enforce it for us. So how do we make sure that we never produce an invalidly-ordered tree?&lt;/p&gt;
&lt;p&gt;We use the concept of an &lt;em&gt;invariant&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;First, we document an ordering invariant that we expect to always hold for any &lt;code&gt;Node&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // INVARIANT: All values in `left` are less than `value`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    left&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Option&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // INVARIANT: All values in `right` are greater than `value`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    right&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Option&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    value&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we ensure that every time we create a new &lt;code&gt;Node&lt;/code&gt;, the ordering invariant holds:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // Post-condition: `Node`&amp;#39;s internal field invariants hold.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    pub fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; new&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            left&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; None&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            right&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; None&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            value&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, we ensure that every time we modify an existing &lt;code&gt;Node&lt;/code&gt;, we preserve the ordering invariant, assuming it held to begin with:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Node&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // Pre-condition: `Node`&amp;#39;s internal field invariants hold.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // Post-condition: `Node`&amp;#39;s internal field invariants hold.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    pub fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; insert&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; value&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Option&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now imagine that you are code outside of this module. (We&#39;ll restrict ourselves here to safe code; obviously &lt;code&gt;unsafe&lt;/code&gt; code can do whatever it wants.)&lt;/p&gt;
&lt;p&gt;I claim that, from the perspective of safe code outside of this module, there is no difference whatsoever between the safety invariants provided by the language and the ordering invariant provided by this module.&lt;/p&gt;
&lt;p&gt;If you write code which, if run, would violate Rust&#39;s memory-safety guarantees, Rust guarantees that the code will not compile. By a similar token, if you write code outside this module which, if run, would violate the ordering invariant, then similarly Rust guarantees that the code will not compile.&lt;/p&gt;
&lt;p&gt;In other words, by structuring our code in this way, we have in some sense &quot;taught&quot; Rust about a new safety property that it didn&#39;t know about before.&lt;/p&gt;
&lt;p&gt;We can use this &lt;code&gt;Node&lt;/code&gt; example to explain the framework. It has three components.&lt;/p&gt;
&lt;h3 id=&quot;definition&quot;&gt;Definition&lt;/h3&gt;
&lt;p&gt;First, &lt;strong&gt;definition&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We define an object that the Rust type system can reason about. In this case, we define the &lt;code&gt;Node&lt;/code&gt; struct. We attach to this object a safety property that Rust cannot reason about. In this case, that is the ordering property.&lt;/p&gt;
&lt;p&gt;Because Rust can&#39;t reason about this safety property, it&#39;s up to us, as the authors of the abstraction, to make sure never to violate it. This brings us to the second component.&lt;/p&gt;
&lt;h3 id=&quot;enforcement&quot;&gt;Enforcement&lt;/h3&gt;
&lt;p&gt;Second, &lt;strong&gt;enforcement&lt;/strong&gt;. Here, we enforce that our safety property is upheld – that responsibility is on us as the programmers.&lt;/p&gt;
&lt;p&gt;In this case, we use field privacy – we make sure that our struct fields are private. If they were public, external code could modify them and violate our safety property.&lt;/p&gt;
&lt;p&gt;Next, we make sure that all the code &lt;em&gt;we&lt;/em&gt; write preserves the safety property. In this case, the methods that modify the tree are responsible for maintaining its order.&lt;/p&gt;
&lt;h3 id=&quot;consumption&quot;&gt;Consumption&lt;/h3&gt;
&lt;p&gt;Finally, &lt;strong&gt;consumption&lt;/strong&gt;. This is where we get the bang for our buck.&lt;/p&gt;
&lt;p&gt;We write code that consumes the safety property as a precondition, and is only correct in virtue of that safety property being upheld. In this case, our methods can find the correct location in the tree for a particular value in &lt;code&gt;O(log N)&lt;/code&gt; time, without having to traverse the entire tree.&lt;/p&gt;
&lt;p&gt;That optimization is only valid because we are guaranteed that the tree is ordered. And the tree is only guaranteed to be ordered because we structured our code to &lt;strong&gt;define&lt;/strong&gt; and &lt;strong&gt;enforce&lt;/strong&gt; this ordering property so that we could later consume it as a precondition.&lt;/p&gt;
&lt;p&gt;With that framework in mind, Let&#39;s get to our first example.&lt;/p&gt;
&lt;h2 id=&quot;example-1-thread-safety&quot;&gt;Example 1: Thread safety&lt;/h2&gt;
&lt;p&gt;Our first example is from the standard library and concerns thread safety.&lt;/p&gt;
&lt;p&gt;What I&#39;m going to demonstrate is that not only can libraries use the language&#39;s core features to build new safety guarantees, but the standard library &lt;em&gt;itself&lt;/em&gt; already uses this technique.&lt;/p&gt;
&lt;p&gt;In fact, the thread safety that Rust advertises as one of its core features is not actually a language feature at all. It is implemented in the standard library and, in principle, could have been implemented in a third-party crate. It&#39;s just convenient to have it in the standard library.&lt;/p&gt;
&lt;p&gt;Imagine that you&#39;re writing &lt;code&gt;spawn&lt;/code&gt;. &lt;code&gt;spawn&lt;/code&gt; is a real function from the &lt;code&gt;thread&lt;/code&gt; module in the standard library (although I&#39;ve stripped down its signature for simplicity):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; spawn&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; FnOnce&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;()&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; F&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;) {&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; ...&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It takes a function and spawns a new thread that will run that function.&lt;/p&gt;
&lt;p&gt;If we think about how we might implement &lt;code&gt;spawn&lt;/code&gt;, we immediately run into a limitation in the language: the Rust language itself doesn&#39;t provide any mechanism to interact with threads. Threads are an operating system concept, and so creating a new thread requires going outside the language and making use of an API provided by the operating system itself.&lt;/p&gt;
&lt;p&gt;For example, on a POSIX system, this might require calling &lt;code&gt;libc&lt;/code&gt;&#39;s &lt;code&gt;pthread_create&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; spawn&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; FnOnce&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;()&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; F&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    unsafe&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; libc&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;pthread_create&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;) };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is where we run into the first core abstraction that we&#39;ll need to use as a building block.&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;libc&lt;/code&gt; functions like &lt;code&gt;pthread_create&lt;/code&gt; are implemented outside the language, Rust has no visibility into their behavior, and so it has no way of guaranteeing that calling such a function won&#39;t violate memory safety.&lt;/p&gt;
&lt;p&gt;This is why Rust introduces the notion of &lt;code&gt;unsafe&lt;/code&gt; code. &lt;code&gt;unsafe&lt;/code&gt; code is code that Rust can&#39;t guarantee won&#39;t violate memory safety. That doesn&#39;t mean it definitely &lt;em&gt;will&lt;/em&gt; violate memory safety. It just means that, on its own, Rust isn&#39;t smart enough to prove that it won&#39;t. Instead, Rust has to rely on the programmer to do the heavy lifting and confirm that the &lt;code&gt;unsafe&lt;/code&gt; code is correct — or &lt;em&gt;sound&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is the purpose of an &lt;code&gt;unsafe&lt;/code&gt; block like the one above. Inside an &lt;code&gt;unsafe&lt;/code&gt; block, Rust gives the programmer free rein to perform operations that Rust can&#39;t reason about. In exchange, the programmer takes responsibility for upholding memory safety. If they mess it up, all bets are off.&lt;/p&gt;
&lt;p&gt;This is our first example of using a core abstraction to extend the power of the language. Rust itself provides &lt;code&gt;unsafe&lt;/code&gt; functions and &lt;code&gt;unsafe&lt;/code&gt; blocks, but it doesn&#39;t provide any mechanism for interacting with threads. However, by using &lt;code&gt;unsafe&lt;/code&gt; in combination with external APIs like &lt;code&gt;pthread_create&lt;/code&gt;, we can &quot;teach&quot; the language about threads.&lt;/p&gt;
&lt;p&gt;As written, though, this implementation of &lt;code&gt;spawn&lt;/code&gt; is unsound.&lt;/p&gt;
&lt;p&gt;Not all values are thread-safe, meaning that not all values are sound to send between threads. Think of the difference between &lt;a rel=&quot;external&quot; href=&quot;https://doc.rust-lang.org/std/sync/struct.Arc.html&quot;&gt;&lt;code&gt;Arc&lt;/code&gt;&lt;/a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https://doc.rust-lang.org/std/rc/struct.Rc.html&quot;&gt;&lt;code&gt;Rc&lt;/code&gt;&lt;/a&gt;. As written, there&#39;s nothing to stop you from passing a closure that captures some value that is not thread-safe.&lt;/p&gt;
&lt;p&gt;So the standard library encodes the notion of thread safety in the type system.&lt;/p&gt;
&lt;p&gt;First, we introduce a new trait called &lt;code&gt;Send&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// # Safety&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// `Self` is thread-safe.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub unsafe trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the standard-library &lt;a rel=&quot;external&quot; href=&quot;https://doc.rust-lang.org/std/marker/trait.Send.html&quot;&gt;&lt;code&gt;Send&lt;/code&gt;&lt;/a&gt; that you all know and love.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;Send&lt;/code&gt; is an &lt;code&gt;unsafe&lt;/code&gt; trait. Just like &lt;code&gt;unsafe&lt;/code&gt; functions, &lt;code&gt;unsafe&lt;/code&gt; traits tell the type system: &quot;This trait has safety implications that you can&#39;t reason about.&quot; Just as calling an &lt;code&gt;unsafe&lt;/code&gt; function can only happen inside an &lt;code&gt;unsafe&lt;/code&gt; block, implementing an &lt;code&gt;unsafe&lt;/code&gt; trait requires an &lt;code&gt;unsafe impl&lt;/code&gt; block. The programmer must opt into taking responsibility for upholding memory safety.&lt;/p&gt;
&lt;p&gt;Since the language can&#39;t reason about the meaning of &lt;code&gt;Send&lt;/code&gt; – it&#39;s just an opaque trait with some name – we have to document its meaning in prose like we&#39;ve done here. In this case, we say that a type can only be &lt;code&gt;Send&lt;/code&gt; if it&#39;s thread-safe.&lt;/p&gt;
&lt;p&gt;Now that we&#39;ve introduced this trait, we can use it as a bound elsewhere in our program:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; spawn&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; FnOnce&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; +&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; F&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    unsafe&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; libc&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;pthread_create&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;) };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By requiring that &lt;code&gt;F&lt;/code&gt; implement &lt;code&gt;Send&lt;/code&gt;, we can make &lt;code&gt;spawn&lt;/code&gt; sound. There&#39;s no longer a risk that a programmer could accidentally call &lt;code&gt;spawn&lt;/code&gt; with a non-thread-safe value, because that wouldn&#39;t type-check.&lt;/p&gt;
&lt;p&gt;So we&#39;ve introduced this &lt;code&gt;Send&lt;/code&gt; trait that encodes the notion of thread safety, but we haven&#39;t actually implemented it for anything. Let&#39;s do that.&lt;/p&gt;
&lt;p&gt;First, we can implement &lt;code&gt;Send&lt;/code&gt; for any built-in type that we know is always thread-safe:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; u8&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; u16&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; u32&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From Rust&#39;s perspective, this is axiomatic. Using these &lt;code&gt;unsafe impl&lt;/code&gt; blocks, we&#39;ve declared by fiat that the &lt;code&gt;Send&lt;/code&gt; property holds of these types.&lt;/p&gt;
&lt;p&gt;Again, Rust has no way of knowing what &lt;code&gt;Send&lt;/code&gt; means, and so it has no way of knowing whether these implementations are correct. It&#39;s just taking our word for it.&lt;/p&gt;
&lt;p&gt;We can also implement &lt;code&gt;Send&lt;/code&gt; for more complex types. For example, a mutex is thread-safe by design, and so it&#39;s okay to send mutex references between threads:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;a Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we can permit arbitrary composite types to implement &lt;code&gt;Send&lt;/code&gt; by writing a custom derive:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;#[&lt;/span&gt;&lt;span&gt;derive&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Send&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; U&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; U&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, in reality, &lt;code&gt;Send&lt;/code&gt; uses a special mechanism known as an &lt;em&gt;auto trait&lt;/em&gt; to accomplish the same thing for ergonomics reasons. My point here is that there is no reason in principle that &lt;code&gt;Send&lt;/code&gt; couldn&#39;t have been developed as a library maintained by somebody other than the Rust project. Again, the core abstractions provided by the language are enough on their own to permit somebody to build an abstraction as powerful as &lt;code&gt;Send&lt;/code&gt; outside the Rust language project itself&lt;/p&gt;
&lt;p&gt;Sticking with the hypothetical, our custom derive would automatically emit an &lt;code&gt;unsafe impl&lt;/code&gt; block with the appropriate bounds. In particular, a type can be &lt;code&gt;Send&lt;/code&gt; if all its fields are &lt;code&gt;Send&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;#[&lt;/span&gt;&lt;span&gt;derive&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Send&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; U&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; U&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;// Derive-generated code:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; U&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; U&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    T&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    U&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Send&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;code&gt;Send&lt;/code&gt; is just a normal trait, once we&#39;ve written our implementations, it works like any other trait:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; u16&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; /* ... */&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;spawn&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;move ||&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // use `foo`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We know that this &lt;code&gt;Foo&lt;/code&gt; type is &lt;code&gt;Send&lt;/code&gt; because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We derived &lt;code&gt;Send&lt;/code&gt; for &lt;code&gt;Foo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We manually implemented &lt;code&gt;Send&lt;/code&gt; for &lt;code&gt;Mutex&lt;/code&gt; references.&lt;/li&gt;
&lt;li&gt;We manually implemented &lt;code&gt;Send&lt;/code&gt; for primitive types.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;How does this example fit into our framework?&lt;/p&gt;
&lt;h3 id=&quot;definition-1&quot;&gt;Definition&lt;/h3&gt;
&lt;p&gt;We define &lt;code&gt;Send&lt;/code&gt;, teaching Rust about a new trait. We use prose to document that &lt;code&gt;Send&lt;/code&gt; carries a special safety property that Rust can&#39;t reason about: thread safety.&lt;/p&gt;
&lt;h3 id=&quot;enforcement-1&quot;&gt;Enforcement&lt;/h3&gt;
&lt;p&gt;We define &lt;code&gt;Send&lt;/code&gt; as an unsafe trait so users can&#39;t violate the safety property without writing the &lt;code&gt;unsafe&lt;/code&gt; keyword.&lt;/p&gt;
&lt;p&gt;We manually implement &lt;code&gt;Send&lt;/code&gt; for types that we know satisfy the safety property.&lt;/p&gt;
&lt;p&gt;And, in our hypothetical version, we write a custom derive that generates an implementation that guarantees thread safety by requiring every field to be &lt;code&gt;Send&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;consumption-1&quot;&gt;Consumption&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;spawn&lt;/code&gt;, we use a &lt;code&gt;Send&lt;/code&gt; bound to justify that our internal call to &lt;code&gt;pthread_create&lt;/code&gt; is sound.&lt;/p&gt;
&lt;p&gt;And that&#39;s how Rust guarantees thread safety without any support from the language itself.&lt;/p&gt;
&lt;h2 id=&quot;example-2-deadlock-prevention&quot;&gt;Example 2: Deadlock prevention&lt;/h2&gt;
&lt;p&gt;Our second example is about preventing deadlocks. This is work by &lt;a rel=&quot;external&quot; href=&quot;https://github.com/akonradi&quot;&gt;Alex Konradi&lt;/a&gt;, who was on the Netstack3 team at the time – I&#39;m basically just bragging for him.&lt;/p&gt;
&lt;p&gt;Imagine you&#39;re writing a netstack and you want to make your stack multithreaded. You care about performance, so instead of putting one mutex around all your state, you do fine-grained locking, using small mutexes around different pieces of state:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Stack&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;IpState&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;DeviceState&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we saw in the previous example, Rust will guarantee that anything you do with these mutexes is thread-safe, but it won&#39;t prevent you from deadlocking.&lt;/p&gt;
&lt;p&gt;For example, imagine two different threads acquire these mutexes in different orders:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;// Thread A&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;// Thread B&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a classic deadlock scenario. If we&#39;re unlucky, Thread A will successfully acquire the IP mutex and Thread B will successfully acquire the device mutex. Now, to make progress, they&#39;re each blocked on the other.&lt;/p&gt;
&lt;p&gt;You can conceptualize this as a graph of the locks we might want to acquire. All threads start in an &lt;code&gt;Unlocked&lt;/code&gt; state, and can take different paths through the graph in order to acquire different locks:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;mermaid&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%%{init: {&amp;quot;theme&amp;quot;:&amp;quot;base&amp;quot;,&amp;quot;securityLevel&amp;quot;:&amp;quot;loose&amp;quot;,&amp;quot;flowchart&amp;quot;:{&amp;quot;htmlLabels&amp;quot;:true,&amp;quot;padding&amp;quot;:1,&amp;quot;diagramPadding&amp;quot;:0,&amp;quot;wrappingWidth&amp;quot;:520},&amp;quot;themeCSS&amp;quot;:&amp;quot;.diagram-box{stroke:none!important}.box-unlocked{fill:#e0e0e0!important}.box-ip{fill:#f2d4d3!important}.box-device{fill:#d3d2f5!important}.diagram-black{fill:none!important;stroke:#000!important;stroke-linecap:butt!important;stroke-linejoin:miter!important}.black-left{stroke-width:1.4px!important}.black-right{stroke-width:1.4px!important}.diagram-red{fill:none!important;stroke:#db3b26!important;stroke-width:2.8px!important;stroke-linecap:butt!important;stroke-linejoin:miter!important}.diagram-arrow{fill:#db3b26!important;stroke:none!important}.diagram-label{fill:#000!important;font-family:Liberation Mono,Menlo,Monaco,Consolas,Courier New,monospace!important;font-weight:400!important}.diagram-node-label{font-size:38px!important;letter-spacing:0.375px!important;stroke:#000!important;stroke-width:0.8px!important;paint-order:stroke fill!important}.diagram-thread-label{font-size:26.75px!important;letter-spacing:0.125px!important;stroke:#000!important;stroke-width:0.5px!important;paint-order:stroke fill!important}&amp;quot;}}%%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;flowchart&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  canvas&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot;&amp;lt;svg xmlns=&amp;#39;http://www.w3.org/2000/svg&amp;#39; width=&amp;#39;520&amp;#39; height=&amp;#39;399&amp;#39; viewBox=&amp;#39;0 0 586 450&amp;#39; style=&amp;#39;display:block&amp;#39;&amp;gt;&amp;lt;g transform=&amp;#39;translate(-2,-1)&amp;#39;&amp;gt;&amp;lt;rect class=&amp;#39;diagram-box box-unlocked&amp;#39; x=&amp;#39;197&amp;#39; y=&amp;#39;23&amp;#39; width=&amp;#39;198&amp;#39; height=&amp;#39;128&amp;#39;/&amp;gt;&amp;lt;rect class=&amp;#39;diagram-box box-ip&amp;#39; x=&amp;#39;21&amp;#39; y=&amp;#39;240&amp;#39; width=&amp;#39;198&amp;#39; height=&amp;#39;198&amp;#39;/&amp;gt;&amp;lt;rect class=&amp;#39;diagram-box box-device&amp;#39; x=&amp;#39;373&amp;#39; y=&amp;#39;240&amp;#39; width=&amp;#39;198&amp;#39; height=&amp;#39;198&amp;#39;/&amp;gt;&amp;lt;line class=&amp;#39;diagram-red&amp;#39; x1=&amp;#39;127&amp;#39; y1=&amp;#39;307.6&amp;#39; x2=&amp;#39;365&amp;#39; y2=&amp;#39;307.6&amp;#39;/&amp;gt;&amp;lt;polygon class=&amp;#39;diagram-arrow&amp;#39; points=&amp;#39;361.5,301.5 373,307.5 361.5,313.5&amp;#39;/&amp;gt;&amp;lt;line class=&amp;#39;diagram-red&amp;#39; x1=&amp;#39;230&amp;#39; y1=&amp;#39;375&amp;#39; x2=&amp;#39;465&amp;#39; y2=&amp;#39;375&amp;#39;/&amp;gt;&amp;lt;polygon class=&amp;#39;diagram-arrow&amp;#39; points=&amp;#39;231,369 219,375 231,381&amp;#39;/&amp;gt;&amp;lt;path class=&amp;#39;diagram-black black-left&amp;#39; d=&amp;#39;M197 86.75 H127.25 V307.75&amp;#39;/&amp;gt;&amp;lt;path class=&amp;#39;diagram-black black-right&amp;#39; d=&amp;#39;M395 86.75 H465 V376&amp;#39;/&amp;gt;&amp;lt;text class=&amp;#39;diagram-label diagram-node-label&amp;#39; x=&amp;#39;295.75&amp;#39; y=&amp;#39;101&amp;#39; text-anchor=&amp;#39;middle&amp;#39;&amp;gt;Unlocked&amp;lt;/text&amp;gt;&amp;lt;text class=&amp;#39;diagram-label diagram-node-label&amp;#39; x=&amp;#39;120.5&amp;#39; y=&amp;#39;352&amp;#39; text-anchor=&amp;#39;middle&amp;#39;&amp;gt;IP&amp;lt;/text&amp;gt;&amp;lt;text class=&amp;#39;diagram-label diagram-node-label&amp;#39; x=&amp;#39;471.75&amp;#39; y=&amp;#39;353&amp;#39; text-anchor=&amp;#39;middle&amp;#39;&amp;gt;Device&amp;lt;/text&amp;gt;&amp;lt;text class=&amp;#39;diagram-label diagram-thread-label&amp;#39; x=&amp;#39;295.5&amp;#39; y=&amp;#39;298&amp;#39; text-anchor=&amp;#39;middle&amp;#39;&amp;gt;Thread A&amp;lt;/text&amp;gt;&amp;lt;text class=&amp;#39;diagram-label diagram-thread-label&amp;#39; x=&amp;#39;296.25&amp;#39; y=&amp;#39;401&amp;#39; text-anchor=&amp;#39;middle&amp;#39;&amp;gt;Thread B&amp;lt;/text&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;/svg&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  style canvas fill&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;transparent&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;stroke&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;transparent&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;stroke-width&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;0px&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To avoid the risk of deadlocking, we need to make sure that this graph is acyclic. The two acquisition orders above form a cycle, so we need to remove at least one of those red edges.&lt;/p&gt;
&lt;p&gt;This might seem like a fairly trivial problem in this tiny example. It&#39;s pretty obvious from looking at the code that it might deadlock.&lt;/p&gt;
&lt;p&gt;But Netstack3 has 77 different mutexes protecting all manner of different state spread across 192,000 lines of code. You can imagine that keeping track of the order in which you&#39;re supposed to acquire mutexes in that environment would get pretty difficult pretty fast.&lt;/p&gt;
&lt;p&gt;And indeed, Netstack2, its predecessor which is written in Go, has historically been plagued by deadlocks.&lt;/p&gt;
&lt;p&gt;So the Netstack3 team decided to try to prevent deadlocks statically, at compile time. To do this, they needed a way to encode a lock-order graph in the type system and a way to ensure that code could only acquire locks consistent with that graph.&lt;/p&gt;
&lt;p&gt;Let&#39;s see how they did it.&lt;/p&gt;
&lt;h3 id=&quot;name-every-mutex&quot;&gt;Name every mutex&lt;/h3&gt;
&lt;p&gt;The first step is to name each mutex:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    mtx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; std&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    _marker&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; PhantomData&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This new &lt;code&gt;Mutex&lt;/code&gt; type is identical to the standard-library mutex, except that it carries an extra type parameter used to identify the mutex.&lt;/p&gt;
&lt;p&gt;Returning to our example, we define one type per mutex and use those types as names:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Stack&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;IpLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpState&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;DeviceLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; DeviceState&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; DeviceLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These types are never constructed at runtime. We only need them for type-system purposes.&lt;/p&gt;
&lt;h3 id=&quot;encode-the-lock-order-graph&quot;&gt;Encode the lock-order graph&lt;/h3&gt;
&lt;p&gt;Next, we define the &lt;code&gt;LockAfter&lt;/code&gt; and &lt;code&gt;LockBefore&lt;/code&gt; traits:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// # Safety&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// No cycles!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub unsafe trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockAfter&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub unsafe trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockBefore&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockAfter&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; A&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockBefore&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; A&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These traits encode the lock-order graph. They&#39;re &lt;code&gt;unsafe&lt;/code&gt; to implement because the user has to promise not to introduce a lock-order graph with cycles. If they do, they violate our safety property.&lt;/p&gt;
&lt;p&gt;Next, we define a macro that implements these traits on behalf of a user:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;macro_rules! impl_lock_after&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    (&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ty&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt; $&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ty&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // SAFETY: The blanket impl will cause any cycles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // to result in a blanket impl conflict, and thus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // won&amp;#39;t compile.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        unsafe impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockAfter&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for $&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        unsafe impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockBefore&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockAfter&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for $&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;impl_lock_after!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;TransportLock&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;impl_lock_after!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;IpLock&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; DeviceLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the macro expansion adds a blanket implementation. Don&#39;t worry about following the full logic here, but the consequence of that blanket implementation is important: if a user invokes the macro in a way that introduces cycles into the lock graph, those blanket implementations will conflict with one another.&lt;/p&gt;
&lt;p&gt;Cyclic graphs therefore fail to compile.&lt;/p&gt;
&lt;h3 id=&quot;track-the-current-position-in-the-graph&quot;&gt;Track the current position in the graph&lt;/h3&gt;
&lt;p&gt;Next, we define the notion of a &lt;em&gt;lock context&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;PhantomData&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;LockCtx&lt;/code&gt; allows the type system to keep track of where in the lock graph you are at any given point in the source code. It is a zero-sized type, so it has no cost at runtime.&lt;/p&gt;
&lt;p&gt;Using these building blocks, we can build a deadlock-proof locking API:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    pub fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        ctx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    )&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;MutexGuard&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    where&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        L&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockBefore&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;        (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;mtx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            LockCtx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;PhantomData&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s walk through the components of this signature one by one.&lt;/p&gt;
&lt;p&gt;First, we require an existing &lt;code&gt;LockCtx&lt;/code&gt;. Note that we borrow it mutably, which disables the &lt;code&gt;LockCtx&lt;/code&gt; for further use until we&#39;ve unlocked the mutex by dropping the &lt;code&gt;MutexGuard&lt;/code&gt;. So long as we&#39;re holding the mutex, that context is effectively unusable.&lt;/p&gt;
&lt;p&gt;Second, we require that the existing &lt;code&gt;LockCtx&lt;/code&gt; has a lock ID upstream of our lock ID in the graph. This prevents us from locking a mutex which we&#39;ve already locked.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockBefore&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we return a new &lt;code&gt;LockCtx&lt;/code&gt; that the caller can use to continue locking mutexes (recall that the original &lt;code&gt;LockCtx&lt;/code&gt; is now unusable so long as the current mutex is held). This new &lt;code&gt;LockCtx&lt;/code&gt; has our lock ID. So long as the returned &lt;code&gt;MutexGuard&lt;/code&gt; exists — in other words, so long as this lock is held — this new &lt;code&gt;LockCtx&lt;/code&gt; is the only usable lock context, and it only permits locking mutexes downstream of this one in the lock graph.&lt;/p&gt;
&lt;p&gt;One last bit of boilerplate: to represent the root of any lock graph, we introduce the &lt;code&gt;Unlocked&lt;/code&gt; type and permit anyone to construct a lock context that starts off unlocked:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Unlocked&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Unlocked&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    pub const&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; UNLOCKED&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Unlocked&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;PhantomData&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;use-the-graph&quot;&gt;Use the graph&lt;/h3&gt;
&lt;p&gt;Let&#39;s go back to our example and see how we can use this machinery to prevent deadlocks.&lt;/p&gt;
&lt;p&gt;As we showed before, we introduce one type for each mutex and use the macro to encode our graph in the type system as implementations of &lt;code&gt;LockAfter&lt;/code&gt; and &lt;code&gt;LockBefore&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Stack&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;IpLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpState&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Mutex&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;DeviceLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; DeviceState&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; DeviceLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;impl_lock_after!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Unlocked&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;impl_lock_after!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;IpLock&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; DeviceLock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember that this code will only compile so long as the graph is free of cycles.&lt;/p&gt;
&lt;p&gt;Now let&#39;s walk through how we use this graph at runtime. First, we construct a new context that starts in the unlocked state:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;UNLOCKED&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we lock our first mutex — the IP mutex. This generates a &lt;code&gt;MutexGuard&lt;/code&gt; and a new &lt;code&gt;LockCtx&lt;/code&gt; that shadows the old one:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we repeat the same process to lock the device mutex:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting it together:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;UNLOCKED&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now take a look at what happens if we try to violate the lock order. As before, we start in an unlocked state and directly lock the device mutex:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; LockCtx&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;UNLOCKED&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;device&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On its own, that is fine. We haven&#39;t introduced a cycle yet, so it compiles.&lt;/p&gt;
&lt;p&gt;But if, having acquired the device mutex, we now try to acquire the IP mutex, that won&#39;t compile, because there&#39;s no path in the graph from the device mutex to the IP mutex:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; stack&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;mut&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ctx&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;//                                ^^^^^^^^ ERROR&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How does this fit into our framework?&lt;/p&gt;
&lt;h3 id=&quot;definition-2&quot;&gt;Definition&lt;/h3&gt;
&lt;p&gt;First, we define the &lt;code&gt;LockAfter&lt;/code&gt; and &lt;code&gt;LockBefore&lt;/code&gt; traits. We document in prose that they carry a safety property: they always encode an acyclic graph.&lt;/p&gt;
&lt;p&gt;Second, we define the &lt;code&gt;Mutex&lt;/code&gt; type. We document in prose that it carries a safety property: it is only locked consistent with a predefined lock-order graph.&lt;/p&gt;
&lt;h3 id=&quot;enforcement-2&quot;&gt;Enforcement&lt;/h3&gt;
&lt;p&gt;We make the &lt;code&gt;LockAfter&lt;/code&gt; and &lt;code&gt;LockBefore&lt;/code&gt; traits &lt;code&gt;unsafe&lt;/code&gt; so that a user can only violate our safety property by writing the &lt;code&gt;unsafe&lt;/code&gt; keyword.&lt;/p&gt;
&lt;p&gt;We design &lt;code&gt;impl_lock_after!&lt;/code&gt; so that it guarantees that only acyclic graphs can compile.&lt;/p&gt;
&lt;p&gt;And we use a &lt;code&gt;LockBefore&lt;/code&gt; bound to ensure that the &lt;code&gt;lock&lt;/code&gt; method can only be called consistently with the lock-order graph.&lt;/p&gt;
&lt;h3 id=&quot;consumption-2&quot;&gt;Consumption&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;lock&lt;/code&gt; method uses its &lt;code&gt;LockBefore&lt;/code&gt; bound to justify that locking the inner mutex won&#39;t deadlock.&lt;/p&gt;
&lt;p&gt;What I have presented here is a simplified version of what exists in practice. There are actually two subtle ways that I&#39;m aware of that you can violate deadlock safety using this simplified version. And there&#39;s an interesting conversation to be had about whether safety properties like these should be literally impossible to circumvent, or whether they only need to be hard enough to circumvent that you could&#39;t shoot yourself in the foot by accident.&lt;/p&gt;
&lt;p&gt;In reality, the lock-ordering library takes the latter approach. I&#39;m not going to get into that discussion here, and it doesn&#39;t really affect the point I&#39;m trying to make.&lt;/p&gt;
&lt;h2 id=&quot;the-results&quot;&gt;The results&lt;/h2&gt;
&lt;p&gt;How has this played out for Netstack3?&lt;/p&gt;
&lt;p&gt;In the beginning, Netstack3 was entirely single-threaded for simplicity. But over the past few years, the team has been working to thread mutexes and mutex guards through the entire stack. Finally, just a few weeks ago, they had finished that process and were ready to flip the switch — to go from running on one thread to running on multiple threads.&lt;/p&gt;
&lt;p&gt;So they changed the default number of threads from one to four:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Self(NonZeroU8::new(1).unwrap())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+ Self(NonZeroU8::new(4).unwrap())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it. &lt;a rel=&quot;external&quot; href=&quot;https://fxrev.dev/1102436&quot;&gt;That was the whole change&lt;/a&gt;. It was bug-free on the first try.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Those are my two examples.&lt;/p&gt;
&lt;p&gt;I&#39;d like to encourage you to try this methodology for yourself, and especially to bring it to new domains and new classes of bugs that nobody in the Rust community has tackled yet.&lt;/p&gt;
&lt;p&gt;Let me give you a few pieces of concrete advice to help get you started.&lt;/p&gt;
&lt;h3 id=&quot;treat-partial-functions-as-a-code-smell&quot;&gt;Treat partial functions as a code smell&lt;/h3&gt;
&lt;p&gt;On a practical note, think of partial functions in your API as a code smell.&lt;/p&gt;
&lt;p&gt;Your public functions should never panic, and they usually shouldn&#39;t return &lt;code&gt;Option&lt;/code&gt; or &lt;code&gt;Result&lt;/code&gt; unless that is inherent to the behavior you&#39;re modeling.&lt;/p&gt;
&lt;p&gt;Returning an error because an I/O operation failed is unavoidable and totally fine. Returning an error because the caller passed an illegal value? That code shouldn&#39;t have compiled in the first place.&lt;/p&gt;
&lt;p&gt;For great primers on this way of thinking, I recommend &lt;a rel=&quot;external&quot; href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot;&gt;Parse, don&#39;t validate&lt;/a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https://www.parsonsmatt.org/2017/10/11/type_safety_back_and_forth.html&quot;&gt;Type Safety Back and Forth&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;make-your-apis-exactly-match-the-problem&quot;&gt;Make your APIs exactly match the problem&lt;/h3&gt;
&lt;p&gt;Make your APIs exactly match the structure of the problem you&#39;re modeling.&lt;/p&gt;
&lt;p&gt;Here is the error type that Netstack3 returns when it fails to parse an IP packet:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpParseError&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IcmpIpExt&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    Parse&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        error&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ParseError&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    ParameterProblem&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        src_ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; I&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Addr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        dst_ip&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; I&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Addr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        code&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; I&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ParameterProblemCode&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        pointer&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; I&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ParameterProblemPointer&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        must_send_icmp&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        header_len&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; I&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;HeaderLen&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        action&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpParseErrorAction&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; IpParseErrorAction&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    DiscardPacket&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    DiscardPacketSendIcmp&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    DiscardPacketSendIcmpNoMulticast&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub enum&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; ParseError&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    NotSupported&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    NotExpected&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    Checksum&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    Format&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This may seem surprisingly convoluted, but it is a faithful representation of the complexity of both the IPv4 and IPv6 protocols. To do anything simpler would cause us problems down the line.&lt;/p&gt;
&lt;p&gt;For example, let&#39;s zoom in on the &lt;em&gt;parameter problem pointer&lt;/em&gt; field.&lt;/p&gt;
&lt;p&gt;If you receive a malformed packet, you have to respond with your own packet containing an error message. That error message identifies the byte offset of the malformed field that caused parsing to fail. That byte offset is known as the &quot;parameter problem pointer&quot;.&lt;/p&gt;
&lt;p&gt;Note the generic type here. In IPv4, the field in the error message that stores this pointer is one byte long. In IPv6, it&#39;s four bytes long. Using generics ensures that we always store the byte offset using the right size of integer.&lt;/p&gt;
&lt;p&gt;If instead we uniformly stored the pointer as, for example, a &lt;code&gt;u32&lt;/code&gt;, we would have to perform a fallible conversion elsewhere in the codebase. If we had a bug, that conversion would either silently produce incorrect error packets or panic and crash the stack.&lt;/p&gt;
&lt;p&gt;By ensuring that our error type faithfully models the behavior of IPv4 and IPv6, we can make that sort of bug impossible.&lt;/p&gt;
&lt;h3 id=&quot;expect-diverse-solutions&quot;&gt;Expect diverse solutions&lt;/h3&gt;
&lt;p&gt;Don&#39;t expect the solution to always be the same.&lt;/p&gt;
&lt;p&gt;Just because the catchphrase is always that &quot;buggy programs don&#39;t compile&quot; doesn&#39;t mean that there&#39;s a recipe. In my experience, different problems call for wildly different solutions that leverage a hodgepodge of language features.&lt;/p&gt;
&lt;h3 id=&quot;simplicity-is-the-art-of-hiding-complexity&quot;&gt;Simplicity is the art of hiding complexity&lt;/h3&gt;
&lt;p&gt;Don&#39;t expect it to always fall out naturally.&lt;/p&gt;
&lt;p&gt;One of my favorite quotes is from Rob Pike, &lt;a rel=&quot;external&quot; href=&quot;https://go.dev/talks/2015/simplicity-is-complicated.slide#18&quot;&gt;talking about Go&#39;s design&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Simplicity is the art of hiding complexity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Your responsibility is to do the hard work so that your users have a simple mental model of your API and they don&#39;t have to understand how awful the internals of your library are.&lt;/p&gt;
&lt;p&gt;Rust wasn&#39;t explicitly designed to support this methodology, at least not in its full generality, and you may have to really bend the language to your will.&lt;/p&gt;
&lt;p&gt;For example, if you haven&#39;t seen the trick, it is not at all obvious that it would be possible to prevent graph cycles using the trait system. The internals of the lock-ordering library are kind of ugly as a result, but the mental model that a user needs in order to reason about the API is very simple:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cyclic graphs don&#39;t compile.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&#39;s it.&lt;/p&gt;
&lt;h3 id=&quot;turtles-all-the-way-down&quot;&gt;Turtles all the way down&lt;/h3&gt;
&lt;p&gt;When it comes to your internal APIs, use the same level of discipline and rigor that you would use with a public API.&lt;/p&gt;
&lt;p&gt;If a function has safety requirements, make it an &lt;code&gt;unsafe&lt;/code&gt; function. If a function can panic, document it clearly.&lt;/p&gt;
&lt;p&gt;It may seem obvious in the moment how to call an internal API correctly, but it won&#39;t be so obvious to the new developer on the team four years and six refactors from now. If you keep up this discipline, then no matter how much time passes, your internal APIs will be just as easy to use correctly as the day you wrote them.&lt;/p&gt;
&lt;p&gt;We adhered to this discipline strictly in Netstack3, and the larger the project grew, the more it paid off.&lt;/p&gt;
&lt;h2 id=&quot;a-bit-of-speculation&quot;&gt;A bit of speculation&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;We&#39;re late in the podcast now, so we can let our hair down a bit and speculate.&lt;/p&gt;
&lt;p&gt;– Sean Carroll&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, if you&#39;ll permit me a bit of speculation, I think this methodology has the potential to fundamentally reshape how we engage in the process of software engineering, and I think that so far we&#39;ve only scratched the surface of how far we can push it.&lt;/p&gt;
&lt;p&gt;One reason is that there are domains where correctness is a much bigger deal than it is for most of us in this room. Rust is only just starting to make inroads into high-assurance domains like automotive, aerospace, medical devices, and so on. Those are domains where bugs are so unacceptable that the pace of development is absolutely glacial.&lt;/p&gt;
&lt;p&gt;I&#39;m not suggesting that we&#39;re going to be able to stop doing code reviews or anything crazy like that. But imagine how much faster we could move if we eliminated entire classes of bugs that we normally have to catch through reviews or testing.&lt;/p&gt;
&lt;p&gt;Another reason I think this methodology could be a big deal is that it allows software to scale more effectively.&lt;/p&gt;
&lt;p&gt;Software complexity often scales superlinearly as a function of the size of the codebase, and much of that complexity is incidental rather than inherent. Humans only have so much mental capacity. As incidental complexity increases, it crowds out our ability to reason about the inherent complexity that we&#39;re actually interested in. That puts a natural upper limit on the inherent complexity of the problems we can tackle.&lt;/p&gt;
&lt;p&gt;My guess is that this methodology stands to make the biggest difference in large, complex codebases, where small savings in complexity across every module compound on one another.&lt;/p&gt;
&lt;p&gt;That has certainly been our experience in Netstack3.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;As I mentioned at the beginning, I wasn&#39;t able to provide nearly as many examples as I would have liked. I strongly encourage you to check out the &lt;a rel=&quot;external&quot; href=&quot;https://gist.github.com/joshlf/65ccb20e034445a0fc6595f3a270653d&quot;&gt;references&lt;/a&gt; and do more reading on your own.&lt;/p&gt;
&lt;p&gt;I really believe that, thanks to Rust, we have the opportunity to fundamentally improve the state of software engineering, and I intend to spend the next phase of my career proving it.&lt;/p&gt;
&lt;p&gt;I hope you&#39;ll join me. Thank you.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>I May Have Been Targeted by a Spear Phishing Attack</title>
    <published>2026-06-26T00:00:00+00:00</published>
    
    <updated>2026-06-26T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/spear-phishing/"/>
    <id>https://joshlf.com/posts/spear-phishing/</id>
    
      
    <category term="Rust"/>
      
    <category term="Security"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/spear-phishing/">&lt;p&gt;Matthew Mastracci &lt;a rel=&quot;external&quot; href=&quot;https://grack.com/blog/2026/06/25/dissecting-a-failed-nation-state-attack/&quot;&gt;recently published&lt;/a&gt; a writeup of an apparent targeted supply-chain attack against Rust maintainers. This was &lt;a rel=&quot;external&quot; href=&quot;https://www.reddit.com/r/rust/comments/1ug9pzn/anatomy_of_a_failed_nationstate_attack/&quot;&gt;posted&lt;/a&gt; to &lt;a rel=&quot;external&quot; href=&quot;https://www.reddit.com/r/rust/&quot;&gt;r/rust&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was one of the maintainers who received similar outreach. In my case, I assume the target was my maintainer access to &lt;a rel=&quot;external&quot; href=&quot;https://crates.io/crates/zerocopy&quot;&gt;zerocopy&lt;/a&gt;. &lt;a rel=&quot;external&quot; href=&quot;https://grack.com/blog/2026/06/25/dissecting-a-failed-nation-state-attack/#what-it-drops&quot;&gt;According to Matthew&lt;/a&gt;, the payload he received was a remote access trojan (RAT):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The drop is a full remote-access trojan that seems to have been put together by someone who knows what they are doing. It sets up an RSA key locally and uses AES-256-CBC as a session key.&lt;/p&gt;
&lt;p&gt;On startup it calls a checkin routine that harvests and exfiltrates a host fingerprint:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;primary IP address (enumerates all non-internal interfaces), plus all IPs&lt;/li&gt;
&lt;li&gt;username (&lt;code&gt;os.userInfo().username&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;hostname&lt;/li&gt;
&lt;li&gt;OS type + release + platform + architecture&lt;/li&gt;
&lt;li&gt;process PID and full &lt;code&gt;process.argv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Node version&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It generates an RSA-2048 keypair and a random AES-256 session key (aes_psk), then all subsequent traffic is AES-256-CBC encrypted with an HMAC-SHA256 integrity tag.&lt;/p&gt;
&lt;p&gt;It supports the following commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;env&lt;/code&gt; — &lt;code&gt;JSON.stringify(process.env)&lt;/code&gt; dumped and sent back.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;upload&lt;/code&gt; — reads an arbitrary file path and exfiltrates it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;download&lt;/code&gt; — writes attacker-supplied bytes to any writable path.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spawn&lt;/code&gt; — runs an arbitrary process with optional shell expansion.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ls&lt;/code&gt; / &lt;code&gt;cd&lt;/code&gt; / &lt;code&gt;pwd&lt;/code&gt; / &lt;code&gt;cp&lt;/code&gt; / &lt;code&gt;mv&lt;/code&gt; — general filesystem primitives.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dns&lt;/code&gt; — makes the host resolve arbitrary names through a specified resolver (for DNS tunneling?).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dismantle&lt;/code&gt; — self-removal.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here are the emails I received:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/spear-phishing/screenshot1.png&quot; alt=&quot;Email screenshot 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/spear-phishing/screenshot2.png&quot; alt=&quot;Email screenshot 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/spear-phishing/screenshot3.png&quot; alt=&quot;Email screenshot 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/spear-phishing/screenshot4.png&quot; alt=&quot;Email screenshot 4&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The approach was professionally plausible: someone claiming to represent a VC firm reached out about (presumably paid) technical diligence/consulting. While in my case the conversation petered out before moving beyond email, other targets were eventually directed toward a software project which, as Matthew&#39;s post describes, contained malicious code.&lt;/p&gt;
&lt;p&gt;I don&#39;t know who was behind this, and I don&#39;t have independent evidence for attribution. But it appears to have been a coordinated attempt to compromise the maintainers of widely-used Rust crates. A similar attack – presumably carried out by the same actors – is &lt;a rel=&quot;external&quot; href=&quot;https://www.linkedin.com/posts/piyush-shukla-44b7a11b1_yesterday-i-came-across-one-of-the-most-ugcPost-7422893062072328192-bz7d/&quot;&gt;described by&lt;/a&gt; Piyush Shukla roughly four months before Matthew&#39;s post. Piyush was himself the target; he works in the cryptocurrency space, so this may go beyond just Rust.&lt;/p&gt;
&lt;p&gt;This post is just to add my data point to the public record: maintainers of high-impact open-source Rust projects are being targeted through ordinary-looking professional outreach.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>The Coming Programming Language Renaissance</title>
    <published>2026-06-08T00:00:00+00:00</published>
    
    <updated>2026-06-08T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/pl-renaissance/"/>
    <id>https://joshlf.com/posts/pl-renaissance/</id>
    
      
    
    <content type="html" xml:base="https://joshlf.com/posts/pl-renaissance/">&lt;p&gt;For decades, programming language researchers have invented ways to make programs more explicit, more checkable, more constrained, more secure, and more verifiable. Refinement types. Dependent types. Effect systems. Session types. Typestate. Linear types. Contracts. Capabilities. Model checking. Proof assistants. Program synthesis. Typed holes. Semantic editing.&lt;/p&gt;
&lt;p&gt;While watered-down versions of some of these have occasionally made it out of the academy (&quot;&lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Rust_(programming_language)#2006.E2.80.932009:_Early_years&quot;&gt;technology from the past come to save the future from itself&lt;/a&gt;&quot;), these are the exceptions that prove the rule. For the most part, what we know how to do &lt;em&gt;in theory&lt;/em&gt; makes our industrial practice look like it&#39;s stuck in the stone age.&lt;/p&gt;
&lt;p&gt;Some powerful programming language research directions are hamstrung by fundamental constraints like computability, but my sense is that most of what stops great programming language ideas from escaping the academy are human factors constraints. Human cognition is weird and, in many ways, &lt;em&gt;extremely&lt;/em&gt; limited. Empirical work shows, for example, that even apparently superficial language syntax choices can &lt;a rel=&quot;external&quot; href=&quot;https://www.vidarholen.net/~vidar/An_Empirical_Investigation_into_Programming_Language_Syntax.pdf&quot;&gt;materially affect programmer accuracy and learning&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Coding agents, on the other hand, have few of the same limitations. Research already shows that they excel where humans struggle, benefiting from their ability to &lt;a rel=&quot;external&quot; href=&quot;https://arxiv.org/abs/2606.01522&quot;&gt;read verbose error messages&lt;/a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https://ranjitjhala.github.io/static/icse25-neurosymbolic-refinement-inference.pdf&quot;&gt;author precise specifications&lt;/a&gt;, and tolerate the iteration required to &lt;a rel=&quot;external&quot; href=&quot;https://dl.acm.org/doi/abs/10.1145/3763174&quot;&gt;generate valid proofs of program correctness&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;ve been here before. In the 1930s and 1940s, between the Great Depression suppressing demand for new technology, wartime secrecy requirements preventing discoveries from being made public,&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-secrecy-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/pl-renaissance/#fn-secrecy&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; and military demand driving increased R&amp;amp;D spending, a huge backlog of research built up. Some economists have suggested that America&#39;s &lt;a rel=&quot;external&quot; href=&quot;https://www.youtube.com/watch?v=Mh5LY4Mz15o&amp;amp;t=524s&quot;&gt;postwar economic miracle&lt;/a&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-pwem-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/pl-renaissance/#fn-pwem&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; – which brought us innovations from the &lt;a rel=&quot;external&quot; href=&quot;https://www.si.edu/collections/snapshot/microwave-oven&quot;&gt;microwave&lt;/a&gt; to &lt;a rel=&quot;external&quot; href=&quot;https://www.britannica.com/technology/history-of-flight/The-jet-age&quot;&gt;commercial aviation&lt;/a&gt; to &lt;a rel=&quot;external&quot; href=&quot;https://www.acs.org/education/whatischemistry/landmarks/flemingpenicillin.html&quot;&gt;mass-market penicillin&lt;/a&gt; – was in part the natural consequence of corporations simply &lt;a rel=&quot;external&quot; href=&quot;https://andrewjfieldhouse.com/wp-content/uploads/2024/11/The_Return_to_Government_R_D_revised_manuscript.pdf&quot;&gt;working through this research backlog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Programming language development in 2026 looks very similar. Decades of theoretical innovation have built up in the academy due to human limitations that are about to be lifted en masse at exactly the time when demand for the &lt;em&gt;production&lt;/em&gt; of new programming artifacts is skyrocketing.&lt;/p&gt;
&lt;p&gt;Concretely, I predict that agentic programming will lead to a renaissance in programming language design. Language designers, faced with a fundamentally new type of user, suddenly have decades of theoretical research to draw from in designing new, powerful language features uniquely suited to the strengths of coding agents. Whether innovation takes the form of new language features in existing languages, DSLs, entirely new languages, or even a reimagining of what counts as a programming language, change is coming.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-secrecy&quot;&gt;
&lt;p&gt;During WWII, the USPTO placed &lt;a rel=&quot;external&quot; href=&quot;https://ideas.repec.org/a/inm/ormnsc/v69y2023i4p2318-2338.html&quot;&gt;more than 11,000 patent applications&lt;/a&gt; under secrecy orders, then rescinded them en masse after the war. &lt;a href=&quot;https://joshlf.com/posts/pl-renaissance/#fr-secrecy-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-pwem&quot;&gt;
&lt;p&gt;That video is about Japan, but the reference was too good to resist. &lt;a href=&quot;https://joshlf.com/posts/pl-renaissance/#fr-pwem-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Memory Safety Is a Matter of Life and Death</title>
    <published>2026-06-02T00:00:00+00:00</published>
    
    <updated>2026-06-02T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/memory-safety-life-and-death/"/>
    <id>https://joshlf.com/posts/memory-safety-life-and-death/</id>
    
      
    
    <content type="html" xml:base="https://joshlf.com/posts/memory-safety-life-and-death/">&lt;p&gt;In 2018, Saudi journalist Jamal Khashoggi&#39;s fiancée&#39;s phone was hacked. Later that year, Khashoggi walked into the Saudi Arabian consulate in Istanbul to obtain documents related to his planned marriage, and &lt;a rel=&quot;external&quot; href=&quot;https://www.boston25news.com/news/national/journalist-jamal-khashoggis-disappearance-a-timeline-of-events/854679184/&quot;&gt;left two hours later&lt;/a&gt; in a body bag.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s easy to forget that the work we do affects real people. It&#39;s easy to feel, if only unconsciously, that the &lt;em&gt;point&lt;/em&gt; of programming is to be mathematically beautiful or fun to use. It&#39;s easy to forget that buffer overflows aren&#39;t just bad in the abstract, but that sometimes, they get real people killed.&lt;/p&gt;
&lt;p&gt;And it&#39;s about to get much, &lt;em&gt;much&lt;/em&gt; worse.&lt;/p&gt;
&lt;p&gt;In my day job, I work on a security team, so I have access to hard data and water cooler talk with colleagues at Google and elsewhere about agentic bug-finding models, which are behind what the security industry has coined the &quot;vulnpocalypse&quot;. For the past few weeks, I&#39;ve been repeatedly asked the same question: &quot;&lt;a rel=&quot;external&quot; href=&quot;https://www.anthropic.com/glasswing&quot;&gt;Mythos&lt;/a&gt;. Is it really &lt;em&gt;that&lt;/em&gt; bad?&quot; In a word: Yes.&lt;/p&gt;
&lt;p&gt;The point of this post isn&#39;t to adjudicate this claim, so in leiu of a serious argument, I&#39;ll just leave you with this graph &lt;a rel=&quot;external&quot; href=&quot;https://hacks.mozilla.org/2026/05/behind-the-scenes-hardening-firefox/&quot;&gt;courtesy of Firefox&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/firefox-security-bug-fixes-2026.png&quot; alt=&quot;Firefox security bug fixes by month&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Many factors will determine the long-term equillibrium of vulnerability discovery,&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; but that equillibrium will take many years to reach. Regardless of how that plays out in the long term, the medium term impact is clear: memory-unsafe&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt; open-source&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; software is not ready for high-quality bug-finding agents to be made widely available. It is expected that broad availability will happen at some point this summer,&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-5-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt; and when it does, few open source programs written in memory-unsafe languages will be safe from catastrophic exploits. Many actors will use these exploits to steal identities, or steal money, or commit other run-of-the-mill cyber crimes. But some will use these exploits to kill people.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-6-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-6&quot;&gt;[6]&lt;/a&gt;&lt;/sup&gt; I am not being hyperbolic when I say that when these agents are made available, more people will die.&lt;/p&gt;
&lt;p&gt;While memory safe languages are not a panacea, they will prevent the majority of these vulnerabilities (a &lt;a rel=&quot;external&quot; href=&quot;https://www.microsoft.com/en-us/msrc/blog/2019/07/a-proactive-approach-to-more-secure-code&quot;&gt;typical estimate&lt;/a&gt; is 70%), and they will prevent the highest-impact of these vulnerabilities.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-7-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-7&quot;&gt;[7]&lt;/a&gt;&lt;/sup&gt; &lt;strong&gt;This makes switching to memory safe languages a moral imperative.&lt;/strong&gt; Alternatives such as Carbon are being developed, and other languages with different performance characteristics like Go or Java exist. However, when it comes to memory safe languages which are &lt;em&gt;already in production&lt;/em&gt; and which impose &lt;em&gt;no overhead relative to C or C++&lt;/em&gt;,&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-8-1&quot;&gt;&lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fn-8&quot;&gt;[8]&lt;/a&gt;&lt;/sup&gt; Rust is the only option. Therefore, it is a moral imperative: Rust must succeed.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I am honored to call many people in the Rust community some of my closest friends. I have heard their stories at conferences, and over drinks, and on Zulip threads and Jitsi meetings. We have come to Rust for many different reasons (although they usually involve some form of nerd sniping). While the community has had its struggles, as any open source community does, it has always been an absolute blast – in our better moments, we have been kind to each other and written amazing software. To paraphrase Scott McNealy, we have &quot;kicked butt, had fun, and changed computing forever.&quot;&lt;/p&gt;
&lt;p&gt;I don&#39;t see why we can&#39;t keep having fun with Rust for the rest of our lives. But at the same time, we must acknowledge a hard truth: of the billions of people our software touches, only a tiny fraction know what a pointer is. To these people, it&#39;s irrelevant whether Rust is beautiful or fun. But for some of these people, if Rust doesn&#39;t succeed, they will die.&lt;/p&gt;
&lt;p&gt;My dad and sister are both doctors, and I&#39;ve always admired how they show up to work every day and face the weight of real, life-and-death consequences. The connection between their work and the lives of real people is immediate. One contrast that I&#39;ve seen between their industry and our own is how they measure what is important.&lt;/p&gt;
&lt;p&gt;Imagine that your parent had a worrisome lump on an annual physical and went to the radiologist to get it checked out. Imagine that the radiologist could choose a highly-accurate imaging technology, but instead they chose one with a high false-negative rate. You would be furious that this radiologist was jeopardizing your parent&#39;s life, and it wouldn&#39;t make you feel any better if the radiologist tried to reassure you that the technology they chose used a cleverer design, or had a better user interface, or made them feel nostalgic for when they were in med school. The radiologist&#39;s job is to treat your parent, and everything else is secondary.&lt;/p&gt;
&lt;p&gt;Whatever the reason we each got into Rust, and whatever keeps us going, we have a new responsibility that most of us never asked for: people are now depending on us for their survival. They depend on Rust being secure. But more importantly, since Rust is already the most secure systems language in existence, they depend on Rust succeeding.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I wrote this post as a celebration that we have built a language so secure that people&#39;s lives depend on projects choosing it. We should be &lt;em&gt;immensely&lt;/em&gt; proud of what we&#39;ve accomplished.&lt;/p&gt;
&lt;p&gt;But I also wrote it as a call to arms. Now more than ever, it is important that Rust succeed. In the coming months and years, we will need to make hard choices. We cannot be all things to all people. We will need to prioritize some use cases over others. We must think of progress and consensus as virtues in and of themselves. We must learn to recognize when having &lt;em&gt;a&lt;/em&gt; consensus is more important than having &lt;em&gt;the right&lt;/em&gt; consensus, and in these cases, to pick progress over stagnation. Whether it&#39;s C++ interop, or auditability, or any other un-glamorous feature which will nonetheless increase Rust adoption, we will have to hold our noses, wade into the muck, and get the work done.&lt;/p&gt;
&lt;p&gt;I want to keep having fun, and thinking deep thoughts, and writing great code. I don&#39;t want to give up what has made Rust a joy to participate in.&lt;/p&gt;
&lt;p&gt;But I also don&#39;t want people to die. If that means having a little less fun and being a little more serious, then I believe in our community&#39;s ability to rise to the occasion.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;The exact chain of events is &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Jamal_Khashoggi&quot;&gt;complicated&lt;/a&gt;, with the intelligence services of multiple countries targeting multiple people close to Khashoggi for surveillance, both before and after his murder. Publicly-available information is insufficient to prove that Khashoggi would not have been murdered had certain hacking attempts been unsuccessful. However, many other examples, such as the ransomware attack against Synnovis in 2024 and the WannaCry malware in 2017, demonstrate that hacking often leads directly or indirectly to the deaths of innocent people.&lt;/p&gt;
&lt;p&gt;I chose to open with the Khashoggi example as it makes the moral obligation that I talk about in the rest of this article very clear. However, if you want to read this article with a less emotional and more analytical mindset, replace &quot;this one person was brutally murdered thanks to a memory safety bug&quot; with &quot;in expectation, many people are injured, killed, or otherwise harmed thanks to memory safety bugs, although it&#39;s usually difficult to attribute a single incident to a particular bug.&quot; Beyond physical harm from nation state actors, estimates of the economic damage of cyber crime range from $100B to $1T annually. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-1-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;If you had asked someone in 1995, &quot;what will be the long-term social consequences of the proliferation of cellular phones,&quot; nobody would have answered, &quot;we will see a &lt;a rel=&quot;external&quot; href=&quot;https://jamanetwork.com/journals/jamanetworkopen/fullarticle/2733430&quot;&gt;rapid rise in the suicide rate&lt;/a&gt; among teen girls.&quot; Anyone who tells you they know how this will play out is wrong (or lying).&lt;/p&gt;
&lt;p&gt;To be less glib, some people have argued that the long-term effect of high-quality bug-finding agents will be to make software &lt;em&gt;more&lt;/em&gt; secure, as teams will use them to catch potential vulnerabilities before they are merged. This is a real possibility, but so is the opposite, and in any case it may take a long time reach any equillibrium. The point of this article isn&#39;t to argue that we can predict any particular outcome, but rather that we have to consider that catastrophic outcomes are sufficiently probable to be worth worrying about and preparing for. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-2-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;While memory safe languages are not free from vulnerabilities, they are generally free from &lt;em&gt;memory safety&lt;/em&gt; vulnerabilities. Non-memory safety vulnerabilities tend to permit exploits which are significantly less impactful than the exploits permitted by their memory safety-related counterparts. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-3-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;Some &lt;a rel=&quot;external&quot; href=&quot;https://red.anthropic.com/2026/mythos-preview/&quot;&gt;have suggested&lt;/a&gt; that agents are good enough at binary analysis that even closed-source software won&#39;t be safe – as long as an agent can inspect the binary, it can find vulnerabilities. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-4-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-5&quot;&gt;
&lt;p&gt;Specifically, it is expected that Mythos itself or equivalently powerful models will become available for public use. In fact, ChatGPT 5.5, which is available to the public, &lt;a rel=&quot;external&quot; href=&quot;https://www.aisi.gov.uk/blog/our-evaluation-of-openais-gpt-5-5-cyber-capabilities&quot;&gt;may already match Mythos in capability&lt;/a&gt;. While such models may have guardrails, these usually only pose a serious impediment to casual users, while serious actors are usually able to find ways to bypass them. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-5-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-6&quot;&gt;
&lt;p&gt;More accurately, they will use these exploits to steal information which will allow them to kill people. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-6-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-7&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://security.googleblog.com/2022/12/memory-safe-languages-in-android-13.html&quot;&gt;Per Android&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Memory safety vulnerabilities disproportionately represent our most severe vulnerabilities. In 2022, despite only representing 36% of vulnerabilities in the security bulletin, memory-safety vulnerabilities accounted for 86% of our critical severity security vulnerabilities, our highest rating, and 89% of our &lt;a rel=&quot;external&quot; href=&quot;https://source.android.com/docs/security/overview/updates-resources#local-vs-remote&quot;&gt;remotely exploitable&lt;/a&gt; vulnerabilities. Over the past few years, memory safety vulnerabilities have accounted for &lt;a rel=&quot;external&quot; href=&quot;https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=1190662839&quot;&gt;78% of confirmed exploited “in-the-wild”&lt;/a&gt; vulnerabilities on Android devices. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-7-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-8&quot;&gt;
&lt;p&gt;...which is a non-negotiable for many teams when switching languages. &lt;a href=&quot;https://joshlf.com/posts/memory-safety-life-and-death/#fr-8-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>How to Run When You&#39;re Not Being Chased</title>
    <published>2026-05-18T00:00:00+00:00</published>
    
    <updated>2026-05-18T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/how-to-run/"/>
    <id>https://joshlf.com/posts/how-to-run/</id>
    
      
    <category term="Mental Health"/>
      
    <category term="Career"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/how-to-run/">&lt;p&gt;Have you heard this one before?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I obviously don&#39;t &lt;em&gt;like&lt;/em&gt; being anxious, but it&#39;s how I drive myself. If I (meditated / went to therapy / got on anti-anxiety meds / etc), I would lose my edge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#39;ve had multiple close friends use some form of this argument to justify why they avoid working on their mental health: that their demons (anxiety or anything else) fuel their success, and that they couldn&#39;t succeed without them. Even if we grant that &quot;keeping your edge&quot; is a worthwhile goal, in my experience this argument doesn&#39;t hold up &lt;em&gt;factually&lt;/em&gt;. The reality is instead:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In childhood, your demons &lt;em&gt;did&lt;/em&gt; shape your ability to be successful, but that&#39;s done. As an adult:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;They&#39;re not helping anymore.&lt;/li&gt;
&lt;li&gt;They&#39;re actively holding you back.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I once heard someone articulate the argument succintly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Imagine that you had schizophrena, and that you frequently hallucinated being chased by monsters. As a result, you spent a lot of time running away from these monsters. What would happen after you got treatment, stopped hallucinating the monsters, and stopped needing to run? &lt;strong&gt;You&#39;d still be in great cardio shape.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The problem with the &quot;my demons give me my edge&quot; perspective is that it fails to distinguish between &lt;em&gt;developing&lt;/em&gt; skills and &lt;em&gt;using&lt;/em&gt; those skills. If, as a child, your demons made you feel like you had no choice but to succeed, then you spent your childhood pushing yourself, becoming comfortable with hard work and stress, and generally cultivating habits, traits, and skills that allow you to succeed as an adult. But now that you &lt;em&gt;are&lt;/em&gt; an adult, the development is done. Your success is predicated on your &lt;em&gt;having&lt;/em&gt; certain skills, not on the factors that led you to develop those skills in the first place.&lt;/p&gt;
&lt;p&gt;What&#39;s more, your demons are likely holding you back by driving you to waste your energy on unimportant things.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The more severe the mental illness is, the more people believe [the false projections of] their mind.&lt;/p&gt;
&lt;p&gt;– &lt;a rel=&quot;external&quot; href=&quot;https://www.youtube.com/watch?v=gOUwoU7WddM&amp;amp;t=846s&quot;&gt;Dr. Alok Kanojia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mental illness impairs our ability to rationally assess what is required in a given situation. To expand on the hallucination example, while it&#39;s useful to be in great running shape, it&#39;s actively &lt;em&gt;harmful&lt;/em&gt; to feel driven to run all the time. If you&#39;re always running, even when it&#39;s not necessary, then you&#39;ll always be exhausted. On the occasions when it really &lt;em&gt;is&lt;/em&gt; necessary, your energy will already be spent. What you really want is to have the judgment to know when running is justified, and otherwise to conserve your energy. To paraphrase the &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Serenity_Prayer&quot;&gt;Serenity Prayer&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Give me the calm to rest when I can, the fitness to run when I must, and the mental health to be able to tell the difference.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So if you find yourself avoiding working on your mental health because you&#39;re worried you&#39;ll sabatoge your own success, consider that &lt;em&gt;not&lt;/em&gt; working on your mental health may be the real act of sabotage.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>How to Brush Your Teeth at Work</title>
    <published>2026-04-14T00:00:00+00:00</published>
    
    <updated>2026-04-14T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/brush-your-teeth/"/>
    <id>https://joshlf.com/posts/brush-your-teeth/</id>
    
      
    <category term="Career"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/brush-your-teeth/">&lt;p&gt;When you were a kid, you had to learn to brush your teeth. It may be easy now, but at one point it was a &lt;em&gt;skill&lt;/em&gt;. You would get toothpaste everywhere, and your mom or dad would have to remind you to brush every tooth.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;You also probably &lt;em&gt;hated&lt;/em&gt; doing it. You&#39;d conveniently &quot;forget&quot; unless reminded, and then make excuses for why you hadn&#39;t done it yet, or didn&#39;t actually need to do it tonight in particular, or that actually your teeth were better than everybody else&#39;s teeth and thus brushing was unnecessary and beneath you.&lt;/p&gt;
&lt;p&gt;The problem, of course, is that if you don&#39;t brush your teeth, your teeth will fall out of your head. At first, your parents were responsible for keeping your teeth in your head. Eventually, as you got better at brushing your teeth and got used to it as an inevitable, minor daily annoyance, you stopped thinking about it.&lt;/p&gt;
&lt;p&gt;Now, as an adult, imagine if someone told you that brushing their teeth was too much of a hassle to be worth doing – that it would take too much effort to get good at and that, besides, it&#39;s ridiculous that we &lt;em&gt;need&lt;/em&gt; to brush our teeth. Shouldn&#39;t they just be healthy all on their own? Why haven&#39;t we evolved that? You would rightfully think that they were shooting themselves in the foot over a very minor inconveience. Surely a few minutes of mindless chore per day is worth the upside, right?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is the pitch that someone gave to me a few years ago, and it changed my relationship with my career.&lt;/p&gt;
&lt;p&gt;At the time, I was feeling what is, I think, a very common feeling: That pointless bureaucracy was making my job a slog, that I was being held back from doing good, interesting work, being asked to make it &lt;em&gt;worse&lt;/em&gt; in order to make it legible to a bureaucracy that didn&#39;t understand what I was doing, didn&#39;t understand why the way I was doing it was actually &lt;em&gt;better&lt;/em&gt;, didn&#39;t value quality, didn&#39;t reward the right behaviors, and generally made us all do paperwork that few people would ever read and that would have no meaningful effect on what we actually &lt;em&gt;produced&lt;/em&gt;. It all felt so pointless and unfair. Why can&#39;t we just let people do good work and get on with their lives?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As an aside, there are actually good reasons for all of this that tend to be harder to appreciate when you&#39;re earlier in your career. A mentor once told me: &quot;Organizational dysfunction is never completely avoidable. Sure, it might be possible to do things better, but it&#39;s always downstream of a genuinely hard coordination problem. The fact that all these different people and groups, with their competing and misaligned interests, can collaborate &lt;em&gt;at all&lt;/em&gt; is a miracle of game theory. The fact that it isn&#39;t &lt;em&gt;perfect&lt;/em&gt; should be the least surprising thing in the world.&quot; If this is interesting to you, read &lt;em&gt;The Evolution of Cooperation&lt;/em&gt; by Robert Axelrod. It will change how you think about human organizations.&lt;/p&gt;
&lt;p&gt;But let&#39;s ignore that and assume, for the sake of argument, that bureaucracy really does exist for no good reason at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While this feeling is nearly universal at some point in a career, consider the analogy to brushing your teeth. No matter how stilly it may feel, feeling that it&#39;s silly isn&#39;t going to magically make us evolve past the need to brush our teeth. You have two options: You can either do what most of us do – accept a very minor inconvenience and get the benefits of having teeth – or you can avoid a very minor inconvenience, but at the cost of feeling constantly angry at an unfair world &lt;em&gt;and&lt;/em&gt; not having teeth.&lt;/p&gt;
&lt;p&gt;Think of the bureaucratic bullshit as teeth-brushing. The child perspective entails constantly dreading the impending request to brush, clumsily brushing and getting toothpaste all over your face, and having poor dental health from all of the times you managed to avoid doing it. Imagine, instead, if you got &lt;em&gt;good&lt;/em&gt; at navigating the bureaucracy. It would take some up-front investment to develop the skill, but once you did, you could put it all on auto-pilot. Just like brushing your teeth, as you got good at it, it would take less mental effort. It would feel less like a big, looming obligation and more like just another small cost of doing business that you get out of the way so you can move on to the interesting work you really care about doing.&lt;/p&gt;
&lt;p&gt;Beyond the mental peace, you would also have more control over your career. As you learned how to speak bureaucrat-ese, you would be more effective at demonstrating – in a language that your manager&#39;s manager&#39;s manager can understand – that your work is important and should continue to be funded. You would get to pick more interesting projects because you would know how to convince your leadership that they were worth investing in. You would get less oversight and micromanagement because you would be trusted to use your judgment about what to work on.&lt;/p&gt;
&lt;p&gt;The next time you encounter somebody with a really cool job and think, &quot;fuck, what did they do to get a job that cool,&quot; consider how good they are at brushing their teeth. Maybe a lot of what separates you from them is just a few minutes per day and some toothpaste.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Force Your Macro&#39;s Callers to Write Unsafe</title>
    <published>2025-04-05T00:00:00+00:00</published>
    
    <updated>2025-04-05T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/unsafe-macros/"/>
    <id>https://joshlf.com/posts/unsafe-macros/</id>
    
      
    <category term="Rust"/>
      
    <category term="Unsafe"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/unsafe-macros/">&lt;p&gt;Imagine you&#39;re writing this macro:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// Types that can be frobnicated.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// # Safety&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// It must be sound to frobnicate `Self`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Frobnicatable&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// Implements `Frobnicatable` for `$t`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// # Safety&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// `$t` must satisfy the safety invariant of `Frobnicatable`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;macro_rules! unsafe_impl_frobnicatable&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    (&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ty&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // SAFETY: The caller has promised that `$t` satisfies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // the safety invariant of `Frobnicatable`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        unsafe impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Frobnicatable&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for $&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;&lt;em&gt;Of course, you&#39;d never actually write a macro to emit code this simple, but
it&#39;s a meant as a stand-in for macros that emit more complex code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A caller might write this:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;// SAFETY: It is sound to frobnicate `Foo`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;unsafe_impl_frobnicatable!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But imagine that your caller wants to practice good safety hygeine, and they use
&lt;a rel=&quot;external&quot; href=&quot;https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks&quot;&gt;&lt;code&gt;#![deny(clippy::undocumented_unsafe_blocks)]&lt;/code&gt;&lt;/a&gt;.
Because Clippy doesn&#39;t realize that the macro call requires a safety comment, it
won&#39;t complain if your caller forgets their safety comment:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;#&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;[&lt;/span&gt;&lt;span&gt;deny&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span&gt;clippy&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span&gt;undocumented_unsafe_blocks&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;// Clippy: 🙈&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;unsafe_impl_frobnicatable!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, you should write your macro so that it &lt;em&gt;invokes&lt;/em&gt; unsafe code. This also
means that we can drop the &lt;code&gt;unsafe_&lt;/code&gt; prefix from the macro&#39;s name – it was just
there to make it less likely for your callers to miss the safety requirement,
but that&#39;s no longer a concern. &lt;em&gt;Also, make sure to have the macro&#39;s right-hand
side contain a block – ie, &lt;code&gt;{{ ... }}&lt;/code&gt; – see the appendix for an explanation of
why this is important.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// Implements `Frobnicatable` for `$t`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// # Safety&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// `$t` must satisfy the safety invariant of `Frobnicatable`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;macro_rules! impl_frobnicatable&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    (&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ty&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // Force caller to wrap in an `unsafe { ... }` block.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        $crate::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;__unsafe&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // SAFETY: The caller has promised that `$t` satisfies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // the safety invariant of `Frobnicatable`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        unsafe impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Frobnicatable&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for $&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {}&lt;/span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;#[&lt;/span&gt;&lt;span&gt;doc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span&gt;hidden&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub const unsafe fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; __unsafe&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;() {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, even when Clippy isn&#39;t used, Rust will force your caller to put the macro
invocation in an &lt;code&gt;unsafe&lt;/code&gt; block. In other words, this will no longer compile:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;// SAFETY: It is sound to frobnicate `Foo`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;impl_frobnicatable!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fix this, your caller must wrap the invocation in an &lt;code&gt;unsafe&lt;/code&gt; block, for
example:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;// SAFETY: It is sound to frobnicate `Foo`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; _&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; ()&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; = unsafe&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; impl_frobnicatable!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;) };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now Clippy &lt;em&gt;will&lt;/em&gt; catch a missing safety comment since your caller is using
a normal &lt;code&gt;unsafe&lt;/code&gt; block.&lt;/p&gt;
&lt;h2 id=&quot;appendix-macro-expansion&quot;&gt;Appendix: Macro expansion&lt;/h2&gt;
&lt;p&gt;Note one subtlety: You&#39;re going to want to have your macro emit a block (ie, use
&lt;code&gt;(...) =&amp;gt; {{ ... }}&lt;/code&gt; rather than &lt;code&gt;(...) =&amp;gt; { ... }&lt;/code&gt;). You&#39;re now requiring your
callers to call your macro in expression or statement position (ie, inside of a
block) rather than in item position (ie, at the top-level, outside of a block).
Thus, it has to play nicely with code before and after it in the same block.
Expanding to a self-contained block is a good way of ensuring that this will
happen.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Introducing Mundane, a New Cryptography Library for Rust</title>
    <published>2018-11-06T00:00:00+00:00</published>
    
    <updated>2018-11-06T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/introducing-mundane/"/>
    <id>https://joshlf.com/posts/introducing-mundane/</id>
    
      
    <category term="Rust"/>
      
    <category term="Cryptography"/>
      
    <category term="Mundane"/>
      
    <category term="BoringSSL"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/introducing-mundane/">&lt;p&gt;Mundane, meet the world. The world, meet Mundane.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/rustdoc/mundane&quot;&gt;Mundane&lt;/a&gt; is a cryptography library written in Rust and backed
by BoringSSL. It aims to be difficult to misuse, ergonomic, and performant (in
that order). It was originally created to serve the cryptography needs of
Fuchsia, but we&#39;ve decided to split it off as a general-purpose crate.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;why-mundane&quot;&gt;Why Mundane?&lt;/h2&gt;
&lt;p&gt;Mundane&#39;s raison d&#39;être is to provide an API which is difficult to misuse.
Experience shows that one of the most common failure modes of cryptography is
incorrect implementation, and often, that failure occurs at the boundary between
an application and a cryptography library.&lt;/p&gt;
&lt;p&gt;Given this experience, Mundane takes the approach of giving the programmer the
fewest degrees of freedom possible. Doing the right thing should be easy and
feel natural. Doing the wrong thing should feel difficult and ideally be
entirely impossible.&lt;/p&gt;
&lt;p&gt;Rust is the perfect language for a library with this design philosophy. Its
expressive and strict type system allows us to ensure that, across a wide array
of correctness properties, an incorrect program will not compile.&lt;/p&gt;
&lt;p&gt;Consider, for example, the humble signature. A signature consists of two
components: a hash of some input data, and a digital signature of that hash.
Mundane&#39;s &lt;code&gt;Signature&lt;/code&gt; trait looks like this:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// A cryptographic signature generated by a private key.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Signature&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Sealed&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; +&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Sized&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// The private key type used to generate this signature.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    type&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; PrivateKey&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; PrivateKey&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// Sign a message.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    ///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// The input to this function is always a message, never a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// digest. If a signature scheme calls for hashing a message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// and signing the hash digest, `sign` is responsible for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// both hashing and signing.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; sign&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;PrivateKey&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; message&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Result&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Error&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// Verify a signature.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    ///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// The input to this function is always a message, never a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// digest. If a signature scheme calls for hashing a message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// and signing the hash digest, `verify` is responsible for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    /// both hashing and verifying the digest.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; verify&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; key&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;PrivateKey&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; as&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; PrivateKey&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Public&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        message&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right away, we see an example of a mistake which is impossible with Mundane&#39;s
API: It&#39;s impossible to incorrectly combine hashing and signing because they&#39;re
not exposed as separate operations. Instead, both on the signing path and the
verification path, hashing is handled by the API automatically.&lt;/p&gt;
&lt;p&gt;This allows us to unlock more powerful and subtle correctness properties. For
example, since we are responsible for hashing, not only can we ensure that
hashing is done properly, we can also ensure that a secure hash function is
used. Consider, for example, the &lt;code&gt;EcdsaSignature&lt;/code&gt;, which implements &lt;code&gt;Signature&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;/// A DER-encoded ECDSA signature.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;pub struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; EcdsaSignature&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; PCurve&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; H&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Hasher&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; +&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; EcdsaHash&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt; {&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; ...&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ECDSA signature algorithm can operate over any elliptic curve (the &lt;code&gt;C&lt;/code&gt; type
parameter) and any hash function (the &lt;code&gt;H&lt;/code&gt; type parameter). If we look closely,
we see that &lt;code&gt;H&lt;/code&gt; is not just a &lt;code&gt;Hasher&lt;/code&gt; (the trait implemented by hash
functions), but is, in addition, an &lt;code&gt;EcdsaHash&amp;lt;C&amp;gt;&lt;/code&gt;. This trait is only
implemented for valid hash/curve pairs. Some hashes are large enough that, in
order to sign them using ECDSA, they would need to be truncated. For example,
using a SHA-512 hash with ECDSA over a P-256 curve would require truncating the
hash before signing, reducing the security of the hash.&lt;/p&gt;
&lt;p&gt;Thus, we only implement &lt;code&gt;EcdsaHash&lt;/code&gt; for hash/curve pairs where no truncation is
necessary. Hash/curve pairs which require truncation aren&#39;t supported, and code
which tries to use them won&#39;t compile.&lt;/p&gt;
&lt;p&gt;For more examples, see the &lt;a href=&quot;/rustdoc/mundane&quot;&gt;documentation&lt;/a&gt;. For an in-depth
discussion of our design philosophy, see the &lt;a rel=&quot;external&quot; href=&quot;https://github.com/google/mundane/blob/master/DESIGN.md&quot;&gt;design
doc&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;
&lt;p&gt;Of course, there&#39;s more to cryptography than the API. Mundane is based on the
well-vetted and actively-developed BoringSSL. Mundane does not provide any
implementations itself, and does not currently have any plans to do so in the
future.&lt;/p&gt;
&lt;p&gt;A common problem with relying on native libraries from Rust crates is
compatibility - while Rust and Cargo are able to compile multiple crate versions
into a single binary, C is not so flexible. In order to avoid this problem,
Mundane vendors a copy of the BoringSSL source, which is shipped along with the
crate on crates.io. It uses symbol prefixing to ensure that the version of
BoringSSL compiled for a particular version of Mundane will not conflict with
either a) the version of BoringSSL compiled for a different version of Mundane
or, b) any version of BoringSSL compiled for any other Rust crate. Because the
source is shipped with Mundane, users do not need to have BoringSSL installed
when building.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The approach we use to prefix BoringSSL&#39;s symbols is complex, and makes
compilations take longer than we&#39;d like. If you&#39;re interested in helping improve
the situation, please get in touch!&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-not-other-cryptography-crate&quot;&gt;Why not &amp;lt;other cryptography crate&amp;gt;?&lt;/h2&gt;
&lt;p&gt;There are a host of fantastic cryptography crates in Rust, each with its own
focus and design tradeoffs. Mundane has its focus - to be misuse-resistant at
all costs - and it makes design tradeoffs with that focus in mind. If that&#39;s not
what you&#39;re looking for, then one of the other cryptography crates might be a
better fit for your use case.&lt;/p&gt;
&lt;p&gt;Additionally, as the primary Rust cryptography crate used by the Fuchsia OS,
Mundane has a very high bar for security and active maintenance. While Rust is
our ideal language for almost everything, it still has some shortcomings when it
comes to writing cryptography code, such as the lack of guaranteed constant-time
operations. Moreover, to be blunt, we don&#39;t trust ourselves to implement
cryptography correctly. That&#39;s why we rely exclusively on BoringSSL, which is
developed full-time by a team of professional cryptographers, and which provides
strong guarantees about fixing vulnerabilities quickly if they arise.&lt;/p&gt;
&lt;h2 id=&quot;how-can-i-help&quot;&gt;How can I help?&lt;/h2&gt;
&lt;p&gt;Use Mundane! Use it for high-level applications and low level applications. Use
it in all different environments. The more users we have, the more feedback
we&#39;ll get, and the better Mundane will be. Tell us what you like, and what you
don&#39;t. Tell us what features you want to see in the future. Submit
&lt;a rel=&quot;external&quot; href=&quot;https://github.com/google/mundane/issues&quot;&gt;issues&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Rust Has Higher Kinded Types Already... Sort Of</title>
    <published>2018-10-18T00:00:00+00:00</published>
    
    <updated>2018-10-18T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/rust-higher-kinded-types-already/"/>
    <id>https://joshlf.com/posts/rust-higher-kinded-types-already/</id>
    
      
    <category term="Rust"/>
      
    <category term="Types"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/rust-higher-kinded-types-already/">&lt;h2 id=&quot;refresher&quot;&gt;Refresher&lt;/h2&gt;
&lt;p&gt;First, a very quick refresher.&lt;/p&gt;
&lt;p&gt;In Rust, a type which takes type parameters (&lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;Vec&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;HashMap&amp;lt;K, V&amp;gt;&lt;/code&gt;,
etc) is only a valid type when all type parameters are specified. In other
words, &lt;code&gt;Rc&lt;/code&gt;, &lt;code&gt;Vec&lt;/code&gt;, and &lt;code&gt;HashMap&amp;lt;K&amp;gt;&lt;/code&gt; are not types. You can&#39;t have a variable of
type &lt;code&gt;Rc&lt;/code&gt;. You can&#39;t pass &lt;code&gt;Rc&lt;/code&gt; as a parameter to other types.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;The ability to have such things be actual types is a feature called &lt;em&gt;higher
kinded types&lt;/em&gt; (HKT). It&#39;s primarily useful when combined with traits which also
take type parameters. Consider, for example, a hypothetical trait to abstract
over different kinds of reference-counted pointers.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Clone&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; +&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can easily implement this for &lt;code&gt;Rc&lt;/code&gt; and &lt;code&gt;Arc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Rc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Arc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, with HKTs, &lt;code&gt;RcPtr&lt;/code&gt; (as opposed to &lt;code&gt;RcPtr&amp;lt;T&amp;gt;&lt;/code&gt;) would be a valid trait,
and &lt;code&gt;Rc&lt;/code&gt; and &lt;code&gt;Arc&lt;/code&gt; would implement it (as opposed to &lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This would allow you to do things like:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; TreeNode&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; P&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    val&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    right&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; P&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;TreeNode&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; P&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    left&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; P&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;TreeNode&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; P&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a tree data structure where the caller gets to decide whether it&#39;s
thread-safe or not. There are many applications which would benefit greatly from
allowing the caller to specify some property such as thread safety, caching
behavior, etc - all things which require HKTs in order to leave type parameters
unbound until later than is allowed in normal Rust today (I say &quot;normal&quot;
because, well, read the next section).&lt;/p&gt;
&lt;h2 id=&quot;hkts-in-rust-today&quot;&gt;HKTs in Rust Today&lt;/h2&gt;
&lt;p&gt;One way to view the limitation that prevents us from writing this code is that,
a) when declaring a trait bound, all type parameters must be bound (i.e., &lt;code&gt;P: RcPtr&lt;/code&gt; is not a valid trait bound since &lt;code&gt;RcPtr&lt;/code&gt; takes a type parameter) and, b)
when declaring a type, all type parameters must be bound (i.e., &lt;code&gt;Rc&lt;/code&gt; and &lt;code&gt;Arc&lt;/code&gt;
aren&#39;t types; &lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt; are).&lt;/p&gt;
&lt;p&gt;However, it&#39;s not quite true that there&#39;s no way to define a trait which allows
some type parameters to remain unbound, or that there&#39;s no way to implement
those traits with types which also leave some type parameters unbound. Consider,
for example, the following function from the standard library&#39;s &lt;code&gt;Iterator&lt;/code&gt;
trait:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Iterator&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; sum&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Sum&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; S&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even once a type has implemented the &lt;code&gt;Iterator&lt;/code&gt; trait, the &lt;code&gt;S&lt;/code&gt; type parameter on
&lt;code&gt;sum&lt;/code&gt; is still unbound - it&#39;s only bound once the method is called. This implies
a general pattern - if you want to allow specifying a trait bound while leaving
type parameters unbound, just move them into the methods on that trait. Let&#39;s
give it a try:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; clone&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If this trait gives you an uneasy feeling, you&#39;ve got the right intuition.
Normally, with a trait with a type parameter like:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; clone&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You declare variables like:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; = ...&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, whenever you operate on &lt;code&gt;foo&lt;/code&gt;, the compiler guarantees that the correct
type &lt;code&gt;T&lt;/code&gt; is used. This is important, or else you&#39;d be able to operate on the
same variable as different types at different points in the program:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; usize&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; 0&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; &amp;quot;hello there&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;])[&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; +=&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; 1&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, the fact that Rust tracks the type of variables is what allows
us to have memory safety! So if the type parameter to &lt;code&gt;RcPtr&lt;/code&gt; is moved from the
trait itself into each of the methods, then you could do something like:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; = ...&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;deref&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; bar&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; foo&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;]&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, you could violate memory safety. No bueno. I guess we&#39;re out of
luck...&lt;/p&gt;
&lt;p&gt;Although... There is a giant, hairy, awful, scary escape hatch in the language,
so what if we just...&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    unsafe fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; clone&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    unsafe fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s better :)&lt;/p&gt;
&lt;p&gt;Of course, using &lt;code&gt;unsafe&lt;/code&gt; means that you&#39;re opting into manually verifying
certain properties. So what properties does the programmer pinky-swear to uphold
here? Essentially, it becomes the programmer&#39;s responsibility to track the types
of variables and only ever access them consistently. In other words, for a given
instance of a variable, it must only ever be accessed with the same &lt;code&gt;T&lt;/code&gt;
parameter.&lt;/p&gt;
&lt;p&gt;Luckily, Rust is pretty good at encapsulation, so we can just encapsulate this
in a safe type that uses unsafe under the hood, and guarantees to always use the
same &lt;code&gt;T&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcWrapper&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    rc&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; R&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    _marker&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; PhantomData&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcWrapper&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; new&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        RcWrapper&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            rc&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; R&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            _marker&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; PhantomData&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Deref&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcWrapper&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    type&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Target&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        unsafe&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;rc&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;() }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given an &lt;code&gt;R: RcPtr&lt;/code&gt; and a &lt;code&gt;T&lt;/code&gt;, instead of writing &lt;code&gt;R&amp;lt;T&amp;gt;&lt;/code&gt; as we would if Rust
supported HKT natively, we write &lt;code&gt;RcWrapper&amp;lt;R, T&amp;gt;&lt;/code&gt;. We can then treat the
&lt;code&gt;RcWrapper&amp;lt;R, T&amp;gt;&lt;/code&gt; just as we would &lt;code&gt;R&amp;lt;T&amp;gt;&lt;/code&gt; if we had native HKT - we can pass it
around, call methods on it, clone it, etc.&lt;/p&gt;
&lt;p&gt;OK, so we can define the trait, and we can even make it safe to use. But how on
earth could we implement the trait? What would such an implementation look like?&lt;/p&gt;
&lt;p&gt;Awful, that&#39;s what. While one of the benefits of giving variables types is that
you can guarantee that you always operate on them as the proper type, another
benefit is that you always know what size they are. What size is something whose
type isn&#39;t known until you call methods on it? God only knows...&lt;/p&gt;
&lt;p&gt;And when only God knows something, you&#39;ve got no choice but to figure it out at
runtime, and stick it on the heap.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; SingleThreadedRc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // Actually *mut Rc&amp;lt;T&amp;gt;, but we don&amp;#39;t know&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // what T is until runtime...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: *mut&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; SingleThreadedRc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // Dear SingleThreadedRc, I pinky-swear that&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // you&amp;#39;re actually holding a pointer to an Rc&amp;lt;T&amp;gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;    // I swear on my mother&amp;#39;s grave.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    unsafe fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; inner&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Rc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        &amp;amp;*&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span&gt;inner &lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;as *const&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;unsafe impl&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; RcPtr&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; SingleThreadedRc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    unsafe fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; clone&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // Get access to the Rc&amp;lt;T&amp;gt; we knew we had &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        // inside of us deep down all along...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Rc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; new_inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Rc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; new_inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Box&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;new_inner&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        SingleThreadedRc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Box&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;into_raw&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;new_inner&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; as *mut&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; (),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    unsafe fn&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;        let&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Rc&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; self&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        inner&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;deref&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Does anybody have any Purell?&lt;/p&gt;
&lt;p&gt;But it works. You can see a full example including usage
&lt;a rel=&quot;external&quot; href=&quot;https://play.rust-lang.org/?version=stable&amp;amp;mode=debug&amp;amp;edition=2015&amp;amp;gist=d280c71819f6d698e05ab3ec448f2394&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;To recap, here&#39;s the general pattern. You would like a trait, &lt;code&gt;MyTrait&amp;lt;T&amp;gt;&lt;/code&gt;, to
be higher-kinded, but we don&#39;t support that in Rust right now. Instead, you
create a trait, &lt;code&gt;MyTrait&lt;/code&gt;, which takes no type parameters, but each of its
methods take a type parameter, &lt;code&gt;T&lt;/code&gt;. Then, if you have an &lt;code&gt;M: MyTrait&lt;/code&gt;, instead
of doing &lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt; as you normally would, you create a concrete wrapper type,
&lt;code&gt;MyTraitWrapper&amp;lt;M: MyTrait, T&amp;gt;&lt;/code&gt;. &lt;code&gt;M&amp;lt;T&amp;gt;&lt;/code&gt; is then written as &lt;code&gt;MyTraitWrapper&amp;lt;M, T&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course, the code presented here is far from pretty or optimal. One obvious
drawback is the heap allocation. If you could guarantee an upper bound on the
size of the internal type (e.g., if you knew an upper bound on the size of
&lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt; for all &lt;code&gt;T&lt;/code&gt;), you could stack- instead of heap-allocate.&lt;/p&gt;
&lt;p&gt;This also doesn&#39;t cover everything you might want HKT for. For example, how do
you emulate the following trait, where you&#39;d like to be able to do &lt;code&gt;M: MyTrait&lt;/code&gt;
and then, later, &lt;code&gt;M::&amp;lt;T&amp;gt;::MyType&lt;/code&gt;?&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;trait&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; MyTrait&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;    type&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; MyType&lt;/span&gt;&lt;span class=&quot;z-9 z-b&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; Clone&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-5&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;m pretty sure it&#39;s possible, but I haven&#39;t actually gotten it working in code
yet. In the interest of keeping this post short (and also reclaiming some of my
free time), I&#39;ve decided to leave it an exercise to readers to either get it
working, or argue that it can&#39;t be done (and thus that the approach I&#39;ve
proposed here falls short of full HKT).&lt;/p&gt;
&lt;p&gt;Finally, in fairness, calling this &quot;HKT&quot; is a bit of a stretch. It&#39;s not a
general-purpose mechanism - you have to manually implement it for every trait
and every type - and it doesn&#39;t provide the same soundness guarantees that a
language feature would. But, for any given application that needs a particular
trait to be HKT-ified, it gets the job done.&lt;/p&gt;
&lt;p&gt;Rust has HKT right now, but only the sinners can use it.&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: In Review</title>
    <published>2016-09-18T00:00:00+00:00</published>
    
    <updated>2016-09-18T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-in-review/"/>
    <id>https://joshlf.com/posts/soylent-in-review/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-in-review/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Just over two years ago, I started what I thought was going to be, as the note above suggests, a month-long experiment with &lt;a rel=&quot;external&quot; href=&quot;https://www.soylent.com&quot;&gt;Soylent&lt;/a&gt; (if you don&#39;t know what Soylent is, read the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt;). At the time, I was considering Soylent as a potential full or partial replacement for normal food, but since I was about to head into a school year with a full meal plan, I wasn&#39;t going to be able to start right away. So I wanted to try it out for a month to see if it was something I&#39;d want to do full-time after graduation, and I decided to write this blog series on it - one post per day - to track my progress and let others benefit from my experience.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;Not only did I not end up switching to Soylent, I didn&#39;t even finish the blog series (or, for that matter, the experiment itself). And for the past two years, I&#39;ve continually putting off writing a final post. Better late than never, I guess?&lt;/p&gt;
&lt;p&gt;In this post, I&#39;m going to explain my main takeaways from the experiment, and a number of tips, tricks, and insights that I learned along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE (09/18/2016): I should note that the version of Soylent I used for this experiment was 1.0. Some results may vary with other versions.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;you-need-to-need-it&quot;&gt;You Need to Need It&lt;/h2&gt;
&lt;p&gt;By far the most important lesson that I learned is that Soylent would never work for me unless I need it to. As I described in the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt;, my reason for considering Soylent was convenience - I&#39;m lazy when it comes to shopping, cooking, and cleaning, and Soylent reduces the burden of all of these. But the timing of the experiment meant that I never needed the convenience. For the first two weeks of the experiment, I was on summer break, and I had all the time in the world. Cooking was, if anything, a way to fill the time. After that, I was at school, and on a full meal plan. Instead of shopping, cooking, and cleaning, I simply walked into a dining hall, ate already-prepared food, and left my plates to be cleaned by somebody else.&lt;/p&gt;
&lt;p&gt;For me, Soylent would only work if the alternative was time-consuming or annoying. To be fair, though, I never got to try, so I can only speculate. Maybe even then it wouldn&#39;t be enough.&lt;/p&gt;
&lt;p&gt;But that begs the question - why didn&#39;t I enjoy Soylent in its own right?&lt;/p&gt;
&lt;h2 id=&quot;soylent-is-medicine&quot;&gt;Soylent is Medicine&lt;/h2&gt;
&lt;p&gt;After you get used to it, Soylent doesn&#39;t taste actively bad, but it certainly isn&#39;t appealing in its own right either. I found myself craving real food not because I was hungry - Soylent certainly made me full - but for the taste and the texture. As I described in my &lt;a href=&quot;/posts/soylent-day-3/&quot;&gt;third post&lt;/a&gt;, &quot;I still feel full and satisfied after I drink it, but I have to will myself to drink it knowing that that will be the outcome; I don&#39;t find myself actively wanting Soylent itself.&quot; In short, you have to treat it like medicine - you eat it because you need to, not because you want to.&lt;/p&gt;
&lt;p&gt;Again, you need to need it. If it&#39;s your only option, or if it has upsides that normal food doesn&#39;t, then it&#39;s worth it. I also know that a lot of people only use Soylent for one meal in the day - for example, a quick breakfast if they&#39;re rushing to get to work in the morning. It makes sense to me that that might work better since you can still enjoy lunch and dinner, but I haven&#39;t tried it myself, so I can&#39;t say for sure.&lt;/p&gt;
&lt;h2 id=&quot;tips-tricks-and-insights&quot;&gt;Tips, Tricks, and Insights&lt;/h2&gt;
&lt;p&gt;Even though I didn&#39;t see the experiment through to its conclusion, I did eat it for more than two weeks, and picked a few tips, tricks, and insights along the way.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The taste of Soylent is mildly sweet, and it was a bit off-putting to me at first. The texture is very thick, and I was not used to drinking liquid that dense. It takes a few days to become fully comfortable with drinking it, so be patient.&lt;/li&gt;
&lt;li&gt;Drink &lt;em&gt;slowly&lt;/em&gt;. I can&#39;t emphasize this enough. Each glass of Soylent has the caloric content of a full meal. Imagine how full you would feel if you scarfed down a cheeseburger in thirty seconds. Soylent may be a liquid, but if you drink it quickly, you will feel just as full. I made this mistake the first day, and I felt queasy afterwards.&lt;/li&gt;
&lt;li&gt;Not only should you drink slowly when sitting down to a meal, but it may be a good idea to sip continuously throughout the day instead of treating each drink as a single meal. I found myself naturally falling into this rythm, and I think the reason is that, being a liquid, Soylent doesn&#39;t have to be broken down by stomach acids before its nutrients get absorbed into the blood stream. Thus, in order to get the continual feeling of having energy that you get from eating a meal of solid food, just drink small quantities of Soylent continuously.&lt;/li&gt;
&lt;li&gt;If you use Soylent for a large part of your diet, and you adopt the approach of drinking small amounts continuously, you may find that you become accustomed to eating small quantities, and that eating a large quantity of food (such as at a restaurant) makes you feel much more full than it normally would.&lt;/li&gt;
&lt;li&gt;A common problem that people report when first trying Soylent is flatulence. &quot;Something something gut biome,&quot; I guess; I&#39;m not a biologist. But it&#39;s something people experience. I never had it that badly, but one thing I can say is that drinking Soylent quickly makes it worse - again, always drink slowly.&lt;/li&gt;
&lt;li&gt;Always drink cool or cold Soylent, and never water it down. To this day, my friends cite the most entertaining post in this series as the &lt;a href=&quot;/posts/soylent-day-15/&quot;&gt;day 15 post&lt;/a&gt; in which I describe the horror of drinking warm, watered-down Soylent. &quot;For the love of all that is good and holy, do not water down your Soylent... I don&#39;t know what it is about watered down or warm Soylent, but just... just don&#39;t. Dear god, just don&#39;t.&quot; I felt really queasy - on the verge of throwing up - for the better part of the morning. However, I had cold, not-watered-down Soylent for lunch, and it made my stomach feel much better, which confirmed that the temperature and dilution were the problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well, that&#39;s all I&#39;ve got! It feels like a relief to finally get this thing written - I&#39;ve seriously been putting it off for two years. Hopefully this dinky blog series on a dinky personal website will find someone in the future with questions, and give them some answers. It will be my little piece of &quot;Wisdom of the Ancients.&quot;&lt;/p&gt;
&lt;img alt=&quot;Wisdom of the Ancients&quot; src=&quot;http://imgs.xkcd.com/comics/wisdom_of_the_ancients.png&quot; style=&quot;margin:0px auto;display:block&quot;&gt;
&lt;p style=&quot;text-align:center&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://xkcd.com/979/&quot;&gt;Wisdom of the Ancients&lt;/a&gt;&lt;/i&gt;, xkcd&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 17</title>
    <published>2014-08-28T00:00:00+00:00</published>
    
    <updated>2014-08-28T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-17/"/>
    <id>https://joshlf.com/posts/soylent-day-17/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-17/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing noteworthy to report today.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: N/A&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 16</title>
    <published>2014-08-27T00:00:00+00:00</published>
    
    <updated>2014-08-27T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-16/"/>
    <id>https://joshlf.com/posts/soylent-day-16/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-16/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing noteworthy to report today.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: N/A&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 15</title>
    <published>2014-08-26T00:00:00+00:00</published>
    
    <updated>2014-08-26T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-15/"/>
    <id>https://joshlf.com/posts/soylent-day-15/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-15/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For the love of all that is good and holy, do not water down your Soylent. This morning, not having a fridge to store a full pitcher in, I decided to make one serving for breakfast. I thought that I could get away with fitting one and a half servings in my water bottle, so I put one and a half serving&#39;s worth of water in. Then I realized that it wasn&#39;t going to fit, so I only put in one serving of Soylent. Oh, and since I didn&#39;t have a fridge, it was room temperature (another big no-no). I forced myself to drink the warm, diluted substance because I needed to eat, but each sip made me feel like I was going to puke. I don&#39;t know what it is about watered down or warm Soylent, but just... just don&#39;t. Dear god, just don&#39;t.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I spoke too soon! After initially posting this article, I had some Soylent that had been sitting in the fridge all day. It was actually a huge relief. The taste of the watered down Soylent had been in my mouth all day, and the cold Soylent was like cool sweet relief. Not only was it refreshing, but it actually washed away the taste of the watered down Soylent from earlier. Soylent to the rescue, I guess?&lt;/p&gt;
&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;p&gt;I still don&#39;t have access to a scale in my dorm, and I forgot to take my heart rate (that one&#39;s on me).&lt;/p&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: N/A&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 14</title>
    <published>2014-08-25T00:00:00+00:00</published>
    
    <updated>2014-08-25T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-14/"/>
    <id>https://joshlf.com/posts/soylent-day-14/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-14/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yesterday was my last day in Boston for the summer before heading to Providence. Being me, I decided to make the trip by bike, and, also being me, decided to bump said trip up to 2:00 am last night on a whim.&lt;/p&gt;
&lt;p&gt;Besides preening my adventurer&#39;s feathers, I mention this because I had to finish all of the Soylent that I had before I left, or else throw it away (I took the pitcher with me, and I didn&#39;t want to have a half-full pitcher of Soylent sloshing around on the back of my bike). Naturally, I picked the first option.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;There was a lot of Soylent left - about two very full glasses&#39; worth. Having made the decision to bump up the trip about 30 minutes before I was going to leave, I had 30 minutes to drink it all. So I chugged.&lt;/p&gt;
&lt;p&gt;I expected to feel over-full and maybe in a small amount of pain. But that&#39;s not exactly what happened. I felt pretty full, but not so much that it bothered me. Instead, I think largely from drinking the Soylent so quickly and giving my esophagus a workout, I got a heartburn-like pain near the bottom of my sternum that lasted all through the night and even persists faintly now at 9:00 pm the next day.&lt;/p&gt;
&lt;p&gt;The moral of the story: Drink. Soylent. Slowly.&lt;/p&gt;
&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;p&gt;I don&#39;t have access to a scale in my dorm, so I was unable to weigh myself. I may buy a cheap one so I can keep taking weight measurements. I also didn&#39;t want to take my heart rate after a night of biking and no sleep since that would kind of be like slapping statistical significance in the face.&lt;/p&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: N/A&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 13</title>
    <published>2014-08-24T00:00:00+00:00</published>
    
    <updated>2014-08-24T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-13/"/>
    <id>https://joshlf.com/posts/soylent-day-13/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-13/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing noteworthy to report today.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 164 lbs&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 12</title>
    <published>2014-08-23T00:00:00+00:00</published>
    
    <updated>2014-08-23T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-12/"/>
    <id>https://joshlf.com/posts/soylent-day-12/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-12/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing noteworthy to report today.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 165 lbs&lt;/li&gt;
&lt;li&gt;Heart rate: 64 bpm&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 11</title>
    <published>2014-08-22T00:00:00+00:00</published>
    
    <updated>2014-08-22T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-11/"/>
    <id>https://joshlf.com/posts/soylent-day-11/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-11/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing new to report today.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;p&gt;I wasn&#39;t at home last night, so I couldn&#39;t weigh myself in the morning (no scale available), and I forgot to take my heart rate (that one&#39;s on me).&lt;/p&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: N/A&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 10</title>
    <published>2014-08-21T00:00:00+00:00</published>
    
    <updated>2014-08-21T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-10/"/>
    <id>https://joshlf.com/posts/soylent-day-10/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-10/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today I went out to dinner and ate a fairly large amount, and I was less full than I had been in previous days. I think my straying from a pure-Soylent diet the past few days has gotten me more accustomed to large quantities of food in bursts as opposed to small quantities repeatedly.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;p&gt;I&#39;ve decided that, given the fact that my physical health hasn&#39;t fluctuated at all (it&#39;s just been listed as &quot;good&quot; on all but one of the days), I&#39;m going to remove it from the list of vitals. If any noteworthy changes happen, I&#39;ll note them, but otherwise I won&#39;t mention it.&lt;/p&gt;
&lt;p&gt;Also, I pulled an all-nighter last night, and so I couldn&#39;t take my heart rate just after waking up, and I omitted it today.&lt;/p&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 164 lbs&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 9</title>
    <published>2014-08-20T00:00:00+00:00</published>
    
    <updated>2014-08-20T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-9/"/>
    <id>https://joshlf.com/posts/soylent-day-9/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-9/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today, I went out to dinner &lt;em&gt;and&lt;/em&gt; desert, I didn&#39;t fill up as much as I expected. I have a suspicion that this may just be because of the increased amount of normal food I&#39;ve had over the past few days (with going out to dinner on Sunday and snacks the past few days). I just had a glass of Soylent as I sit here writing this (at 3:00am, so it&#39;s been a while since I ate), and I was actually hungry before I had it. Really the take-home here is that this stuff makes for good blog posts but really shitty empirical science. Hooray for small sample sizes!&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 162 lbs&lt;/li&gt;
&lt;li&gt;Heart rate: 72 bpm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Good&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 8</title>
    <published>2014-08-19T00:00:00+00:00</published>
    
    <updated>2014-08-19T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-8/"/>
    <id>https://joshlf.com/posts/soylent-day-8/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-8/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today, I had a turkey sandwich with two slices of sharp cheddar cheese on a relatively empty stomach, and now I&#39;m very full. Normally this would not be the case - I&#39;d be satisfied at best. I&#39;m getting the sense that I&#39;m really getting used to eating a bit at a time, and I&#39;m getting used to it pretty quickly (after all, it&#39;s barely been a week).&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 168 lbs&lt;/li&gt;
&lt;li&gt;Heart rate: 62 bpm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Good&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 7</title>
    <published>2014-08-18T00:00:00+00:00</published>
    
    <updated>2014-08-18T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-7/"/>
    <id>https://joshlf.com/posts/soylent-day-7/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-7/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing noteworthy to report today.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;p&gt;I forgot to take my vitals this morning... sorry.&lt;/p&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: N/A&lt;/li&gt;
&lt;li&gt;Heart rate: N/A&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Good&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 6</title>
    <published>2014-08-17T00:00:00+00:00</published>
    
    <updated>2014-08-17T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-6/"/>
    <id>https://joshlf.com/posts/soylent-day-6/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-6/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today, I went out to dinner with a friend and had a restaurant-sized cheeseburger. I normally have a bottomless pit of a stomach, but this filled me up to the point of being uncomfortable. My hypothesis is that I&#39;ve gotten used to not eating a large amount at a time. Because Soylent is a liquid, it is absorbed immediately, and thus must be consumed bit by bit during the day. Thus, over the course of the past few days, my stomach has never been particularly full. I guess I&#39;ve gotten used to it.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;I also didn&#39;t even finish the leftover Soylent from last night (there was about a fifth of a day&#39;s worth), let alone make a new pitcher. I&#39;ll be curious to see if I wake up very hungry tomorrow (or have more after posting this article and before going to bed).&lt;/p&gt;
&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 162 lbs&lt;/li&gt;
&lt;li&gt;Heart rate: 80 bpm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Good&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 5</title>
    <published>2014-08-16T00:00:00+00:00</published>
    
    <updated>2014-08-16T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-5/"/>
    <id>https://joshlf.com/posts/soylent-day-5/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-5/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing particularly noteworthy from today. However, it&#39;s been four full days now, and I haven&#39;t had nearly the amount of crime-against-humanity farting that many others have reported. I&#39;ve had a little, but it&#39;s been pretty infrequent (a few farts a day) and not particularly smelly. I expect that it&#39;s been some combination of following the advice I wrote about on &lt;a href=&quot;/posts/soylent-day-2/&quot;&gt;day two&lt;/a&gt; (not chugging the Soylent) and my body&#39;s unique sensitivity (or lack thereof) to the ingredients in Soylent. There&#39;s no obvious single answer; I guess the most I can say is that I got lucky.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;p&gt;A friend suggested that I add heart rate to my daily objective vital tally since it&#39;s trivial to take yourself and doesn&#39;t fluctuate too much.&lt;/p&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 161 lbs&lt;/li&gt;
&lt;li&gt;Heart rate: 74 bpm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Good&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 4</title>
    <published>2014-08-15T00:00:00+00:00</published>
    
    <updated>2014-08-15T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-4/"/>
    <id>https://joshlf.com/posts/soylent-day-4/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-4/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Soylent itself has been getting steadily more palatable. Though I&#39;m making the same mixture each day, it seems thinner to me now than it did at the start, and more enjoyable. I&#39;m still not to the point where I&#39;ll want it if I&#39;m hungry (though I&#39;ll convince myself to eat it in that case), but it&#39;s better than it was.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 164 lbs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Good, but I pulled an all-nighter last night, so any subjective data from today is untrustworthy&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 3</title>
    <published>2014-08-14T00:00:00+00:00</published>
    
    <updated>2014-08-14T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-3/"/>
    <id>https://joshlf.com/posts/soylent-day-3/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-3/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today I made another observation about eating quickly. Don&#39;t. Just don&#39;t. I tried sipping more slowly like I wrote about in &lt;a href=&quot;/posts/soylent-day-2/&quot;&gt;yesterday&#39;s post&lt;/a&gt;, but I guess I didn&#39;t slow down enough because now I feel almost uncomfortably full. In retrospect this shouldn&#39;t be surprising. Imagine eating a plate of spaghetti in a minute. Of course you&#39;re going to be full.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;I&#39;ve also noticed that a full pitcher seems like too much for a day. I&#39;ll admit that I&#39;ve been snacking on normal food a bit, so maybe that&#39;s been making up for some of my calorie count, but I finished the pitcher I made for dinner two nights ago for breakfast this morning (that is, it lasted me almost two days). I haven&#39;t been very active these past two days, so maybe I&#39;m just not burning much energy on a daily basis.&lt;/p&gt;
&lt;p&gt;Lastly, I&#39;ve found myself being actively hungry for something &lt;em&gt;other&lt;/em&gt; than Soylent. As in, the idea of eating tasty food really appeals to me. I&#39;m not sure if it&#39;s because the bland taste is, well, bland, or because I&#39;m missing some key nutrients (or at least nutrients that aren&#39;t necessary but I had a habbit of getting a lot of before). I still feel full and satisfied after I drink it, but I have to will myself to drink it knowing that that will be the outcome; I don&#39;t find myself actively wanting Soylent itself.&lt;/p&gt;
&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 162 lbs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Good.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: Day 2</title>
    <published>2014-08-13T00:00:00+00:00</published>
    
    <updated>2014-08-13T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-day-2/"/>
    <id>https://joshlf.com/posts/soylent-day-2/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-day-2/">&lt;p&gt;&lt;em&gt;[This post is part of a series on my month-long experiment with Soylent. See the &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;original post&lt;/a&gt; for an introduction.]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&quot;/posts/soylent-the-blog-series/&quot;&gt;previous post&lt;/a&gt;, I mentioned that I had found drinking Soylent to be unpleasant, and that it gave me a queasy feeling in my stomach. I now think that that had mostly to do with the large quantity of candy I had eaten just beforehand because, when I had my first Soylent today (even without the strawberries that I blended in yesterday to make it palatable), I didn&#39;t find it nearly as unpleasant. Since I was more hungry, the sweetness was more enjoyable.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;Besides the sweetness, I had made another mistake. I found a post online by a guy discussing the flatulence issue. He said that he hadn&#39;t had it so bad, but his wife had. He figured out that it was because she was drinking it quickly like she might a normal beverage, and they found that when she stopped drinking so quickly, and instead sipped it slowly like one might eat a normal meal, the issue subsided. I haven&#39;t yet had any issues with gas, but his point about drinking quickly was nonetheless relevant: I had drunk my Soylent quickly, and that probably contributed to my feeling queasy - it was like eating a big hamburger in under a minute. Today, I tried more slowly, and found that it helped.&lt;/p&gt;
&lt;p&gt;Also, I should note one thing that I forgot to mention in the original post: I&#39;m going to set a rule for myself that I can eat less than a day&#39;s serving of Soylent if I want to (though not by supplementing it with other food), but I won&#39;t ever eat more than a day&#39;s serving. If I end up getting really hungry this way, I may stop after a week or so, but I want to try it for at least some amount of time to see how it feels.&lt;/p&gt;
&lt;h2 id=&quot;vitals&quot;&gt;Vitals&lt;/h2&gt;
&lt;p&gt;Today is the first day I&#39;m taking any vitals. I probably should have started yesterday - oh well. I don&#39;t have much equipment, so for the time being I&#39;m just going to take my weight, and also record some subjective stuff like how healthy I feel (not mood, but physical health).&lt;/p&gt;
&lt;p&gt;Also, I should note that weight fluctuates a lot day-to-day based on things like how late you ate the night before and how early you weigh yourself and so on. For that reason, I&#39;d advise you not to read too much into the minor fluctuations, but pay attention rather to the overall trends. I&#39;ll try to write about these trends in any multi-day summaries that I write.&lt;/p&gt;
&lt;h3 id=&quot;objective-vitals&quot;&gt;Objective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Weight: 166 lbs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;subjective-vitals&quot;&gt;Subjective Vitals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Physical health: Decent. I&#39;ve got a bit of a headache, but I didn&#39;t sleep a full night, so that&#39;s probably why.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Soylent: The Blog Series</title>
    <published>2014-08-12T00:00:00+00:00</published>
    
    <updated>2014-08-12T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/soylent-the-blog-series/"/>
    <id>https://joshlf.com/posts/soylent-the-blog-series/</id>
    
      
    <category term="Soylent"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/soylent-the-blog-series/">&lt;p&gt;For the next month, I will not be eating normal food, but will instead be subsisting almost exclusively off of &lt;a rel=&quot;external&quot; href=&quot;http://www.soylent.me/&quot;&gt;Soylent&lt;/a&gt;. Soylent is a a powder which contains all of the nutrients that a human body needs to be healthy (at least, as far as modern science knows). When mixed with water, it yields a bland, brownish liquid that you drink.&lt;/p&gt;
&lt;p&gt;What exactly do we call this concoction? The side of the box it was shipped in bears the tagline &quot;powdered food.&quot; Some have referred to it as a &quot;food alternative,&quot; or have suggested that they are eating Soylent instead of food. Most importantly, there&#39;s no shortage of articles and blog posts discussing the various philosophical aspects of Soylent - is it food? Will people want to eat it? Isn&#39;t food meant to be social? I have thoughts on these questions, but that&#39;s not the point of this blog series. I may write a post on the subject, but for the most part this series is about my personal experience with Soylent, and the practicalities of using it as a replacement for a traditional diet.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;h2 id=&quot;the-blog-series&quot;&gt;The Blog Series&lt;/h2&gt;
&lt;p&gt;As I mentioned, this blog series is focused primarily on my experience with Soylent and the practicalities of using it as a replacement for a traditional diet. I&#39;m going to use it as a sort of scientific log book or journal, documenting how the Soylent tastes, how it&#39;s making me feel, whether I&#39;ve stripped the paint off of any of my walls with my farts [&lt;a href=&quot;https://joshlf.com/posts/soylent-the-blog-series/#1&quot;&gt;1&lt;/a&gt;], and so on. I hope to post once a day. I expect that most posts will be fairly brief, and not much will change day-to-day (&quot;Still haven&#39;t died; my housemates still hate my intestines.&quot;). From time to time I may do a review post noting trends that I&#39;ve seen over the past x amount of time.&lt;/p&gt;
&lt;h2 id=&quot;the-why&quot;&gt;The Why&lt;/h2&gt;
&lt;p&gt;A reasonable question to ask is why - why am eating Soylent for a month? That&#39;s easy - I&#39;m doing it to see how it affects me so that in the future I&#39;ll know if it&#39;s a viable option (I&#39;m on meal plan at college this year, so I won&#39;t be using Soylent long-term for at least another nine months). The harder question is - why would I want to do it long term?&lt;/p&gt;
&lt;p&gt;I have two main reasons. First, it&#39;s easy. I&#39;m really not a fan of the chores of life - the stuff that you do so you can keep living the parts of life that you look forward to. While I don&#39;t consider eating to be a chore, it&#39;s a different story for cooking, cleaning, and shopping for food. When my life is relaxed and not too busy, this isn&#39;t such a big deal, but when it does get busy, time spent on those chores is time that I invariably don&#39;t spend on more enjoyable activities.&lt;/p&gt;
&lt;p&gt;Second, it&#39;s healthy. I&#39;m something of a garbage truck when it comes to food - I basically just eat whatever tastes good. This is fun while I&#39;m young, but it&#39;s clearly going to come back to bite me later in life. And, yes, eating a normal healthy diet is obviously an option, but I know myself, and I know that planning, executing, and, most importantly, paying for a healthy diet isn&#39;t something I&#39;m realistically going to do. Soylent is (as far as we know) very healthy, and it&#39;s cheap and requires no effort or planning.&lt;/p&gt;
&lt;p&gt;Now, there&#39;s more to it than just that, but those are my primary reasons - the rest is just minutiae. Hopefully this little primer on my thinking will give context to this blog series and my opinions on and reactions to different aspects of Soylent.&lt;/p&gt;
&lt;h2 id=&quot;the-what&quot;&gt;The What&lt;/h2&gt;
&lt;p&gt;&quot;So you&#39;re really eating nothing but Soylent for a month?&quot; Well, no. Not exactly. What I want to do is test the efficacy of living off of it exclusively. But I don&#39;t think that occasionally eating normal food is going to mean that my results suddenly are wildly inaccurate. I&#39;m not trying to get precise numerical results - I&#39;m just trying to get a general sense of how an all-Soylent diet affects me. In light of this caveat, I&#39;m going to allow myself a few exceptions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An occasional snack or desert (so long as it doesn&#39;t constitute a meaningful portion of my daily intake)&lt;/li&gt;
&lt;li&gt;Social eating (going out to dinner with friends and whatnot). I&#39;ll try to have Soylent in social situations whenever possible, but I&#39;m obviously not going to bring a water bottle of Soylent to a restaurant.&lt;/li&gt;
&lt;li&gt;Additives to make the Soylent itself taste better (so long as they don&#39;t constitute a meaningful portion of my daily intake)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nonetheless, I&#39;m going to try to stick as closely as possible to the spirit of going &quot;all Soylent.&quot; I may adjust how &lt;em&gt;much&lt;/em&gt; Soylent I eat (for example, if I&#39;m not getting enough calories each day), but in general, I won&#39;t introduce non-Soylent food as a significant part of my diet.&lt;/p&gt;
&lt;h2 id=&quot;the-unboxing&quot;&gt;The Unboxing&lt;/h2&gt;
&lt;p&gt;When you order Soylent, the first thing that you get is not the Soylent itself, but a &quot;starter kit.&quot; It includes a pitcher for mixing and storing the Soylent, and a measuring cup which holds one half serving&#39;s amount of Soylent powder.&lt;/p&gt;
&lt;p&gt;Then comes the real behemoth - the Soylent itself. I ordered a month&#39;s supply of Soylent, so it came in a box big enough to uncomfortably smuggle a human. Inside the box were four smaller boxes, each containing a week&#39;s supply of Soylent and a small instruction booklet.&lt;/p&gt;
&lt;p&gt;The booklet is labeled &quot;Soylent 1.0 Release Notes,&quot; a clear nod to Soylent&#39;s open source ethos.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/soylent_box_9042216c5172726a78d731fdd20b2334.jpg&quot; alt=&quot;A large unopened Soylent shipping box&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/soylent_box_open_4d7cf27b60a8a038293724786e377461.jpg&quot; alt=&quot;An open Soylent shipping box with smaller boxes inside&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/soylent_week_3ff8e7b2bcfd6854f8e0a823e409f64b.jpg&quot; alt=&quot;A weekly Soylent box with an instruction booklet&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The Soylent itself comes in seven packages - one per day - and seven small bottles of oil blend. A few of the ingredients in Soylent are sourced from animal products, and in an effort to remain vegan-friendly, these are packaged separately in the oil blend. Soylent&#39;s makers claim they hope to eventually find vegan alternatives so that they can sell Soylent as the powder alone.&lt;/p&gt;
&lt;p&gt;The pouches themselves are, like everything in the box and the box itself, styled minimalistically - plain black text on a white background. They bear only the logo and nutrition facts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/soylent_pouch_and_pitcher_42768f76f6ee934476d12946147eff45.jpg&quot; alt=&quot;A Soylent pouch next to the included pitcher and oil bottle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The powder is beige and quite dense. If you drop the pouch on the counter, the powder settles with a single muted thud. It gives off a pungent, sickly sweet smell (I had just eaten five servings of Twizzlers as a last hurrah, so that probably lowered my tolerance).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/soylent_powder_c8cbc60bd10c31fc0122948c1078ecfa.jpg&quot; alt=&quot;Soylent powder inside an opened pouch&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-preparation&quot;&gt;The Preparation&lt;/h2&gt;
&lt;p&gt;Once Soylent has been mixed with water, it has a recommended fridge lifetime of 48 hours. The instruction booklet suggests ways to make single servings if you aren&#39;t going to eat a full day&#39;s worth within that time. However, I&#39;m going all in on this, so it&#39;s not a problem.&lt;/p&gt;
&lt;p&gt;The pitcher that is included in the starter kit holds one day&#39;s worth of Soylent - one pouch and one vial of oil blend mixed into the proper amount of water. This means that it conveniently serves as a measuring device - just dump the powder and the oil in and then fill the rest up with water.&lt;/p&gt;
&lt;p&gt;The instruction booklet recommends a slightly more nuanced procedure. First, dump the powder into the pitcher. Then fill most of the way up with water. Shake vigorously for 30 seconds. Then add the oil blend and fill the remaining space with water. Shake vigorously again for 30 seconds.&lt;/p&gt;
&lt;p&gt;When I first added the water to the pitcher of powder, it looked as though the powder was somehow resistant to mixing with the water. However, probably due to the fine grain of the powder, after 30 seconds of vigorous shaking, the mixture was completely mixed. The whole thing was pretty heavy, and after adding the oil blend and shaking for another 30 seconds, my arms were pretty tired.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/soylent_powder_in_pitcher_bc2515efda92d5013cd6c13db72bbb28.jpg&quot; alt=&quot;Soylent powder poured into the pitcher&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/content/soylent_and_oil_cd6783046d4b50f033d559108e697ebd.jpg&quot; alt=&quot;Soylent powder and oil blend in the pitcher&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-consumption&quot;&gt;The Consumption&lt;/h2&gt;
&lt;p&gt;The resultant liquid has the same sickly sweet smell as the powder, and I was afraid that drinking it would be quite unpleasant. However, it didn&#39;t taste nearly as bad as it smelled. I&#39;d heard reports that it had a grainy texture, but I didn&#39;t find that to be an accurate description. I could certainly tell that it had been mixed from a powder, but the powder was fine enough that I couldn&#39;t make out the individual grains. Instead, it had a smooth but heavy texture somewhat like a well-blended milkshake made from dense ice cream.&lt;/p&gt;
&lt;p&gt;However, there was something off-putting about it. I couldn&#39;t place my finger on what it was, but I found that drinking it gave me a sensation like what I was drinking tasted actively bad, though it didn&#39;t actually taste that way. In order to make it more palatable, I blended in four frozen strawberries with a glass (about one serving, or one third of a full day&#39;s worth). This helped, but I still found it off-putting. When I drank water shortly after drinking the Soylent, I got a mild queasy feeling in my stomach.&lt;/p&gt;
&lt;p&gt;I have a few hypotheses here. First, maybe it just takes some getting used to. Second, maybe I shouldn&#39;t have eaten it on a full stomach (remember those Twizzlers?). Or maybe it&#39;s something else. I&#39;m going to look around online tonight and see what other people say about it. I&#39;m sure there&#39;s no shortage of advice online about what to expect and how to make Soylent more palatable. I&#39;ll write about what I find in tomorrow&#39;s post.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That wraps up this first post. I expect that future posts will be much shorter. Please comment or &lt;a href=&quot;mailto:hello@joshlf.com&quot;&gt;write&lt;/a&gt; with questions, thoughts, or suggestions!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a id=&quot;1&quot;&gt;&lt;/a&gt;[1] Many users have reported having pretty bad gas while their digestive tracts adjust; it usually goes away pretty quickly (a few days to a week).&lt;/p&gt;
</content>
  </entry>
    
  <entry xml:lang="en">
    <title>Boston Go Meetup</title>
    <published>2014-03-08T00:00:00+00:00</published>
    
    <updated>2014-03-08T00:00:00+00:00</updated>
    
    
    <author>
      <name>Josh Liebow-Feeser</name>
    </author>
    
    <link rel="alternate" type="text/html" href="https://joshlf.com/posts/boston-go-meetup/"/>
    <id>https://joshlf.com/posts/boston-go-meetup/</id>
    
      
    <category term="Go"/>
      
    <category term="Reflection"/>
      
    
    <content type="html" xml:base="https://joshlf.com/posts/boston-go-meetup/">&lt;p&gt;Yesterday (Thursday, March 7th, 2014), I gave a talk on reflection in Go at the &lt;a rel=&quot;external&quot; href=&quot;https://plus.google.com/u/0/communities/103337146295481792015&quot;&gt;Boston Go Meetup&lt;/a&gt;. It was a blast, and there were a bunch of great people there (and other great talks). Here are the &lt;a href=&quot;/files/talks/Reflection.pdf&quot;&gt;slides from that talk&lt;/a&gt;.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;</content>
  </entry>
    
</feed>
