<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="http://2023.notgull.net/feed.xml" rel="self" type="application/atom+xml" /><link href="http://2023.notgull.net/" rel="alternate" type="text/html" /><updated>2023-12-24T05:37:17+00:00</updated><id>http://2023.notgull.net/feed.xml</id><title type="html">notgull</title><subtitle>The world&apos;s number one source of notgull</subtitle><author><name>John Nunley</name></author><entry><title type="html">SCP-093 is a Timeless Masterpiece</title><link href="http://2023.notgull.net/analysis-scp-093/" rel="alternate" type="text/html" title="SCP-093 is a Timeless Masterpiece" /><published>2023-12-23T00:00:00+00:00</published><updated>2023-12-23T00:00:00+00:00</updated><id>http://2023.notgull.net/analysis-scp-093</id><content type="html" xml:base="http://2023.notgull.net/analysis-scp-093/">&lt;p&gt;&lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is an absolute masterwork. Here’s why.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This essay is adapted from &lt;a href=&quot;http://www.scp-wiki.net/forum/t-118537/scp-093#post-4036289&quot;&gt;this comment&lt;/a&gt; on the &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; discussion page, by me, in 2019. So, the audience of the post of more “people who are familiar with the &lt;a href=&quot;https://scp-wiki.wikidot.com/&quot;&gt;SCP wiki&lt;/a&gt;” than the usual audience of this blog.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some time ago, I was trying to write a long, exploration-log based &lt;a href=&quot;https://scp-wiki.wikidot.com/&quot;&gt;SCP&lt;/a&gt;. However, I found myself struggling with keeping pace with the logs over a long period of time. So I decided to consult one of my favorite skips: &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I consider &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; to be the second best skip of all time, second only to &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-2000&quot;&gt;SCP-2000&lt;/a&gt;, which probably deserves its own essay. I wanted to go in depth and figure out what made 093 different from all of the other 4000+ skips that have shown up since its writing in early 2009.&lt;/p&gt;

&lt;h2 id=&quot;context&quot;&gt;Context&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is about a disc that showed up on the Red Sea. The disc acts as a portal to another world, where everybody’s dead and monsters roam the Earth. The SCP Foundation eventually discovers that this was the work of a singular entity, “&lt;em&gt;Him&lt;/em&gt;”, who convinced the world it was their god.&lt;/p&gt;

&lt;p&gt;Out of universe, &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; used to just be a disc that glowed when people held it. The entry dated back to the EditThis wiki, before Wikidot, and its original author remains anonymous to this day. Eventually, an enterprising user named &lt;a href=&quot;http://www.wikidot.com/user:info/nekochris&quot;&gt;NekoChris&lt;/a&gt; completely rewrote &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, adding a mechanic where it rolled towards mirrors, as well as the new test logs. Aside from some edits made by other users for grammar and tone, this is the version we’re reading today.&lt;/p&gt;

&lt;p&gt;This section is probably unnecessary, but I feel like it’s important to understand these things in the context of their creation. Without further ado, let’s move onto the skip itself.&lt;/p&gt;

&lt;h2 id=&quot;scprocedures&quot;&gt;SCProcedures&lt;/h2&gt;

&lt;p&gt;I wanted to do a line-by-line analysis of this. So let’s skip the ubiquitous Item # and Object Class and skip to the Special Containment Procedures.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Special Containment Procedures:&lt;/strong&gt; See testing document &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-T1 for outline of testing conditions. &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; must remain on a mirror at all times and under video surveillance. Admittance into the area of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s containment must be authorized only with proper video recording and subject retrieval procedures in place. Any attempt to use &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; outside of an approved test will be dealt with severely, up to and including termination.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Short and to the point. Keep it on a mirror, make sure it’s under surveillance, and don’t let anyone in without approval. This foreshadows what’s coming ahead, which is what any good SCProcedures should do.&lt;/p&gt;

&lt;p&gt;There are, however, some points here I’d like to point out.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Any attempt to use &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; outside of an approved test will be dealt with severely, up to and including termination.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is kinda a recurring thing that I dislike about older SCPs. The SCP Foundation hires highly trained, valuable scientists and agents, so why would they just kill them? I think “termination of employment” would work better here.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;See testing document &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-T1 for outline of testing conditions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had to take a moment and think about not only why this line was in the SCProcedures, but why it was the &lt;em&gt;first thing&lt;/em&gt; that it said in there. If this &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; document was thrust into the hands of a containment agent, why would they want them to read “look at this document for testing conditions” first?&lt;/p&gt;

&lt;p&gt;I don’t know, but I have a few ideas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;NekoChris wanted to emphasize that this is a testing log skip.&lt;/li&gt;
  &lt;li&gt;In universe, the testing procedures are really important to make sure &lt;em&gt;He&lt;/em&gt; doesn’t breach containment (more on &lt;em&gt;Him&lt;/em&gt; later)&lt;/li&gt;
  &lt;li&gt;My personal favorite: notice that it says “testing document T1” (where the mirror testing is) rather than “testing document T2” (where the exploring is). I think that this is outlined at the top of the file because they want to make sure people are testing 093 with the mirrors correctly, so they don’t accidentally enter the alternate reality. This foreshadows that &lt;em&gt;the Foundation doesn’t want people entering the alternate reality, even by accident.&lt;/em&gt; I’ll bring this up later in this essay.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;description&quot;&gt;Description&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is a primarily red disc carved from a stone composite resembling cinnabar, with circular engravings and unknown symbols carved at 0.5 cm depth around the entire object. Deeper cuts are present on &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; with a depth of 1 to 1.5 cm. &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is 7.62 cm in diameter and fits comfortably into most palms without abrasion. &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; will change hue when held by a living individual. The colors taken by &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; are still being researched to establish a link. Current belief holds that the changes depend upon regrets carried by the holder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is fairly straightforwards. The first paragraph describes the appearance of the object, that it can be held in your hand without issue, and that it changes color when it’s held by different people. Nothing big.&lt;/p&gt;

&lt;p&gt;By the way, remember how I said that this was a rewrite of a previous low-quality skip? Well, NekoChris pretty much summed up that entire skip in a single &lt;em&gt;paragraph.&lt;/em&gt; Which is, number one, an amazing feat of writing and, number two, I feel is done intentionally. He’s getting the old skip out of the way, so he can focus on the new stuff.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is removed from a mirror and not held by a person, it will seek out the nearest mirror-like surface. &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; has been observed to travel in the largest possible circle while rolling, building up phenomenal speed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, pretty straightforwards. 093 wants to be in front of a mirror, so it’ll roll towards the mirror and break any obstacle in its way to do so.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Additional Notes:&lt;/strong&gt; No records exist to clarify the nature of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s discovery or presence in the Foundation. See &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-OD. Since no records exist explaining &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s method of containment, a test procedure was initiated to establish why mirrors must be used to contain it. The results of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-T1 lead to the discovery of living beings holding &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; being able to move through mirrors and the series of tests in &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-T2 to ascertain the destination reached through this travel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ll come back to this in a minute, but they’ve lost the records for &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, so they have to do some tests to figure out what it does. This leads into the mirror tests, which lead into the exploration logs.&lt;/p&gt;

&lt;h2 id=&quot;original-documentation&quot;&gt;Original Documentation&lt;/h2&gt;

&lt;p&gt;Before we get to the tests, we get to see the original documentation of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;. This is done in a very interesting way; the &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-OD is actually &lt;em&gt;the pre-rewrite version of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;.&lt;/em&gt; This is interesting because, as far as I know, no other rewrites include their pre-rewrite versions wholesale.&lt;/p&gt;

&lt;p&gt;However, the way that it’s included, it’s not just a callback to the original. NekoChris used it in such a way that, just by being there, it progresses the story. Let’s look at two points in this section that I feel are important:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; resembled the documented blue for 54:34 at 1:23 on 26 April 1986 coincidentally when the body of 194-9834 was discovered in Research Facility █████.&lt;/p&gt;

  &lt;p&gt;Ties between 194-9834 and &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; remain inconclusive and effects of prolonged exposure to 093 remain unknown except for infrequent reports of periods of calmness and in the case of 242-0049 as periodic waves of depression, loss of balance and thoughts of suicide.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, in this, it asserts that &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; causes calmness and, in some cases, suicidal thoughts. Remember that &lt;em&gt;this is never mentioned for the rest of the skip.&lt;/em&gt; I think that there are two options here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;NekoChris either accidentally forgot to make a callback to this property, or deliberately did not call back to it to avoid mucking with his narrative.&lt;/li&gt;
  &lt;li&gt;In between 1985 and whatever date the current document takes place at, &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; somehow lost those anomalous properties.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Additional Notes:&lt;/strong&gt; Origins of 093 remain unknown and documents of recovery of 093 have since been destroyed in a fire in Research Facility █████, 09 December 1989.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first glance, this may seem inconsequential. But, remember this line:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Additional Notes:&lt;/strong&gt; No records exist to clarify the nature of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s discovery or presence in the Foundation. See &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-OD. Since no records exist explaining &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s method of containment, a test procedure was initiated to establish why mirrors must be used to contain it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You see, these two relatively small blocks of text, written by two different authors, years apart from each other, instantly create a storyline involving the Foundation in less words and in a much more compelling way than most skips do today.&lt;/p&gt;

&lt;p&gt;Let me explain; according to the “Additional Notes” section of the old documentation, there was a fire that destroyed most of the documentation for &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, leaving them not knowing why they contained it on a mirror, or what the colors of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; meant. First off, this is actually kind of meta; it explains why a lot of Series I skips (especially the older ones) are so short: a fire destroyed their documentation.&lt;/p&gt;

&lt;p&gt;However, NekoChris took advantage of this line in his rewrite by saying that the Foundation &lt;em&gt;didn’t know&lt;/em&gt; about why it was laying on a mirror, and that testing was beginning to find out why.&lt;/p&gt;

&lt;p&gt;This paints the following picture for me: a researcher, or bureaucrat, or whatever, is going through the old Foundation files, when they find the file for &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;. From reading it, they find out that we’ve had some red mood-ring disc lying on a (very expensive) mirror since 1968 for seemingly no rhyme or reason. Of course, they say something along the lines of “why?” followed by “we need some tests.”&lt;/p&gt;

&lt;p&gt;This not only establishes the beginning of a narrative in only a few words, but sets up something grand that I don’t see in a lot of skips, new or old, do: it sets up the Foundation as a main character, and sets it up for characterization.&lt;/p&gt;

&lt;p&gt;What I mean by this: in most skips, you learn information from a certain point of view, whether that of a researcher, the SCP itself, an MTF team, or just none at all. However, in &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, the Foundation &lt;em&gt;itself&lt;/em&gt; takes this role. The reader learns new information at the rate at which the Foundation discovers it, and almost gets to feel the role of the Foundation as they figure out the anomalous properties of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; and explore the world beyond. In addition, this also allows for some pretty cool characterization of the Foundation; we see the Foundation’s motive change from simple testing, to exploration, to full-on planetary defense. I’m not saying that 093 is the only skip to do this; many other skips characterize the Foundation’s goals, history, and parts as well. But they often use paragraphs upon paragraphs to do it, while 093 does it and such a wonderfully subtle way that it’s hardly noticeable without paying attention.&lt;/p&gt;

&lt;p&gt;Just a reminder, &lt;em&gt;all&lt;/em&gt; of this is set up in just around five lines. Five. Lines. This is economy of language at its finest, and is really genius level writing.&lt;/p&gt;

&lt;p&gt;Anyways, now that the main character is set and the plot is ready to go, let’s start with the part where &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; really gets interesting.&lt;/p&gt;

&lt;h2 id=&quot;test-log-1&quot;&gt;Test Log 1&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Mirrored surface, brass frame, retail-grade mirror:&lt;/strong&gt; &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; rests without activity when placed on the mirror. This test alone removes the need for costly silver or wooden containment systems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is actually kind of funny, because it feels like something of a roast directed at the original author.&lt;/p&gt;

&lt;p&gt;This test log really just restates what we’ve already learned from the Description, and principally serves to build up to the final log:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;A person holding &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; placing it on a mirror:&lt;/strong&gt; This test was accidental, the result of one of the staff tripping another after some debate about who would be covering the lunch tab. As a result of the behavior of the researchers, it was discovered that a person holding &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; and placing it against a mirror will in fact move into the mirror.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, a complaint: along with the “termination punishment” thing mentioned above, this is how you can tell that this was written in early 2009; the era of lolFoundation, Keter Duty, and Omega-7. Why would a researcher bring &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, a dangerous object that can punch through walls and has been known to cause suicides, to lunch? Why would they have it out while walking? Why is there a mirror in the hallway? Why would a researcher trip another researcher while he was carrying aforementioned object that punches through walls while it’s not in the palm of someone’s hand?&lt;/p&gt;

&lt;p&gt;To be honest, I headcanon this as some kind of cover-up for some O5-eyes-only secret. Although I do admit that this line has personality, I think a simple “a D-class tripped and accidentally fell through a mirror” would work as well.&lt;/p&gt;

&lt;p&gt;Alright, rant over. What this does well: it kickstarts the upcoming plot. We already knew that 093 rolls towards mirrors, but nobody knew &lt;em&gt;why&lt;/em&gt; 093 rolls towards mirrors. In this, it’s implied that the whole reason why 093 rolls towards mirrors is to show us to this alternate realm. Reminds me of that one movie where there’s that bird that shows the main character to the gateway to the alternate dimensions where she’s supposed to go.&lt;/p&gt;

&lt;p&gt;Now we know that &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; + Mirror = Gateway to an Alternate Dimension. And now our main character, the Foundation, turns its motive from containment to exploration.&lt;/p&gt;

&lt;h2 id=&quot;test-log-2&quot;&gt;Test Log 2&lt;/h2&gt;

&lt;p&gt;(By the way, I’d like to interrupt this by saying that I &lt;em&gt;really&lt;/em&gt; like this table-header format. It’s sad that, as far as I know, there aren’t any skips outside of 093 that use it.)&lt;/p&gt;

&lt;p&gt;We transition here into the exploration logs, which is where the meat of this skip is. We get an idea of what our subjects are taking into the alternate dimension, and then we’re thrown into the Blue Test.&lt;/p&gt;

&lt;h2 id=&quot;blue-test&quot;&gt;Blue Test&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Camera activates, flickers to view. Subject is looking out over the same field reported by technicians. Looks like typical lowland plains, everything has a heavy blue tinge overlapping the normal colors. No discernible landmarks visible as subject pans view left to right, only grass, weeds, and a breeze moving the taller grass. No trees. No living beings visible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first paragraph asserts that we’re in some kind of plains. However, there are no trees, and no living beings. Right off the bat, it is asserted that we’re either in some kind of remote part of this alternate universe, or that everything is dead. This is a post-apocalyptic universe.&lt;/p&gt;

&lt;p&gt;Eventually, the subject enters a hole in the ground, which leads to a tunnel, which leads to some kind of bunker.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Room is bare, no contents, but walls are filthy. Subject states material on walls isn’t dirt, but he can’t identify it, seems to resemble melted plastic but is brown in color rather than black.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where we’re first introduced to what I’ll be calling “mystery goo”. It smells bad, and it’s everywhere. It serves as sort of a “recurring mystery”, where it appears everywhere, and we’re slowly clued into its origin.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Walls of room are clean as is floor, ceiling is coated in the same strange brown material as the third room. In this room there is a makeshift cot made from aged blankets with a pillow, a wooden crate containing open boxes of what appears to have been food stuffs, language appears on video as squiggles however subject states they simply read ‘Cereal’. A second crate in the room contains what appear to be empty water bottles that have dried out. A book lays next to the cot, closed, no title or identifying marks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, this is definitely a survival bunker. This confirms the belief that this is some kind of post-apocalypse, and that there used to be people here. But now, there is just the weird mystery goo, collected on the ceiling.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Careful review of the following ten seconds of tape shows that as the camera pans, a figure is visible at the end of the tunnel where the seventh door is. The door is open only enough for a face to be seen through a crack just before the door silently closes. No details can be seen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is another one of those “recurring mysteries” to help keep readers hooked: these mysterious shadow people that show up everywhere. After all, it’s made clear that this is some kind of post-apocalypse, so why are there people?&lt;/p&gt;

&lt;p&gt;This is almost glossed over- which is good. It’s kind of a “wait, what the hell?” moment, and the fact that it’s almost entirely unmentioned after the fact solidifies that moment.&lt;/p&gt;

&lt;p&gt;Then there’s some cable trouble, then the subject gets pulled out of the hole by some unseen force, and the camera sees 37 creepy ghost people. They’re unidentifiable, and they’re watching the subject for some reason.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Control requests subject return following cable path and screams are caught on the audio with panic from subject. Five shots fired as subject aims pistol at something not visible on camera. Control reports being able to see subject returning toward point of origin while camera shows wire disappearing into a point floating in the air. As subject passes this point all cable is now in the pulley system and camera films only the floor. Control reports that the mirror took approximately five seconds to return to a reflection and &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; remained blue in color until one hour after being recovered from subject.&lt;/p&gt;

  &lt;p&gt;A vile smelling fluid was present on subject’s clothes around his hands when firearm was recovered. This fluid dried quickly and was deemed insignificant of study due to lack of quality sample. Control personnel monitoring the mirror state having seen a massive human being, crawling on the ground, easily fifty times the size of a normal person with no facial features and a very short arm reach, pulling itself toward the mirror before it returned to a reflection. Due to proximity fine details could not be made out but at least one observer noted the being appeared to have been shot from the marks in the otherwise smooth featureless face.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where we get a look at the “antagonist” of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, for lack of a better word: the Unclean. In the first test log, the reader only gets a glimpse of them; they’re big, they’re scary, and they’re chasing the Subject.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Field Test Kit recovered from subject containing a news paper article that reads: [DATA EXPUNGED] and was filed as item [DATA EXPUNGED].&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These expungements may seem unnecessary at first glance; however, this is some story information that is best saved ‘til later, and (IMO) actually convinces the reader to read on out of curiosity as to what’s behind the expungements.&lt;/p&gt;

&lt;p&gt;All in all, a pretty good opening log for this skip. It introduces the parallel universe, the fact that it’s a post-apocalypse, the mystery goo, the ghost people, and the Unclean in just the right amount for it to be spooky, but also to leave the reader wanting more. I do think it could be improved by adding some foreshadowing to the religious apocalypse (I.e. maybe a cross in one of the bunker rooms?) and I think that the Unclean were described a bit &lt;em&gt;too&lt;/em&gt; much for what should’ve been a vague hint at a monster (I.e. instead, maybe say “technicians saw a glimpse of a large humanoid figure crawling on its hand before the mirror returned to a true reflection” and leave it at that), but for what it is, it excellently introduces the concepts and players which are built upon in the remaining logs.&lt;/p&gt;

&lt;h2 id=&quot;green-test&quot;&gt;Green Test&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;No landmarks from Test 1 are discernable as subject pans camera over area.&lt;/p&gt;

  &lt;p&gt;Present is a field, long abandoned, in the middle of which stands the remains of a scarecrow of unknown design, fragments left are rotted and torn. Nothing grows in the tilled land. A farm house is visible to the right of the field, large, two stories, a basement shelter entrance is visible at one end.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, the first few lines tell the audience the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;This is in a different place than Blue Test.&lt;/li&gt;
  &lt;li&gt;We are on a farm.&lt;/li&gt;
  &lt;li&gt;Everything is dead.&lt;/li&gt;
  &lt;li&gt;There’s shelters everywhere, which implies that people knew about whatever apocalypse happened here beforehand.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;As subject pans the area a metal hatch is visible in the ground, similar to a bulkhead on a submarine with a turn handle. Subject remarks that the smell is at its worst around the hatch and the dirt around the hatch is noted as being clumped and claylike.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is repeating the whole “stench” and “mystery goo” thing from Blue Test. What this does is make the audience anticipate the inevitable “mystery goo” and perhaps even the ghost people from Blue Test.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;On the beds are two skeletons and on the floor is a third, lying next to which is a simple six shooter revolver containing no ammunition. Three spent casings are across the floor near the gun.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I haven’t been commenting a lot for a reason I’ll bring up later, but this gives the audience new information: there was a &lt;em&gt;struggle.&lt;/em&gt; They didn’t just keel over, they were killed by something.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In the distance, approximately 700 m from the farm, two massive, humanoid beings are crawling across the landscape.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This further introduces us to the Unclean, which were only slightly glimpsed in the last test.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There is a recliner, a couch, and a television all of 1950s style design. In the recliner is a laptop whose case also resembles 1950s decor and is coated in heavy dust.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is some further world building. When this civilization ended, it was in the 50’s, or some analogous point. This helps to further paint a picture of this world in the reader’s mind.&lt;/p&gt;

&lt;p&gt;To conclude, at first glance, this seems to be a retread of the first log. In fact, the reason why I didn’t do as many quotes was because a lot of the structure is almost identical to the first. However, along with some decent world building, it gives us new information. Whatever apocalypse happened here wasn’t instant. There was a &lt;em&gt;struggle,&lt;/em&gt; against &lt;em&gt;something&lt;/em&gt;. Something that managed to get into the bunkers and kill an entire population. And if you’re like me, you’re beginning to suspect that it has something to do with the large human like things that we’ve seen twice now.&lt;/p&gt;

&lt;p&gt;This all helps to build the mystery, along with the creep factor NekoChris has been setting up: the eerie feel of an empty world, roamed by these eldritch horrors.&lt;/p&gt;

&lt;p&gt;Now onto the third test…&lt;/p&gt;

&lt;h2 id=&quot;violet-test&quot;&gt;Violet Test&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Subject is in what appears to be a modern downtown district similar to a city like New York. The streets are mostly bare except for a few cars of unknown make or model. These cars look highly advanced and streamlined.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of another rural area like the last two tests, we instead start with a city area, which, if we had any doubts about whether or not this was an apocalypse or just a bunch of people leaving the countryside, this silenced those doubts.&lt;/p&gt;

&lt;p&gt;In addition, this gives us a glimpse into this civilization’s tech level with the advanced cars, which we haven’t yet seen. This is some further world building.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Subject attempts to look into the car windows without being instructed to but backs away remarking there is a ‘rank ass stank’ coming from the areas around most of them.&lt;/p&gt;

  &lt;p&gt;Subject is persuaded to move closer to one car and does so with coughing, wiping off a window which is covered in dirt. The inside of the car appears to be completely filled with a strange brown matter, there is nothing at all visible other than the brown matter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Control debates this issue while subject stares around the cityscape from the car. During one pan a face is clearly seen staring into the car, eyes watching the subject; however, this was not noticed until post-test footage review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we also have the stench, the mystery goo, and the ghosts. These are familiar elements, and they’re all gotten out of the way before we really start the exploration.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A team of four armed personnel is sent through the mirror and proceeds to subject’s location.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This time around, we have an entire team of soldiers traveling with the subject. I feel like this is done to change things up from the last log.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The view of the city is astonishing. This building is one of the tallest visible but certainly not alone in its stature. The city below is gray and silent, no evidence of life at this altitude. Some buildings in the city have a strange brown growth that appears to have been splashed against them as if a gelatinous mass was flung and then seeped down before hardening.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, some more world building. They have some pretty good tech, but whatever they did they still weren’t able to fend off the apocalypse. “Gray and silent” in particular get to me in emphasizing that this is a ghost town, minus the Unclean.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;On the desk is a notepad titled ‘From the desk of Dr. Borisizki, Blessed Purificationist’.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah, this was implied with the whole “FaithfulOS” thing earlier, but this tells us that this world has something to do with the wide adoption and fundamentalism of some religion. This is further asserted by the test tubes.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The camera pans to a section of raised expressway across which one of the large torsos is crawling slowly. The entity turns its featureless head to look at the escort team, raises its head to the sky, and emits a bellowing sound.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is an “oh, shit” moment. So far, all we’ve seen involving these entities is them either walking around, or vague glimpses of them. Now, we’re fighting one head on.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When a matching color is displayed and applied to the mirror the video receiver is visible and all individuals report a horrific smell.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Later review of the recovered camera shows escort member ██████ grasping at the air where entry point should be and then turning to look up at the oversized torso. A brown gel seems to drip off the creature as it moves that disappears shortly after being dislodged as if evaporating. Several shots are fired at the creature’s face with the automatic weapon carried by ██████ that land in the ‘face’ of the creature, causing a spray of less viscous brown liquid to pour forth from the ‘wounds’.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ll comment on these two parts later, but this reveals two things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The stench, and therefore, the mystery goo, are both associated with the Unclean.&lt;/li&gt;
  &lt;li&gt;Since they’re associated, and given the goo and the corpses in the bunker, the Unclean were the cause of this apocalypse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, a side note: I think NekoChris went out of his way here to not say “&lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-1” and instead use descriptions to describe the Unclean. I think this is to evoke more imagery with the techniques that they have.&lt;/p&gt;

&lt;p&gt;This test actually reveals quite a bit about the world &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; leads to. We see the high tech cities, the people in the vials, the religious connections, where the mystery goo comes from, and we experience the first real encounter with the Unclean. While Blue Test and Green Test paint a picture of a post-apocalyptic world ravaged by the Unclean, the Violet Test paints a picture of the world as it was before apocalypse. As much as I do detest the fact that the religious aspect is hardly touched upon in the first two logs, I feel like it makes the payoff in this log much more satisfying.&lt;/p&gt;

&lt;h2 id=&quot;yellow-test&quot;&gt;Yellow Test&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;D-class subjects no longer authorized for testing. Testing focus has been shifted to data collection after analyzing the articles brought back from the previous three tests to better understand the fate of the world accessed by &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; and determine if safeguards or practices are required for our own world.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Can I just remark on how &lt;em&gt;epic&lt;/em&gt; this line is? After painting a good enough picture of the world in 093, the Foundation shifts its focus from exploration to &lt;em&gt;full-on planetary defense.&lt;/em&gt; Holy crap.&lt;/p&gt;

&lt;p&gt;Just a reminder that this line comes after the test log where we, the reader, receive a definite linking between the apocalypse and the Unclean. Remember what I said earlier about the first parts of the skip setting up the Foundation as a “perspective character,” a character where we learn information at its pace? This is that setup in action, and it puts the audience is the Foundation’s shoes as it calls for planetary defense. This is one of those genius writing moments that make me love this skip.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The descent down the elevator is long, consuming 15 minutes, during this time the camera experiences one malfunction where the image jerks and turns to snow, restoring to show 14 other figures in the elevator with Dr. █████ as video pans around, all of whom move as he moves to allow him space. They remain for 35 seconds then the camera flickers to snow and returns, Dr. █████ is now alone in the elevator dancing as is assumed by the ducks and sways of the video feed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just wanted to remark about how imagery-inspiring this is. For all the complaints about the tone of these logs, they have some pretty good imagery and characterization.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The third view is facing the opposite direction as a camera glides vertically checking each observation station. A total of 10 can be counted and Dr. █████ is visible as the camera passes by his own station. Looking up, a hovering camera unit with no visible means of propulsion glides up past him. The fourth view shows the ground floor below the observation deck where a single astonishingly large torso being is crawling in circles, bumping into walls and changing directions. From the camera feed the creature’s estimated size is six stories.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is actually setting up for the conclusion, and it does so in an unusual way: contradicting itself. NekoChris has spent the past three logs asserting that everything is dead, and the world has fallen apart. Now, we’re seeing rows upon rows of function PCs, and the containment of one of the Unclean. I’ll comment on this more later.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Analysis of ███-███ and the ammunition for it postponed for reason that it would require deconstruction of one of the rounds and they may be beneficial until testing of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is resolved. Video ends.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two things about this line:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;███-███ is just a poor man’s SCP.-███&lt;/li&gt;
  &lt;li&gt;“they may be beneficial until testing of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is resolved.” This is one of those sentences that really pop out at me. Remember how it was asserted earlier that the Foundation’s now focusing on defending the world from whatever happened in the 093-world? Yeah, they’re &lt;em&gt;taking every weapon they can get to make sure they’re defensive.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in all, the yellow log is really a continuation of the violet log, and helps to set up for the finale with its tonal shifts and feats of working technology.&lt;/p&gt;

&lt;p&gt;Without further ado, let’s get to that finale.&lt;/p&gt;

&lt;h2 id=&quot;red-test&quot;&gt;Red Test&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Service Technician ██████ was able to cause &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; take on a fierce red hue and glow, much brighter than the object’s normal color.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is one of those moments where you, the reader, know that &lt;em&gt;shit’s about to go down.&lt;/em&gt; It’s when your heart starts beating, and you end up glued to the chair as you scroll downwards. This almost perfect buildup for what’s about to happen.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Video flickers to life and Technician ██████, known hereafter as Subject, is viewing a large cylindrical pillar that is rotating on its own. Object is of unknown height and appears to be 1.8 m (6 ft) in width. Holes are distributed throughout the object at seemingly random intervals. On occasion a beam of white light is emitted from these holes. Turning of the camera finds that the beams are connected to a multitude of objects similar to &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; that are part of the room’s wall. The room turns out to also be cylindrical in shape with countless copies of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This makes two assertions. The first is more obvious: &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is a dimension-travel technology. However, the second, the fact that this is some kind of hub for &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, &lt;em&gt;doesn’t guarantee that we’re in the same universe.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let me explain this theory of mine. For the past four tests, we’ve been thrust into an alternate dimension, which appears to be &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s intended destination. Now, we’re in some kind of 093 hub. Maybe the service technician somehow activated a “return to sender” feature on &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; that brought him back to the source? I’ll discuss this one more later, once we’ve finished the SCP and we have all of the facts in one basket.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The ladder exits into a large clean room full of computer equipment that appears antiquated compared to previously encountered equipment. Large computers running on reel-to-reels are clicking and spinning at various locations, a light bulb of unknown meaning turns on for ten seconds then turns off. A large CRT monitor is displaying single words in 8 colors at roughly 5 second intervals. While observed the words ‘Clean’ ‘Unclean’ ‘Clean’ ‘Clean’ ‘Lost’ ‘Unclean’ flash on the screen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some more evidence to my “not the same dimension” theory: it’s obviously not the same level of technology. I theorize that the meaning of the words on the screen are referring to different universes accessible through the 093’s we saw in the hub. Whether they’re not infected by the Unclean, are infected, or if their &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; instance is broken or lost.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;All further &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; tests have been discontinued while review of materials recovered is in effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ll comment on this line later.&lt;/p&gt;

&lt;p&gt;All in all, the red test is a pretty good finale. It takes an “oh, crap” moment and extends it throughout the entire log. Now, let’s move on to the last log.&lt;/p&gt;

&lt;h2 id=&quot;recovered-materials&quot;&gt;Recovered Materials&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Any employee reading past this point who does not have proper classification should consider themselves to be terminated from employment and now subject to disciplinary actions up to and including: Forced administration of Class A Amnesic, immediate transfer to Keter class security, and death.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another one of those “Series-1-esque” bits I talked about earlier. It’s charming, but I feel like punishing employees with death is the wrong way to go.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Most Holy Father Announces Progress, Unclean Being Cleansed!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, this segment, I feel, is the result of a “Catch-22.” NekoChris couldn’t put it explicitly in the Blue Test, as it reveals lore that should be saved for later. But that means that they had to put it here. At this point, the payoff is good, but could be done in another way, I feel.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;But if you see this symbol, if you see it.. you run boy, you run fast, you run far, and you hide, and you never go back where you saw it. That’s all I know. - I remember the symbol, was on the rock he kept on his neck under his shirt. Next day, pap was gone, nowhere to be found, dad weren’t sad, said he knew it’d happen one day, pap went home. See you soon dad, pap..&lt;/p&gt;

  &lt;p&gt;[DATA EXPUNGED] Symbol matched symbol found on &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s surface as one of the deeper engravings. Also matches symbols noticed on video feed of final test on &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; duplicates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is some creepy, good shit.&lt;/p&gt;

&lt;p&gt;Also, why would the symbol be expunged, especially in a file where all of the recovered, unexpunged information is? Given what we learn later about the origin of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, I’d guess that the symbol is &lt;a href=&quot;https://en.m.wikipedia.org/wiki/SCP_Foundation#/media/File%3ASCP_Foundation_(emblem).svg&quot;&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;During preparation for the Tears subject went into a rage and the attending Hand went to recover a sedative. Jennifer tore her clothes off and screamed impure words at me so I locked the door and instructed the Hand to wait outside. I am half shameful to admit I laid with Jennifer a total of seven times before putting her to the Tears.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This line introduces us to the “Tears,” as well as emphasizes the corruption of whatever system was in place before the apocalypse.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Eyes have dated the sample, it is older than myself, older than my elders. It is over 200 cycles in ages. 200!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;I do not think this Unclean is alone. I have seen how they can get into places, between places. Between places! Is that where they have been, all this time? Between places?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;The smell, it is so strong, it comes from all directions. It is not a smell of the dead, it is a smell that comes from something that should be dead but does not know how to die&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is some Kalinin-tier prose, and the note it’s in is great. It shows the perspective of the corruption and the Unclean from somebody who’s not on the top, but knows quite a bit. It’s great insight into this world, and it does it without being too over-explaining.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In the event of any Emergency requiring the Facility to be evacuated, all Clear-4 staff should report to Train Station 3 and use their Vial to call the Evacuation Train. Only one Vial is required to call the train and may contain any amount of Tears. An Empty Vial will not call the train. Clear 2 and 1 staff should remain at their posts until either 10 minutes after the departure of Clear-4 persons or until authorized by Clear-4 staff. Clear-3 staff should utilize the Protective Garments at their stations and weapon lockers before proceeding to designated Crisis Areas as dictated by Clear-4 staff.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This makes it clear that this is some 093-infected Foundation analogue. But remember the multidimensional hub? Yeah, NekoChris invented the multidimensional, all-intrusive Foundation before Scantron codified the concept in their &lt;a href=&quot;https://scp-wiki.wikidot.com/scantron-s-proposal&quot;&gt;001 proposal&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I actually found a scientific report written by someone who stumbled here with a &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; copy. These creatures are the result of exposure to a very pure form of His Tears resulting in a genetic apocalypse occurring within the exposed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;“Genetic apocalypse?”&lt;/li&gt;
  &lt;li&gt;This is where it all starts coming together for the reader. And it does so beautifully.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;I think someone is in this facility, or someones, I keep hearing voices and requests coming from areas under the floor. I want to leave this before I explore the facility any further. I have sent &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; back through the entry mirror to seal that gate. These things can’t be let into our world nor should we have anything to do with this one, we’re simply not smart enough to understand it all I feel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ll comment on this more later, but this is one of those moments where it calls back to something earlier: specifically, the “bad grammar” entry just before this one. And &lt;em&gt;something&lt;/em&gt; happened to that person.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;They’re.. in my head I think.. I didn’t notice it till just now but, equipment in this room is starting to react to me, words on the screen, begging for help.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’ve seen the faces, of the people, the Unclean. They show up on the pictures cast by the machine, in the room with me, watching me. I think, they’re everywhere on this world, only seen by machines now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it also explains the ghost people. Nice.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;they showed me things when i touched them and its not quite like the records say. the unclean remember it all, every person they touch becomes part of them, safe inside them, but dead to us. every mind, every feeling, every terror, its eternal to them. i kind of want to join them but.. too much to do.. they want me to.. find him, kill him.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oh no.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;there was no war it was him him him him him IT. IT. it came from between the folds of time and space and worlds and light and dark something that is but should not be slipped in and called out to them as their god and they believed it and they tasted it and touched it and layed with it and became its property and did its will and IT IS STILL HERE the scp-093 it brought with it pulled forcefully with it built it i don’t know they don’t know but it belongs to him it lets him move between places between worlds so i BROKE IT ha ha ha i threw pieces of it away and through holes so those doors are closed just like ours is closed and i can’t go home so what else can i do&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Oh no.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;it calls out through the rock, somehow, it knows where they are but can’t touch them, but if you hide the rock he can’t call out and he’s stuck too i got you you son of a bitch I GOT YOU BANG BANG ha ha&lt;/p&gt;

  &lt;p&gt;i touched him. with my fist. and my gun. and he fell down. but he’ll get back up. soon. i’m sorry, i did all i could, let me sleep now, please… let… me… slee&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Oh, no!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Despite the over-explaining in the note, the end of it is a fitting conclusion to the adventure. It’s cryptic, but not too much, and leaves the reader wanting more.&lt;/p&gt;

&lt;h2 id=&quot;speculation&quot;&gt;Speculation&lt;/h2&gt;

&lt;p&gt;I’m gonna try here to take educated guesses as to what &lt;em&gt;happened&lt;/em&gt; in &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;. I know it’s not really analysis, but I’ll use it to prove a point later.&lt;/p&gt;

&lt;p&gt;So, first of all, what is &lt;em&gt;Him&lt;/em&gt;? All we really know about &lt;em&gt;Him&lt;/em&gt; is from the last log, so let’s put all that together:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;He’s obviously not human, as the description of his origin (“it came from between the folds of time and space and worlds and light and dark something that is but should not be”) kinda makes me think of “Lovecraftian Monstrosity.”&lt;/li&gt;
  &lt;li&gt;He is able to impersonate, or is, a god.&lt;/li&gt;
  &lt;li&gt;He created several extremely high-end technologies, including &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we know what &lt;em&gt;He&lt;/em&gt; is, what happened to him? My two theories are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;He killed and impersonated the service technician to get into our reality, and when he was killed &lt;em&gt;He&lt;/em&gt; was killed (boring ending).&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;He&lt;/em&gt; is still alive, and is somehow attached to &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; (see below).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I find the second one more interesting, and I think it actually makes a couple of writing quirks that I’ve commented on so far seem justified.&lt;/p&gt;

&lt;p&gt;Let me use an example. For the purposes of the example, let’s give names to the worlds involved in the story:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;World 1 - The world accessed in the Red Test, and the “Hub World” for &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;World 2 - The world accessed in the Blue-Yellow Tests, and has fallen to &lt;em&gt;Him&lt;/em&gt; and the Unclean.&lt;/li&gt;
  &lt;li&gt;World 3 - The world where Agent ██████████ from the recovered documents is from.&lt;/li&gt;
  &lt;li&gt;World 4 - The world where our Foundation is in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s establish a timeline. In World 1, &lt;em&gt;He&lt;/em&gt; appears, possibly just a natural anomaly, like how &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-173&quot;&gt;SCP-173&lt;/a&gt; is an anomaly native to our world. He takes over World 1, builds the 093 hub, and sets out to send 093’s to the other dimensions to bring &lt;em&gt;Him&lt;/em&gt; to the other worlds.&lt;/p&gt;

&lt;p&gt;World 2 is a world that got successfully invaded by &lt;em&gt;Him&lt;/em&gt; and taken over.&lt;/p&gt;

&lt;p&gt;World 3 is a world that got ahold of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; and apparently went on a thorough investigation of either World 2 or another Unclean world. However, the agent eventually realized what &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; really did, and then broke it to &lt;em&gt;He&lt;/em&gt; couldn’t get to World 3.&lt;/p&gt;

&lt;p&gt;In World 4, AKA our world, we see that &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is really just a vehicle for &lt;em&gt;Him&lt;/em&gt;. We now know that its usage could lead to the end of the world for all of us. So the Foundation does what it does best: it locks it up in a box, to make sure it doesn’t see the light of day.&lt;/p&gt;

&lt;p&gt;This explains the narrative quirk of: “why didn’t the Foundation do more explorations of &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;?” Why didn’t they pass around 093 some more to see if they could get it to glow orange, or something? Why didn’t they send an MTF back into the Blue Test so that they could break down some of those stuck doors? Why didn’t they even test out the Unclean-killing revolver? The answer is simple: to open up &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; again would be to risk the same thing happening to us.&lt;/p&gt;

&lt;p&gt;This also explains the missing sadness property from the original documentation: it was there originally, but maybe &lt;em&gt;He&lt;/em&gt; fixed it so people would be more likely to pick it up. This also explains why &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; spins towards mirrors: it’s &lt;em&gt;Him&lt;/em&gt;, trying to show us the way to let him into our world.&lt;/p&gt;

&lt;p&gt;This also explains the very first line of the SCP:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;See testing document &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;-T1 for outline of testing conditions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They’re saying “if we’re testing this thing again, whatever you do, &lt;em&gt;don’t&lt;/em&gt; open up a mirror portal.” As the first thing we see in the documentation, this is driving home the fact that the Foundation wants &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; to stay buried.&lt;/p&gt;

&lt;p&gt;I love these SCPs that you can speculate on, and &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; does a fantastic job of facilitating this speculation. It’s close-ended enough to be a satisfying story, while open-ended enough to the reader to have a sense of wonder.&lt;/p&gt;

&lt;p&gt;In short, &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; is a timeless masterpiece. It not only presents a compelling story and a well-built world at a time when these things were rare, but also develops it all through subtle, masterful writing, and introduces some ambitious concepts that make the SCP truly shine. Really, this could’ve been a lot worse; NekoChris could’ve just said “let’s just make it roll towards mirrors now” during his rewrite and left it at that. Who knows where this skip would be if that happened? But instead, NekoChris made something dazzling. NekoChris made a classic.&lt;/p&gt;

&lt;h2 id=&quot;parting-shots&quot;&gt;Parting Shots&lt;/h2&gt;

&lt;p&gt;Of course, this isn’t perfect. Some problems I noted:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There’s some Series 1 bits that I mentioned above. These slow the skip’s momentum and could be executed better.&lt;/li&gt;
  &lt;li&gt;The tone of the exploration logs is all over the place, and definitely could use a run-through for clinicality.&lt;/li&gt;
  &lt;li&gt;The last document comes across as an info-dump of sorts. I think that it could be spread more across the logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, what I came here to do is to figure out what &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; does right, and how we, as writers, can learn from it. Here’s some key takeaways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Don’t Show Your Entire Monster&lt;/strong&gt; - This is a weakness of the SCP Format: it often forces you to show the entirety of your monster up-front. But when you can, gradually reveal your monster to keep the reader guessing as to what it is.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Create Threading Mysteries&lt;/strong&gt; - Stuff like the mystery goo and the Unclean that recur are what trigger reactions out of the audience and keep them hooked.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Imagery&lt;/strong&gt; - With clinical tone, it’s hard to pull off imagery. But when you can, the pictures and worlds you can create are fabulous.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Don’t Overwhelm the Reader&lt;/strong&gt; - Using a “perspective character” can help to keep information flowing at an appropriate, but exciting pace.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Leave the story Open-Ended&lt;/strong&gt; - I see too many skips today that don’t leave anything up to speculation. This can be a great strength and helps to keep up the mystery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see a skip that takes these lessons from &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; and follows them to a T, look no further than &lt;a href=&quot;http://scp-wiki.wikidot.com/djkaktus&quot;&gt;djkaktus&lt;/a&gt;’ excellent &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-2935&quot;&gt;SCP-2935&lt;/a&gt;. It barely even lets the reader get a picture of the anomaly at first, it has a ton of recurring mysteries, the world is very fleshed out through imagery, the information is well-paced, and the ending is solid enough to be impactful but open enough to leave room for speculation.&lt;/p&gt;

&lt;p&gt;There are some other similarities too, like the log structure, the apocalyptic theme and how the ending is put together. I don’t know if this was an intentional homage to &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;, or if it was coincidental (the number 2&lt;strong&gt;93&lt;/strong&gt;5 points me towards the former conclusion), but it’s a good example of something that follows &lt;a href=&quot;https://scp-wiki.wikidot.com/scp-093&quot;&gt;SCP-093&lt;/a&gt;’s example.&lt;/p&gt;

&lt;p&gt;In conclusion, when we write today, instead of looking at older skips through our new-author-eyes, I think we should instead look at our newer skips through the eyes of the old authors. We can learn a lot from the tried-and-true older skips.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="analysis" /><category term="scp" /><summary type="html">SCP-093 is an absolute masterwork. Here’s why.</summary></entry><entry><title type="html">The rabbit hole of unsafe Rust bugs</title><link href="http://2023.notgull.net/cautionary-unsafe-tale/" rel="alternate" type="text/html" title="The rabbit hole of unsafe Rust bugs" /><published>2023-12-16T00:00:00+00:00</published><updated>2023-12-16T00:00:00+00:00</updated><id>http://2023.notgull.net/cautionary-unsafe-tale</id><content type="html" xml:base="http://2023.notgull.net/cautionary-unsafe-tale/">&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code is not only tricky to get right. It’s also tricky to track down when things go wrong.&lt;/p&gt;

&lt;p&gt;Here’s a question to ponder: do you think you are experienced enough at Rust to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code properly? If you asked me 24 hours ago, I would confidently say “yes, I am.” I would describe my Rust experience level as at least intermediate. On top of that, I have a little bit of an ego.&lt;/p&gt;

&lt;p&gt;In fact, I fully support using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; in libraries! Many times, there’s no other way to do something!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You’re communicating with a system API or C library. Although, for the former, I would recommend seeing if using &lt;a href=&quot;https://crates.io/crates/rustix&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustix&lt;/code&gt;&lt;/a&gt; or another system interface is an option.&lt;/li&gt;
  &lt;li&gt;You’re doing something that the borrow checker or type system can’t fully check your work on, even with workarounds like &lt;a href=&quot;https://doc.rust-lang.org/std/cell/struct.RefCell.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RefCell&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://doc.rust-lang.org/std/any/trait.Any.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Any&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;There’s just some performance boost that’s simply not possible without an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; workaround. I would strongly recommend benchmarking this claim before implementing it in a publicly used crate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While I’m not against &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt;, I am for &lt;em&gt;really&lt;/em&gt; checking and validating that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt;. You need to be making sure it’s doing what it needs to be doing, and that it’s doing that thing &lt;em&gt;right&lt;/em&gt;. The hazard with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; isn’t just that it can break your crate. It’s that it can break &lt;em&gt;other&lt;/em&gt; crates, in a way that’s very, very difficult to trace back to your original crate.&lt;/p&gt;

&lt;p&gt;You know how I said I had a chip on my shoulder? In the past week, I’ve had &lt;em&gt;two&lt;/em&gt; soundness errors reported. For the same crate, no less!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/smol-rs/event-listener/issues/100&quot;&gt;One of those soundness errors&lt;/a&gt; is a fairly routine linked list rigamarole with an associated discussions about public API. &lt;a href=&quot;https://github.com/smol-rs/event-listener/issues/99&quot;&gt;The other one&lt;/a&gt; is a frantic chase through several different crates, where things are never as they seem. This blog post focuses on the second one, as I find it more entertaining and maybe we can even shoehorn a moral in there somewhere.&lt;/p&gt;

&lt;p&gt;So let’s ask ourselves: what do we open ourselves up to when we add unchecked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; to our code.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I mention crates that are created by and maintained by other people in this post. They have done nothing wrong: all of the bugs were introduced by me, notgull. It should go without saying, but please do not seek out or harass these other people.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;event-listener-escapade&quot;&gt;Event Listener Escapade&lt;/h2&gt;

&lt;p&gt;Let’s introduce our cast of characters.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/event-listener&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;event-listener&lt;/code&gt;&lt;/a&gt; is a fairly primitive crate in the &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; ecosystem. It’s main responsibility is communications between tasks; it essentially handles the “if one thing happens in a task, wake up another task” use case. It’s used to implement &lt;a href=&quot;https://crates.io/crates/async-lock&quot;&gt;locks&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/async-channel&quot;&gt;channels&lt;/a&gt;, among other things.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/event-listener&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;event-listener&lt;/code&gt;&lt;/a&gt; also has a lot of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code. In my opinion, this is a good thing: it means that other crates that depend on it don’t need to have that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code for themselves. I’ll also be the first to admit that a lot of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code is unnecessary. Some of it exists because we’ve &lt;a href=&quot;https://github.com/smol-rs/event-listener/pull/42#issue-1460328393&quot;&gt;benchmarked it to be faster&lt;/a&gt;, and some of it exists because there isn’t really a better way to implement, say, &lt;a href=&quot;https://github.com/smol-rs/event-listener/blob/531c106f0ee27bf3fa7cf1bb0a621e46a1a4c9ed/src/no_std.rs#L816-L828&quot;&gt;a limited-contention spinlock&lt;/a&gt; in Safe Rust.&lt;/p&gt;

&lt;p&gt;A few days ago, one of our maintainers reported a bug. Most of the time, soundness bugs have a specific &lt;em&gt;flavor&lt;/em&gt;, like bitter licorice. This bug didn’t have that flavor, at first glance. It was like biting into the sweet apple of a simple off-by-one error, with an aftertaste of smooth, smooth WebAssembly. One fateful day, GitHub Actions started failing with a strange error.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ wasm-pack test --node --no-default-features --features portable-atomic
Running tests/notify.rs (target/wasm32-unknown-unknown/debug/deps/notify-0ef5209d8abd9615.wasm)
Set timeout to 20 seconds...
Executing bindgen...                              
                                                  
running 9 tests

panicked at /home/runner/work/event-listener/event-listener/src/no_std.rs:639:48:
index out of bounds: the len is 0 but the index is 4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/notgull/05755d15f1fd758590cd375d57a54b21&quot;&gt;Here&lt;/a&gt; is the full log, in case you want to try to take a crack at this bug for yourself.&lt;/p&gt;

&lt;h2 id=&quot;debugging-demonology&quot;&gt;Debugging Demonology&lt;/h2&gt;

&lt;p&gt;At first glance, I ran this code on my laptop and wasn’t able to replicate the issue.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;wasm-pack &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--node&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-default-features&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--features&lt;/span&gt; portable-atomic
&amp;lt;snip: tests pass&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I took one glance at the WASM bits and the &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt; feature and decided that it must be some kind of strange one-in-one-thousand race condition. It was a Thursday and I had work to do, so I decided to revisit it on the weekend. The weekend came and, after re-running the Actions workflow, the bugs were still there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Weird&lt;/em&gt;, I thought to myself. If it was a race condition, it shouldn’t be happening consistently. So I needed to take a closer look at what was happening here.&lt;/p&gt;

&lt;p&gt;While reading through the logs, I realized that the list that the out-of-bounds error was happening on was initialized like this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;/// Create a new, empty list.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;listeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;alloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sentinel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;snip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;irrelevant&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This list never has elements removed from it. It works a lot like the &lt;a href=&quot;https://crates.io/crates/slab&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slab&lt;/code&gt;&lt;/a&gt; crate does; it leaves those slots open for future entries to fill. Remember that “out of bounds” error?&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;index out of bounds: the len is 0 but the index is 4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;“len is 0”? The length of this list can only ever be one or more. So unless I’m accidentally calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remove()&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;truncate()&lt;/code&gt; on that list at some point, the length should never be zero.&lt;/p&gt;

&lt;p&gt;On top of that, I noticed this little detail in the logs as well, for another failed test:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;called `Result::unwrap()` on an `Err` value: Full(Notify { count: 1, is_additional: true })
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This operation results from a &lt;a href=&quot;https://docs.rs/concurrent-queue/latest/concurrent_queue/struct.ConcurrentQueue.html&quot;&gt;concurrent queue&lt;/a&gt; push operation, where the queue is initialized like this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;concurrent_queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;ConcurrentQueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unbounded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;snip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;irrelevant&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.rs/concurrent-queue/latest/concurrent_queue/struct.ConcurrentQueue.html#method.unbounded&quot;&gt;Unbounded&lt;/a&gt; queues can never be full. It doesn’t happen; they just allocate more memory to make room. At this point I curled my nose as the bitter aroma of memory corruption started to waft my way.&lt;/p&gt;

&lt;p&gt;“&lt;a href=&quot;https://github.com/smol-rs/event-listener/issues/99#issuecomment-1858872779&quot;&gt;Maybe it’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustc&lt;/code&gt; bug&lt;/a&gt;” I say to myself, still in the “denial” phase. I had to keep digging deeper; hopefully I can find the actual cause of the error and set up a minimal reproduction of it.&lt;/p&gt;

&lt;h2 id=&quot;damaged-dependencies&quot;&gt;Damaged Dependencies&lt;/h2&gt;

&lt;p&gt;At this point, it occurred to me that one of the differences between my machine and the Actions virtual machine is that I have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cargo.lock&lt;/code&gt; with some older dependencies in it. In most of my projects I don’t commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cargo.lock&lt;/code&gt; to Git, even though &lt;a href=&quot;https://blog.rust-lang.org/2023/08/29/committing-lockfiles.html&quot;&gt;it’s the default now&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I back up my current &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cargo.lock&lt;/code&gt; as a “last good state” (foreshadowing for later) and try the tests again.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ wasm-pack test --node --no-default-features --features portable-atomic
&amp;lt;snip: tests succeed&amp;gt;
$ cargo update
    Updating crates.io index
    Updating concurrent-queue v2.3.0 -&amp;gt; v2.4.0
    Updating crossbeam-utils v0.8.16 -&amp;gt; v0.8.17
    Updating futures-lite v2.0.1 -&amp;gt; v2.1.0
    Updating itoa v1.0.9 -&amp;gt; v1.0.10
    Updating js-sys v0.3.65 -&amp;gt; v0.3.66
    Updating libc v0.2.150 -&amp;gt; v0.2.151
    Updating once_cell v1.18.0 -&amp;gt; v1.19.0
    Updating portable-atomic v1.5.1 -&amp;gt; v1.6.0
    Updating proc-macro2 v1.0.69 -&amp;gt; v1.0.70
    Updating ryu v1.0.15 -&amp;gt; v1.0.16
    Updating serde v1.0.192 -&amp;gt; v1.0.193
    Updating serde_derive v1.0.192 -&amp;gt; v1.0.193
    Updating syn v2.0.39 -&amp;gt; v2.0.41
    Updating wasm-bindgen v0.2.88 -&amp;gt; v0.2.89
    Updating wasm-bindgen-backend v0.2.88 -&amp;gt; v0.2.89
    Updating wasm-bindgen-futures v0.4.38 -&amp;gt; v0.4.39
    Updating wasm-bindgen-macro v0.2.88 -&amp;gt; v0.2.89
    Updating wasm-bindgen-macro-support v0.2.88 -&amp;gt; v0.2.89
    Updating wasm-bindgen-shared v0.2.88 -&amp;gt; v0.2.89
    Updating wasm-bindgen-test v0.3.38 -&amp;gt; v0.3.39
    Updating wasm-bindgen-test-macro v0.3.38 -&amp;gt; v0.3.39
    Updating web-sys v0.3.65 -&amp;gt; v0.3.66
$ wasm-pack test --node --no-default-features --features portable-atomic
&amp;lt;snip: tests fail again&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;“Aha! It’s one of the dependencies!” I shout aloud to myself, fully aware no one is listening. “It’s not my fault!”&lt;/p&gt;

&lt;p&gt;Put yourself in my shoes for a second. It’s probably &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt;, right? I mean, the error only happens when &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt; support is enabled. It’s a crate that adds a polyfill for the &lt;a href=&quot;https://doc.rust-lang.org/core/sync/atomic/index.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;core::sync::atomic&lt;/code&gt;&lt;/a&gt; module that works on embedded platforms without atomics. It’s very thorough and has support for many different architectures and platforms. Since it has a lot of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt;, that makes it very easy to blame.&lt;/p&gt;

&lt;p&gt;So, let’s update it and see what happens.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cp Cargo.lock.old Cargo.lock
$ cargo update portable-atomic
    Updating crates.io index
    Updating portable-atomic v1.5.1 to v1.6.0
$ wasm-pack test --node --no-default-features --features portable-atomic
&amp;lt;snip: tests succeed&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The tests passed… I’m sorry, what?&lt;/p&gt;

&lt;p&gt;So it’s a dependency update… but not in &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt;? Weird, I guess I can run through the other dependencies we updated and see which one is the squeaky wheel. Let’s start with &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt;, it seems innocent enough.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cp Cargo.lock.old Cargo.lock
$ cargo update concurrent-queue
    Updating crates.io index
    Updating concurrent-queue v2.3.0 -&amp;gt; v2.4.0
$ wasm-pack test --node --no-default-features --features portable-atomic
&amp;lt;snip: tests fail&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point, I did a double take at my monitor. &lt;em&gt;What?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt; is a &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; crate that provides a queue that can be accessed concurrently. It’s significantly more efficient than having a &lt;a href=&quot;https://doc.rust-lang.org/std/sync/struct.Mutex.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mutex&lt;/code&gt;&lt;/a&gt; around a non-synchronous queue, especially when multiple threads are pushing to or reading from the queue. It also has a lot of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code which, under normal circumstances, I would be happy to blame.&lt;/p&gt;

&lt;p&gt;But, I was the one to push that update from v2.3.0 to v2.4.0. The only real change was &lt;a href=&quot;https://github.com/smol-rs/concurrent-queue/compare/v2.3.0...v2.4.0&quot;&gt;getting rid of a heap allocation&lt;/a&gt;. This didn’t add or remove any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code; it just moved some fields onto the stack instead of the heap… actually, it was still in the heap, since in &lt;a href=&quot;https://crates.io/crates/event-listener&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;event-listener&lt;/code&gt;&lt;/a&gt; the queue was wrapped with an &lt;a href=&quot;https://doc.rust-lang.org/std/sync/struct.Arc.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Arc&lt;/code&gt;&lt;/a&gt;, which allocates on the heap.&lt;/p&gt;

&lt;p&gt;Still, if you’re looking for someone to blame, &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt; seemed like it was caught red-handed. The build broke when I updated it, that was the smoking gun!&lt;/p&gt;

&lt;h2 id=&quot;goose-chase-gallery&quot;&gt;Goose Chase Gallery&lt;/h2&gt;

&lt;p&gt;My attention was piqued when I noticed that I’d forgotten to add WebAssembly tests for &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt;. If this was a &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt; issue, it would be hidden by these lack of tests. My suspicions were confirmed when I ran tests using &lt;a href=&quot;https://rustwasm.github.io/wasm-pack/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wasm-pack&lt;/code&gt;&lt;/a&gt; and saw that, yes, they were failing with &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt; being enabled.&lt;/p&gt;

&lt;p&gt;I began to settle in for the grueling task of reviewing atomics to make sure that all of the operations were correct. Especially for a crate as intricate as &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt;, this could take weeks. Except… let me check those tests again.&lt;/p&gt;

&lt;p&gt;Oh wait, the only tests that are failing are the ones that try to spawn threads. Of course they fail, you can’t spawn threads on WASM! Let’s mask those tests out, and..&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cq-checks-passed.png&quot; alt=&quot;The tests work&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wait, the tests work? Hey, how’s that possible?&lt;/p&gt;

&lt;p&gt;Maybe… maybe the leftover tests aren’t good enough. Yes, maybe the bug I’m looking for isn’t covered by these tests, so I need to write &lt;em&gt;more&lt;/em&gt; tests. So I need to finally figure out how web workers work. Then I’ll need to rewrite my tests, nay, my test &lt;em&gt;harness&lt;/em&gt;, to properly run all of these test cases?&lt;/p&gt;

&lt;p&gt;Alternatively, maybe we have the wrong guy.&lt;/p&gt;

&lt;h2 id=&quot;miri-magic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;miri&lt;/code&gt; Magic&lt;/h2&gt;

&lt;p&gt;Have you ever watched a police procedural? Usually, they play a trick on you in the middle of the episode. A crime happens, and after some detective work they find a guy who &lt;em&gt;looks like&lt;/em&gt; they did it. They have evidence! The smoking gun! But our protagonist, a rookie cop who’s flexible about his position on torturing civilians, doesn’t think they did it. But their completely reasonable qualms that might come up during trial are ignored by the rest of the police force. Then the protagonist confronts the &lt;em&gt;actual&lt;/em&gt; perpetrator, who’s usually some poorly developed background character, and brings him to justice.&lt;/p&gt;

&lt;p&gt;In this metaphor I’m the police force, and I thought I’d caught &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt; red-handed. But something didn’t sit right.&lt;/p&gt;

&lt;p&gt;Before I got too deep into &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt;’s innards, I realized something. In my CI, I wasn’t running &lt;a href=&quot;https://github.com/rust-lang/miri&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;miri&lt;/code&gt;&lt;/a&gt; tests for the case where &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt; was enabled. This meant that, if this &lt;em&gt;was&lt;/em&gt; a memory corruption error, it wasn’t being caught by &lt;a href=&quot;https://github.com/rust-lang/miri&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;miri&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This introduced a thought into my head for the first time, a thought I should’ve had three days ago. &lt;em&gt;Maybe it isn’t strictly a WASM issue?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So I ran &lt;a href=&quot;https://github.com/rust-lang/miri&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;miri&lt;/code&gt;&lt;/a&gt; with &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt; support, and sure enough:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cargo miri &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-default-features&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--features&lt;/span&gt; portable-atomic &lt;span class=&quot;nt&quot;&gt;--tests&lt;/span&gt;

&amp;lt;snip: miri noise&amp;gt;

&lt;span class=&quot;nb&quot;&gt;test &lt;/span&gt;drop_non_notified ... error: Undefined Behavior: constructing invalid value: encountered an unaligned reference &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;required 128 byte alignment but found 16&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /home/jtnunley/.rustup/toolchains/nightly-x86_64-unknown-linux-musl/lib/rustlib/src/rust/library/core/src/ptr/mut_ptr.rs:367:57
    |
367 |         &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;self.is_null&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; None &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; unsafe &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; Some&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&amp;amp;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;self&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    |                                                         ^^^^^^ constructing invalid value: encountered an unaligned reference &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;required 128 byte alignment but found 16&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    |
    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;: this indicates a bug &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the program: it performed an invalid operation, and caused Undefined Behavior
    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;further information
    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; note: BACKTRACE:
    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; note: inside &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;std::ptr::mut_ptr::&amp;lt;impl &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;mut event_listener::Inner&amp;lt;&lt;span class=&quot;o&quot;&gt;()&amp;gt;&amp;gt;&lt;/span&gt;::as_ref::&amp;lt;&lt;span class=&quot;s1&quot;&gt;&apos;_&amp;gt;` at /home/jtnunley/.rustup/toolchains/nightly-x86_64-unknown-linux-musl/lib/rustlib/src/rust/library/core/src/ptr/mut_ptr.rs:367:57: 367:63
note: inside `event_listener::Event::try_inner`
   --&amp;gt; /home/jtnunley/Projects/smol-rs/event-listener/src/lib.rs:443:18
    |
443 |         unsafe { inner.as_ref() }
    |                  ^^^^^^^^^^^^^^
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Specifically, I noticed this error:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;required 128 byte alignment but found 16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What this is telling me is that we are trying to dereference a pointer that isn’t properly aligned. So, where is this pointer coming from?&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;/// Return a reference to the inner state if it has been initialized.&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;#[inline]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;try_inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Inner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.inner&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Ordering&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Okay, this is just the pointer we’re storing in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self.inner&lt;/code&gt; atomic variable. How are we calculating that pointer?&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Allocate the state on the heap.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Arc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Convert the state to a raw pointer.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Arc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;into_raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Inner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Replace the null pointer with the new state pointer.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;inner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;.inner&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.compare_exchange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Ordering&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AcqRel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Ordering&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.unwrap_or_else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inner&lt;/code&gt; is just the return value of an &lt;a href=&quot;https://doc.rust-lang.org/std/sync/struct.Arc.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Arc&lt;/code&gt;&lt;/a&gt; allocation? Weird. The standard library’s types are usually pretty well-tested. Not to mention, I’m sure that other programs make use of dereferencing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;into_raw&lt;/code&gt; too, and they would have seen this error before me right now. Let me check my imports…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Oh no.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;#[cfg(feature&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;portable-atomic&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;portable_atomic_util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Arc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Oh no.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;arc-apocalypse&quot;&gt;Arc Apocalypse&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/portable-atomic-util&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic-util&lt;/code&gt;&lt;/a&gt; is a sort of “side crate” to &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt;. It’s where you put things that are too specific to be put in &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt;, but are probably still useful.&lt;/p&gt;

&lt;p&gt;One of the tools in &lt;a href=&quot;https://crates.io/crates/portable-atomic-util&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic-util&lt;/code&gt;&lt;/a&gt; is an implementation of &lt;a href=&quot;https://docs.rs/portable-atomic-util/latest/portable_atomic_util/struct.Arc.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Arc&lt;/code&gt;&lt;/a&gt;. It’s similar to the one in the standard library, but instead of using atomics from the standard library it uses &lt;a href=&quot;https://crates.io/crates/portable-atomic&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic&lt;/code&gt;&lt;/a&gt;. Unfortunately it’s not a 1:1 copy of the one from the standard library, as the standard library makes use of unstable features that can’t be used from normal library crates.&lt;/p&gt;

&lt;p&gt;So, let’s take a look at its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;into_raw&lt;/code&gt; implementation. It looks a little like this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// The inner heap allocation of an `Arc`.&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;#[repr(C)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Shared&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sized&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;/// The reference count of the `Arc`.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;/// The value that is being reference counted.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Arc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;#[must_use]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;as_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Get the raw pointer.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.shared&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;// Add the size of the header so that it points to the value.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;size_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;// Cast the pointer to the correct type.&lt;/span&gt;
        &lt;span class=&quot;nn&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_metadata_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.shared&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s pretty simple. Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shared&lt;/code&gt; pointer points to an instance of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Shared&lt;/code&gt; structure on the heap, and we want it to point to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; field. That way, when the user dereferences the pointer, they get the underlying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately we can’t use &lt;a href=&quot;https://doc.rust-lang.org/std/ptr/macro.addr_of.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addr_of_mut&lt;/code&gt;&lt;/a&gt; like the standard library yet. It’s stable, but &lt;a href=&quot;https://crates.io/crates/portable-atomic-util&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic-util&lt;/code&gt;&lt;/a&gt;’s &lt;a href=&quot;https://github.com/foresterre/cargo-msrv&quot;&gt;MSRV&lt;/a&gt; is lower than the version where it was introduced. So we do the math manually. The value will be after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header&lt;/code&gt;, so just add the size of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header&lt;/code&gt; to get the pointer. Right?&lt;/p&gt;

&lt;p&gt;Wrong.&lt;/p&gt;

&lt;p&gt;What the author of this code failed to consider is &lt;em&gt;alignment&lt;/em&gt;. A lot of structures need to have their address be a multiple of a certain number, usually the size of their largest field. The reasons for this are related to the underlying CPU architectures and I can’t really get into that. This article is looking pretty long as it is.&lt;/p&gt;

&lt;p&gt;However, the &lt;a href=&quot;https://docs.rs/concurrent-queue/latest/concurrent_queue/struct.ConcurrentQueue.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConcurrentQueue&lt;/code&gt;&lt;/a&gt; type has an alignment of 128. This is related to how cache lines are implemented on the x86 architecture. When you have frequently changed atomic data, you want to put in a separate cache line than other data. That way, the processor won’t need to reload that other data too frequently. No, we &lt;em&gt;really&lt;/em&gt; don’t have time.&lt;/p&gt;

&lt;p&gt;So, it is possible for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Shared&lt;/code&gt; above to be laid out with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header&lt;/code&gt; at the start, then have some number of padding bytes before the actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; field. This means that the pointer addition from above is now pointing into padding, rather than the actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; value. &lt;em&gt;That&lt;/em&gt; explains the memory corruption.&lt;/p&gt;

&lt;p&gt;It also explains why it’s only started to cause undefined behavior now. In v2.3.0 of &lt;a href=&quot;https://docs.rs/concurrent-queue/latest/concurrent_queue/struct.ConcurrentQueue.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConcurrentQueue&lt;/code&gt;&lt;/a&gt;, the data with an alignment of 128 was stored inside of a heap allocation. Since heap allocations have an alignment of the platform word size (in the case of 64-bit architectures, 8), there was no padding between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; here. It was only when that heap allocation was removed and the alignment was increased that this problem appeared.&lt;/p&gt;

&lt;p&gt;Say, who wrote this code? I’ll need to find them and give them a piece of my mind. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git blame&lt;/code&gt; can tell us who, exactly, is responsible for this mess.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/blame-pa.png&quot; alt=&quot;It was me all along&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Egads! It was me all along!&lt;/p&gt;

&lt;p&gt;This bug is no longer in &lt;a href=&quot;https://crates.io/crates/portable-atomic-util&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic-util&lt;/code&gt;&lt;/a&gt;. I &lt;a href=&quot;https://github.com/taiki-e/portable-atomic/pull/138&quot;&gt;filed a PR&lt;/a&gt; which has now been merged, and the versions of &lt;a href=&quot;https://crates.io/crates/portable-atomic-util&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic-util&lt;/code&gt;&lt;/a&gt; with that bug have been yanked from &lt;a href=&quot;https://crates.io&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crates.io&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To come full-circle, let’s see if our tests work with the newest version of &lt;a href=&quot;https://crates.io/crates/portable-atomic-util&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portable-atomic-util&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;wasm-pack &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--node&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-default-features&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--features&lt;/span&gt; portable-atomic
&amp;lt;snip: tests succeed&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Awesome!&lt;/p&gt;

&lt;h2 id=&quot;parting-shots&quot;&gt;Parting Shots&lt;/h2&gt;

&lt;p&gt;So, what’s my conclusion? What did we learn from this little escapade?&lt;/p&gt;

&lt;p&gt;I’d like to bring your attention to the source of the original soundness bug.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;#[must_use]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;as_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Get the raw pointer.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.shared&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Add the size of the header so that it points to the value.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;size_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Cast the pointer to the correct type.&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_metadata_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.shared&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Eagle-eyed readers might have noticed that this code &lt;em&gt;has no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt;&lt;/em&gt;. Not even a line. Sure, it does some risky pointer math, but that’s considered safe in Rust.&lt;/p&gt;

&lt;p&gt;Also, keep in mind that &lt;a href=&quot;https://crates.io/crates/concurrent-queue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concurrent-queue&lt;/code&gt;&lt;/a&gt; had no bugs introduced either. It just changed the alignment of a structure from 8 to 128. That can be done in safe Rust; hell, it isn’t even a minor change according to &lt;a href=&quot;https://semver.org/&quot;&gt;SemVer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code that caused this unsoundness.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;#[inline]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;try_inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Inner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.inner&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Ordering&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s not unsound; it’s not even incorrect. This code was checked, audited and did everything that it was supposed to do. It was a combination of two pieces of 100% safe code from another crate that caused this bug to happen.&lt;/p&gt;

&lt;p&gt;When I begun this article, I talked about how you need to check your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code. What I wanted to prove is that you can’t &lt;em&gt;just&lt;/em&gt; check your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code. You need to check each and every line of safe code too. &lt;a href=&quot;https://doc.rust-lang.org/nomicon/working-with-unsafe.html&quot;&gt;Safety is non-local&lt;/a&gt;, and a bug in safe code can easily cause unsound behavior in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; code if you’re not careful.&lt;/p&gt;

&lt;p&gt;For me, I’m going to be extra careful when I write new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; logic. I advise that you do the same.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="async" /><category term="bug" /><category term="rust" /><category term="smol" /><summary type="html">unsafe code is not only tricky to get right. It’s also tricky to track down when things go wrong.</summary></entry><entry><title type="html">Evaluating new software forges</title><link href="http://2023.notgull.net/finding-a-forge/" rel="alternate" type="text/html" title="Evaluating new software forges" /><published>2023-12-15T00:00:00+00:00</published><updated>2023-12-15T00:00:00+00:00</updated><id>http://2023.notgull.net/finding-a-forge</id><content type="html" xml:base="http://2023.notgull.net/finding-a-forge/">&lt;p&gt;What options &lt;em&gt;are&lt;/em&gt; there other than &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Oh boy, I sure do love contributing to open source software on the largest software forge in the world! I hope they haven’t started down the slow and painful process of &lt;a href=&quot;https://en.wikipedia.org/wiki/Enshittification&quot;&gt;enshittification&lt;/a&gt; by following vague, ill-defined industry trends!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/github-home.png&quot; alt=&quot;[GitHub]&apos;s home page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wait, what’s that? Computer! Enhance!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/github-ai.png&quot; alt=&quot;The same image but zoomed in on AI&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well, I guess I’m ready to find a new forge!&lt;/p&gt;

&lt;h2 id=&quot;software-host-hellscape&quot;&gt;Software Host Hellscape&lt;/h2&gt;

&lt;p&gt;In all seriousness, I’ve been looking to move off of &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; for a while now. Let me be clear, &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; is still far and away the best website for open source discovery. Not to mention, its CI offerings are very nice, especially for something free. Yes, there are better paid CI offerings, but for something that costs zero dollars I’ve found it incredibly useful.&lt;/p&gt;

&lt;p&gt;However, one thing has made me skeptical of &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; is its “&lt;a href=&quot;https://github.com/features/copilot&quot;&gt;Copilot&lt;/a&gt;” offering. I’ll admit, I was in the beta program for Copilot, and found it really neat. Being able to write large amounts of code from small comments was very nice, even if it was really bad practice.&lt;/p&gt;

&lt;p&gt;Then I found out it was &lt;a href=&quot;https://www.zdnet.com/article/is-github-copilots-code-legal-ethically-right/&quot;&gt;training on GPL-licensed data&lt;/a&gt;, which left a pretty bad taste in my mouth. In addition to the fact that I’m increasingly uncomfortable with hosting my free software on a closed source forge, run by Microsoft.&lt;/p&gt;

&lt;p&gt;Let’s take a look at everybody else.&lt;/p&gt;

&lt;h2 id=&quot;gitlab-gauss&quot;&gt;GitLab Gauss&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://about.gitlab.com/&quot;&gt;GitLab&lt;/a&gt; is the original &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; competitor. The Linux to Microsoft’s Windows, or the MariaDB to Oracle’s MySQL. This has made it the most popular &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; competitor by far, by virtue of people vocally quitting &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; in favor of [GitLab].&lt;/p&gt;

&lt;p&gt;Unfortunately, I didn’t really consider GitLab when I was finding a place to move. First of all, &lt;a href=&quot;https://about.gitlab.com/blog/2016/07/20/gitlab-is-open-core-github-is-closed-source/&quot;&gt;they aren’t actually open source&lt;/a&gt;. They’re “open core”, which, I admit, is better than closed source. However, like I said, I’m uncomfortable building free software on infrastructure that isn’t.&lt;/p&gt;

&lt;p&gt;I know I can download GitLab and set it up on my own server. However, I’m a software developer, not a sysadmin. I want to spend my time developing software, not putting out fires and paying AWS bills for the rest of time.&lt;/p&gt;

&lt;p&gt;Also, GitLab has adopted the unfortunate strategy of “following along with whatever &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; does”. They’ve tried to jump onto the bandwagon so frequently, they’ve gotten splinters. For instance, what happens when we check their homepage?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/gitlab-home.png&quot; alt=&quot;GitLab&apos;s home page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Computer! Do the thing again!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/gitlab-ai.png&quot; alt=&quot;Same image but with &amp;quot;AI&amp;quot; zoomed in&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Good golly, it’s even the same wording! Yeah, I’ll pass.&lt;/p&gt;

&lt;h2 id=&quot;sourcehut-scramble&quot;&gt;&lt;a href=&quot;https://sr.ht&quot;&gt;SourceHut&lt;/a&gt; Scramble&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://sr.ht&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sr.ht&lt;/code&gt;&lt;/a&gt; takes the opposite approach as GitLab. Instead of trying to follow along with &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;’s trends, it’s elected to do go in the other direction. Whenever &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; does something, &lt;a href=&quot;https://sr.ht&quot;&gt;SourceHut&lt;/a&gt; does the exact opposite.&lt;/p&gt;

&lt;p&gt;Pull requests? Too centralized, let’s construct a suitable code contribution system around email. Discussion? Why not IRC, it’s been around since the Bronze Age. Get rid of Mercurial support? Not interested.&lt;/p&gt;

&lt;p&gt;I really like &lt;a href=&quot;https://sr.ht&quot;&gt;SourceHut&lt;/a&gt;. When you go to their homepage, they’re not showing off their fancy CSS effects or telling you about their AI offerings. They give you a simple user interface and some of the projects they host.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/sourcehut-home.png&quot; alt=&quot;sr.ht&apos;s homepage&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There was also much to impress me. Their CI offerings are better than &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;, which alone justified me paying the humble $2/month price tag. Rather than needing a complicated YAML file to run a CI system, it’s just cloning Git repos and running commands. It’s delightfully simple yet powerful. Having native BSD and Plan9 runners doesn’t quite make up for its inability to run Windows, but I’m sure I can work around that.&lt;/p&gt;

&lt;p&gt;Not to mention, &lt;a href=&quot;https://sr.ht&quot;&gt;SourceHut&lt;/a&gt; has the &lt;em&gt;second&lt;/em&gt; best repository discovery system. When I go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sr.ht&lt;/code&gt;’s “explore” tab, I’m immediately greeted by a slew of interesting projects. Whether it’s a &lt;a href=&quot;https://git.sr.ht/~crc_/retroforth&quot;&gt;powerful Forth dialect&lt;/a&gt; that brings a lot of genuinely exciting ideas to the table, or a &lt;a href=&quot;https://sr.ht/~mcf/cproc/&quot;&gt;tiny C11 compiler&lt;/a&gt; written in simple ANSI C, I’m always amazed whenever I open up that tab.&lt;/p&gt;

&lt;p&gt;I liked it so much that &lt;a href=&quot;https://hachyderm.io/@notgull/111207497257139313&quot;&gt;I announced that I was moving my personal projects to SourceHut&lt;/a&gt;. However, after moving my &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; project to &lt;a href=&quot;https://sr.ht&quot;&gt;SourceHut&lt;/a&gt;, I found myself dissatisfied with a few things.&lt;/p&gt;

&lt;p&gt;For one, the email-based workflow was a lot clunkier than I expected. In theory, building code contribution on top of a standard protocol that’s been around since the 60’s sounds like a good idea. In practice, it’s &lt;a href=&quot;https://social.treehouse.systems/@marcan/109863991681394714&quot;&gt;a lot clunkier&lt;/a&gt; than you’d expect, especially since most modern email clients are simply not built to read and write code.&lt;/p&gt;

&lt;p&gt;After trying it for myself I can see that it might turn off a lot of people from contributing. I’m already losing a lot of potential contributors by moving off of &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;. I don’t need those remaining contributors to also be turned off by a workflow completely different than what they’re probably used to.&lt;/p&gt;

&lt;p&gt;Still, I can imagine this workflow working for many people, especially ones who already have a decent setup for email-based projects like Linux.&lt;/p&gt;

&lt;h2 id=&quot;codeberg&quot;&gt;Codeberg&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://codeberg.org&quot;&gt;Codeberg&lt;/a&gt; is a public instance of &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt;, which is in turn a fork of &lt;a href=&quot;https://about.gitea.com/&quot;&gt;Gitea&lt;/a&gt;. It’s got a pretty nice interface similar enough to &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;’s. It’s got the familiar pull-request-based contribution interface. The CI is &lt;em&gt;good enough&lt;/em&gt;, I suppose. Docker containers aren’t the best CI environment, but I can certainly think of worse.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/codeberg-home.png&quot; alt=&quot;Codeberg&apos;s home page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So what’s not to like?&lt;/p&gt;

&lt;p&gt;My main problem is that &lt;a href=&quot;https://codeberg.org&quot;&gt;Codeberg&lt;/a&gt; has a very limited CI capacity, and I have a lot of projects that require significant testing. &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt;, for instance, requires these things to be tested:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Make sure it compiles on Windows, Mac, Linux, WASM, Redox, and whatever oblique platform people run Rust on nowadays.&lt;/li&gt;
  &lt;li&gt;Check the various different backends that &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; supports: pure software rendering, &lt;a href=&quot;https://crates.io/crates/wgpu&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wgpu&lt;/code&gt;&lt;/a&gt; and OpenGL. Not to mention all of the different interfaces to OpenGL, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wgl&lt;/code&gt;, GLX, EGL…&lt;/li&gt;
  &lt;li&gt;Check formatting and linting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…which doesn’t even cover testing. For rendering frameworks like &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt;, you want to have some pre-defined rendering programs that render your code to images. That way, you can regenerate these images and compare against an existing set of images in order to check for regressions.&lt;/p&gt;

&lt;p&gt;This isn’t a practical concern, although it really should be. It’s a moral concern. You have an organization like &lt;a href=&quot;https://codeberg.org&quot;&gt;Codeberg&lt;/a&gt;, donating a significant amount of time and resources to try to make a positive difference in the world of software. Now, here I am, sucking up all of those compute resources for my insignificant little projects.&lt;/p&gt;

&lt;p&gt;Of course, while pondering this moral concern, I realized that I’ve locked myself into a &lt;a href=&quot;https://en.wikipedia.org/wiki/Catch-22_(logic)&quot;&gt;Catch-22&lt;/a&gt;. I can’t use any independent project’s CI because of my concerns that I would drain too many of their resources. On the other hand, I can’t use any large company’s CI because I don’t want to host my project with a large company. I can’t self host, because that would be a pain.&lt;/p&gt;

&lt;p&gt;Would it?&lt;/p&gt;

&lt;h2 id=&quot;self-hosting-gitea&quot;&gt;Self-Hosting Gitea&lt;/h2&gt;

&lt;p&gt;I said I didn’t want to self-host. I worked in IT for two years, so I’ve already gotten my fill of fighting with both servers and people.&lt;/p&gt;

&lt;p&gt;However, in a Discord I’m in, an acquaintance of mine talked about how they set up &lt;a href=&quot;https://about.gitea.com/&quot;&gt;Gitea&lt;/a&gt; and &lt;a href=&quot;https://www.drone.io/&quot;&gt;Drone&lt;/a&gt; CI on a school Kubernetes cluster they had access to. I mentioned my predicaments in finding a forge service, and they said that it was only two configuration files.&lt;/p&gt;

&lt;p&gt;That tempted me. Not enough to deal with the absolute nightmare that is Kubernetes, but enough for me to rent out a couple of &lt;a href=&quot;https://en.wikipedia.org/wiki/Timeline_of_Amazon_Web_Services&quot;&gt;Lightsail&lt;/a&gt; servers to experiment.&lt;/p&gt;

&lt;p&gt;I’d like to say that I set up the entire thing in a weekend, but it wasn’t that simple. Sure, it was easy enough to install &lt;a href=&quot;https://about.gitea.com/&quot;&gt;Gitea&lt;/a&gt; and &lt;a href=&quot;https://www.drone.io/&quot;&gt;Drone&lt;/a&gt; in Docker containers. Sure, it wasn’t too hard after that to set up my DNS records to forward &lt;a href=&quot;https://src.2023.notgull.net&quot;&gt;src.2023.notgull.net&lt;/a&gt; to that new serer. Yeah, it’s probably hacky to set up my CI system on a public cloud, but as long as I keep people from abusing it that aren’t me it shouldn’t be &lt;em&gt;too&lt;/em&gt; bad, right?&lt;/p&gt;

&lt;p&gt;Of course, I forget my crucial weakness: my perfectionism. Sure, my site looks pretty good… but it looks a bit ugly. Let’s play around with themes for three days until I find one I like. Oh, the logo doesn’t look good with my new theme. Let’s convert the MS paint drawing I call my avatar into SVG and then set it up to be this site’s logo. Oh, Gitea has a weird templating system; let’s compile it from scratch!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/srcnotgull-home.png&quot; alt=&quot;src.2023.notgull.net home&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At the end of this week(!)long process, I had a somewhat functional &lt;a href=&quot;https://src.2023.notgull.net&quot;&gt;Git forge&lt;/a&gt;, with the following features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A decent Linux &lt;a href=&quot;https://www.drone.io/&quot;&gt;Drone&lt;/a&gt; CI setup.&lt;/li&gt;
  &lt;li&gt;A &lt;a href=&quot;https://docs.renovatebot.com/&quot;&gt;Dependabot clone&lt;/a&gt; for automatic updates.&lt;/li&gt;
  &lt;li&gt;A system that allows everyone to create an account and open issues, but doesn’t allow people to create repos or mess with the CI.
    &lt;ul&gt;
      &lt;li&gt;If you want to create a repo for PR’s sake, email me at dev at notgull dot net and I can set you up.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A mirror to &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;, so I can still take advantage of their code discovery.
    &lt;ul&gt;
      &lt;li&gt;Yeah yeah, I know, but keeping an arm’s length from &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; is a win in my book.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve uploaded a lot of my code to there, and it seems to be working well so far. I have to admit, it is somewhat liberating to have full control of how your code is forged.&lt;/p&gt;

&lt;h2 id=&quot;parting-shots&quot;&gt;Parting Shots&lt;/h2&gt;

&lt;p&gt;I still consider this to be in the “experimental” stage. If it ends up being too inconvenient or too expensive, I’ll probably move it somewhere else. Still, having my own space for code that I can do whatever I want with is very nice. Let’s hope it keeps working well and this blog post doesn’t age like milk.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;All photos are from public websites and fall under free use, as this is a review.&lt;/p&gt;
&lt;/blockquote&gt;</content><author><name>John Nunley</name></author><category term="rust" /><summary type="html">What options are there other than GitHub?</summary></entry><entry><title type="html">My new, remote-access Rust development setup</title><link href="http://2023.notgull.net/remote-setup/" rel="alternate" type="text/html" title="My new, remote-access Rust development setup" /><published>2023-11-12T00:00:00+00:00</published><updated>2023-11-12T00:00:00+00:00</updated><id>http://2023.notgull.net/remote-setup</id><content type="html" xml:base="http://2023.notgull.net/remote-setup/">&lt;p&gt;I’ve set up a new system for Rust development work.&lt;/p&gt;

&lt;p&gt;I work on quite a few crates in the Rust ecosystem. Since I started taking Rust seriously back in 2021, I’ve been using the same laptop that I’ve used since high school.&lt;/p&gt;

&lt;p&gt;It’s actually a pretty beefy laptop, all things considered. It has an i5 CPU and 16 GB of RAM. It ran Ubuntu for the majority of its life but now runs Alpine Linux. These stats were definitely overkill for a high schooler playing around with Python. Even now, it still works with smaller codebases. Honestly, it’s an exceptionally first world problem to even be complaining about.&lt;/p&gt;

&lt;p&gt;However, I’ve started to hit the limits of this computer. 16 gigabytes of RAM is a lot when you’re dealing with codebases like &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;. Even if you put all of &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;’s subcrates together, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rust-analyzer&lt;/code&gt; barely uses up four gigabytes.&lt;/p&gt;

&lt;p&gt;However, lately I’ve been working on codebases that overflow my limits. &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt; is a medium-sized codebase at around 25KB lines, but with all of the dependencies it makes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rust-analyzer&lt;/code&gt; slow to a crawl. &lt;a href=&quot;https://crates.io/crates/x11rb&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x11rb&lt;/code&gt;&lt;/a&gt; has a lot of automatically generated code; I’ve actually experienced a kernel panic because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rust-analyzer&lt;/code&gt; took up all of my memory processing &lt;a href=&quot;https://crates.io/crates/x11rb&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x11rb&lt;/code&gt;&lt;/a&gt;, including an additional 16 gigabytes of swap space.&lt;/p&gt;

&lt;p&gt;Not to mention, once my laptop touches swap space, it might as well be over. Memory access slows to a crawl, and the latency between my thoughts and my applications might as well be dial-up.&lt;/p&gt;

&lt;h1 id=&quot;time-for-an-upgrade&quot;&gt;Time for an Upgrade&lt;/h1&gt;

&lt;p&gt;Since I started this blog in March of this year, I’ve managed to trick a company into giving me money in exchange for writing code for them. Around Prime Day, I decided to burn a paycheck on an upgrade.&lt;/p&gt;

&lt;p&gt;My goal was to build a server that I can access remotely. I move around a lot; I like to write code at various hackerspaces and coffee shops around the city. It’s a nice, social environment where I can talk to (or at least be around) people while I code. I’m already an introvert, so I don’t want to be cooped up inside if I want access to serious computing power.&lt;/p&gt;

&lt;p&gt;The remaining goal was absolute overkill. I don’t want to have to upgrade this machine for the forseeable future. Therefore, I’m going all-out on hardware and software.&lt;/p&gt;

&lt;h1 id=&quot;the-hardware-specs-section&quot;&gt;The Hardware Specs Section&lt;/h1&gt;

&lt;p&gt;I built this computer around the &lt;a href=&quot;https://www.amd.com/en/products/cpu/amd-ryzen-9-5950x&quot;&gt;AMD Ryzen 9 5950x&lt;/a&gt; processor. It was half-off for Prime Day, which is what prompted this entire process. It has 32 cores and is reasonably fast. I’m aware I could go higher, but I don’t want to break my bank account for something I’m not being paid for.&lt;/p&gt;

&lt;p&gt;Don’t get me wrong; my laptop’s CPU was already good enough for my use case. With Rust’s incremental builds, I very rarely spend more than a few seconds waiting for feedback from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rust-analyzer&lt;/code&gt;. Still, from-scratch compiles took a few minutes, especially for larger crates.&lt;/p&gt;

&lt;p&gt;With 32 cores, I can easily parallelize crate builds. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo install ripgrep&lt;/code&gt; completes in less than a minute. Combined with an absolutely overkill 128 gigabytes of RAM, I can build any crate I want to in record time.&lt;/p&gt;

&lt;p&gt;My workload isn’t GPU intensive, so I grabbed an &lt;a href=&quot;https://www.amd.com/en/support/graphics/radeon-500-series/radeon-rx-500x-series/radeon-rx-570x&quot;&gt;AMD Radeon 570x&lt;/a&gt; to use as a GPU to tie the build together. I combined this with an ASRock motherboard, a CoolerMaster chassis and liquid-cooling system, and a 4TB SSD to tie the rest of the computer together. The end result is a system that I don’t intend to use directly, but will be very nice to use remotely.&lt;/p&gt;

&lt;h1 id=&quot;putting-it-all-together&quot;&gt;Putting It All Together&lt;/h1&gt;

&lt;p&gt;I’d like to muse briefly on putting this computer together. I’ve never actually built a computer before. Usually, when I’m in need of a new computer, I don’t have time to go through the process of figuring out which parts go where. So I’ve only used prebuilt systems until now.&lt;/p&gt;

&lt;p&gt;I’ve heard from some people that putting together a PC is like building Legos. While this is true in some respects, keep in mind that these are 2000 dollar legos, where in some cases it might be unclear what part goes where. This leads to a lot of stress; especially around installing the CPU. One bent pin means that you have to throw out the CPU.&lt;/p&gt;

&lt;p&gt;Thankfully, on attempt number three, my friend and I successfully managed to put the CPU in the socket and install the liquid-cooling system. Everything else screwed into place relatively easily. The motherboard goes into the chassis, and everything hooks into the motherboard from there.&lt;/p&gt;

&lt;p&gt;However, I made two crucial mistakes. First, I ordered a 3U chassis where I actually needed a 4U chassis. I also needed a 750W power supply instead of the 500 W one I originally calculated I needed. Amazon has a decent return policy, so I was able to return those parts and get the ones I actually need.&lt;/p&gt;

&lt;p&gt;Finally, after putting it all together, it refused to boot! We thought we’d installed the CPU wrong. After crawling over the manuals and forums for the motherboard a few times, we figured out that e needed to plug in a keybard. Weird. Anyways, one Alpine Linux install later, I had a working PC.&lt;/p&gt;

&lt;h1 id=&quot;utilizing-the-system&quot;&gt;Utilizing the System&lt;/h1&gt;

&lt;p&gt;I’ve set up this PC in the attic. Thankfully, the liquid cooling is quiet enough so that I don’t hear it when I’m trying to sleep.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/remote-setup.jpeg&quot; alt=&quot;setup in the attic&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now, I want to be able to access this from anywhere. Like I said, I want to be able to use this computer like I’m sitting down at it, even if I might be across the country. Originally, I was going to set up an SSH tunnel between my laptop and this server, using an AWS Lightsail instance as an intermediary.&lt;/p&gt;

&lt;p&gt;However, then I found out about &lt;a href=&quot;https://tailscale.com/&quot;&gt;Tailscale&lt;/a&gt; (not sponsored), which fit my use case much better.&lt;/p&gt;

&lt;p&gt;So, I’ve scaled my tail. I’ve hooked up my new server, my phone and my laptop to a tailnet. SSH is a breeze and setting up other services is a cinch as well.&lt;/p&gt;

&lt;p&gt;I’ve been getting used to &lt;a href=&quot;https://github.com/coder/code-server&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code-server&lt;/code&gt;&lt;/a&gt;. In fact, I’m writing this in there right now! I’ve tried to get used to Neovim and Emacs and other editors like that. However, I’m just too used to the VS Code workflow at this point, especially since using it for work. Generally, I don’t notice a difference between &lt;a href=&quot;https://github.com/coder/code-server&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code-server&lt;/code&gt;&lt;/a&gt;’s interface and VS-Code.&lt;/p&gt;

&lt;h1 id=&quot;desktop-dismay&quot;&gt;Desktop Dismay&lt;/h1&gt;

&lt;p&gt;However, there is one cinch. When testing out &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt;, I need direct GUI access. Remote X11 just won’t cut it, especially for rendering.&lt;/p&gt;

&lt;p&gt;I’ve installed a VNC server on my server, and I can just tab over to my VNC client whenever I need to run a GUI application. Still, it’s a somewhat awkward workflow. I’m open to new ideas.&lt;/p&gt;

&lt;h1 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h1&gt;

&lt;p&gt;There isn’t a moral to this story, I just wanted to talk about my new remote workflow. I hope this overview inspires similar remote flows in the future.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="hardware" /><category term="gui" /><category term="rust" /><summary type="html">I’ve set up a new system for Rust development work.</summary></entry><entry><title type="html">Recreating concurrent futures combinators in smol</title><link href="http://2023.notgull.net/futures-concurrency-in-smol/" rel="alternate" type="text/html" title="Recreating concurrent futures combinators in smol" /><published>2023-10-22T00:00:00+00:00</published><updated>2023-10-22T00:00:00+00:00</updated><id>http://2023.notgull.net/futures-concurrency-in-smol</id><content type="html" xml:base="http://2023.notgull.net/futures-concurrency-in-smol/">&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/futures&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures&lt;/code&gt;&lt;/a&gt; comes with many additional combinators that &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; doesn’t have 
out of the box. We can rebuild them, better.&lt;/p&gt;

&lt;p&gt;Whew, it’s almost been a month since my last blogpost here. This was because I
was spending time doing research and testing, and not because I lost the PGP key
that allows me to upload to this site. No sir, how could anyone be that
irresponsible?&lt;/p&gt;

&lt;p&gt;…or maybe I was just using the PGP key as an excuse not to write? It’s not
like I’m being paid to psychoanalyze myself in front of you people.&lt;/p&gt;

&lt;p&gt;It doesn’t matter, we’re back! Let’s talk about &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-problem-with-futures&quot;&gt;The Problem with &lt;a href=&quot;https://crates.io/crates/futures&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/futures&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures&lt;/code&gt;&lt;/a&gt; was originally released in 2016 to provide an implementation of
asynchronous programming for Rust. In the time since, it’s accumulated a lot of
baggage. Many of its combinators have been superseded by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;
syntax, meaning that a large amount of its API surface isn’t relevant anymore.&lt;/p&gt;

&lt;p&gt;For instance, take the &lt;a href=&quot;https://docs.rs/futures/latest/futures/future/struct.Map.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Map&lt;/code&gt;&lt;/a&gt; combinator. It takes the value of some
&lt;a href=&quot;https://doc.rust-lang.org/std/future/trait.Future.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;&lt;/a&gt; and maps the return value through some closure.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fut&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapped_fut&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fut&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the pre-2018-edition days, these combinators were the only way to manipulate
the value of a &lt;a href=&quot;https://doc.rust-lang.org/std/future/trait.Future.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;&lt;/a&gt;. They were completely necessary for using these
asynchronous values back in the day. Nowadays, we can just wrap the original
futures using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; and treat it more like a normal expression.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fut&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapped_fut&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fut&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Therefore, in this brave new post-&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; world, many of these combinators
became unnecessary. &lt;a href=&quot;https://crates.io/crates/futures-lite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures-lite&lt;/code&gt;&lt;/a&gt;, one of the core components of &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;,
was created to address this new reality.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/futures-lite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures-lite&lt;/code&gt;&lt;/a&gt; explicitly ignores all combinators that can be implemented
using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; or features that have already been moved into the standard
library. This leaves behind a small, clean subset of the API that builds fast.&lt;/p&gt;

&lt;p&gt;A semi-frequently asked question I see goes along the lines of: “I was
porting my application over to &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;, but I noticed that it doesn’t have
&lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.for_each_concurrent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.buffered&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffered&lt;/code&gt;&lt;/a&gt;. Is this API excluded purposely?”&lt;/p&gt;

&lt;p&gt;This is a reasonable question. The short answer is “yes”, and the medium answer
is “these concurrent functions have small but frustrating problems that
&lt;a href=&quot;https://crates.io/crates/futures-lite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures-lite&lt;/code&gt;&lt;/a&gt; avoids by not implementing them”. This article is the longer
answer.&lt;/p&gt;

&lt;h2 id=&quot;concurrency-conundrum&quot;&gt;Concurrency Conundrum&lt;/h2&gt;

&lt;p&gt;I would argue that the concurrent &lt;a href=&quot;https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt;&lt;/a&gt; stream combinators mentioned above
are a code smell. Well-formed production-ready code should not use
&lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.for_each_concurrent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.buffered&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffered&lt;/code&gt;&lt;/a&gt;. If I knew how compilers worked, I would
suggest a &lt;a href=&quot;https://doc.rust-lang.org/stable/clippy/index.html&quot;&gt;Clippy&lt;/a&gt; lint that would flag these functions as a warning.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.for_each_concurrent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt;&lt;/a&gt; function is called like
this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.for_each_concurrent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Limiter parameter, not important for now.&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_something&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Closure to run for each element.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To massively oversimplify, &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.for_each_concurrent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt;&lt;/a&gt; does this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FuturesUnordered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Create a list to store all of the futures.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;futures_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;FuturesUnordered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Get all of the values from our stream.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Push the future to the list.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;futures_list&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Wait for all of the futures to complete. FuturesUnordered polls each future&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// in order and returns their results.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;futures_list&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.for_each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|()|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/struct.FuturesUnordered.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FuturesUnordered&lt;/code&gt;&lt;/a&gt; is sort of an unholy combination of an executor and a
&lt;a href=&quot;https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt;&lt;/a&gt;. It collects a bunch of &lt;a href=&quot;https://doc.rust-lang.org/std/future/trait.Future.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;&lt;/a&gt;s into a list, then maintains a
queue of which &lt;a href=&quot;https://doc.rust-lang.org/std/future/trait.Future.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;&lt;/a&gt;s are ready to be polled. Once a &lt;a href=&quot;https://doc.rust-lang.org/std/future/trait.Future.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;&lt;/a&gt; returns
that it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ready&lt;/code&gt;, it returns that &lt;a href=&quot;https://doc.rust-lang.org/std/future/trait.Future.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;&lt;/a&gt;’s value.&lt;/p&gt;

&lt;p&gt;This means that, every time you call &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.for_each_concurrent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt;&lt;/a&gt;, it creates an
entire new executor, runs the &lt;a href=&quot;https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt;&lt;/a&gt; to completion on it, then discards that
executor entirely. &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.buffered&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffered&lt;/code&gt;&lt;/a&gt; is implemented in a similar way.&lt;/p&gt;

&lt;p&gt;It’s bad for a couple of reasons. Most &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; runtimes already provide an
executor. &lt;a href=&quot;https://crates.io/crates/tokio&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio&lt;/code&gt;&lt;/a&gt; provides one out of the box, and &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; encourages you to
create and optimize your own. By using &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.for_each_concurrent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.buffered&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffered&lt;/code&gt;&lt;/a&gt;,
you are essentially ignoring your previous executor in order to spawn a
short-lived temporary executor.&lt;/p&gt;

&lt;p&gt;In addition to the resources that are wasted on the new executor, it’s often
less efficient than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; runtime executors. &lt;a href=&quot;https://crates.io/crates/tokio&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; support
options to let you offload tasks on other threads or handle contention more
efficiently. In contrast, &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/struct.FuturesUnordered.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FuturesUnordered&lt;/code&gt;&lt;/a&gt; is a relatively naive executor
that is completely unaware of its surrounding runtime.&lt;/p&gt;

&lt;p&gt;Not to mention, &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/struct.FuturesUnordered.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FuturesUnordered&lt;/code&gt;&lt;/a&gt; comes with a &lt;a href=&quot;https://github.com/nikomatsakis/wg-async-foundations/blob/d63a92fca362f8a6fbf6a0923d0d86b09d7bf151/src/vision/status_quo/barbara_battles_buffered_streams.md&quot;&gt;few footguns&lt;/a&gt; that make it
impractical for common use cases.&lt;/p&gt;

&lt;h2 id=&quot;make-your-own-better-combinator&quot;&gt;Make your own, better combinator&lt;/h2&gt;

&lt;p&gt;In &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;, you can emulate these use cases somewhat easily. First, you need to
create an &lt;a href=&quot;https://docs.rs/async-executor/latest/async_executor/struct.Executor.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Executor&lt;/code&gt;&lt;/a&gt; and execute your features in its context.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// The code written below will take place in this context.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can emulate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt; by turning every future in the stream into
a task, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;ing all of those tasks. Here’s how it looks if you don’t
have a task limit:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Spawn the set of futures on an executor.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Spawn the future on the executor.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do_something&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Wait for all of the handles to complete.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handles&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, we spawn every future involved onto the executor. We then take all of the
task handles and collect them. Since we are running inside of the executor, all
of these tasks will be run in parallel. Finally, we just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.await&lt;/code&gt; on each handle
to wait for all of the tasks to complete.&lt;/p&gt;

&lt;p&gt;The best part is that the allocation, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vec&amp;lt;smol::Task&amp;lt;()&amp;gt;&amp;gt;&lt;/code&gt;, isn’t even
necessary. It could be one-time allocation that is just extended to hold the
tasks.&lt;/p&gt;

&lt;p&gt;Generally, it doesn’t matter how many tasks are spawned onto the global
executor. In contrast to the mini-executor that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt; spawns,
the global executor is designed to handle large numbers of tasks. However, if
you still want to impose a resource limit, you can use a &lt;a href=&quot;https://docs.rs/async-lock/latest/async_lock/struct.Semaphore.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Semaphore&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Arc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Semaphore for limiting the number of tasks.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Arc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Semaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my_limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Spawn the set of futures on an executor.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// We use using `then` now, since we need to `.await` for the &lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// semaphore to have a permit available.&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Borrow the semaphore and executor.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// Wait for a semaphore permit.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;permit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.acquire_arc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;c&quot;&gt;// Spawn the future on the executor.&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c&quot;&gt;// Run our future.&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;do_something&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;c&quot;&gt;// Drop the permit to let another task run.&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;permit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Wait for the remaining handles to complete.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handles&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works by having each task borrow a &lt;a href=&quot;https://docs.rs/async-lock/latest/async_lock/struct.Semaphore.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Semaphore&lt;/code&gt;&lt;/a&gt; permit. The semaphore is
sort of like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mutex&lt;/code&gt; that can be locked by multiple parties at once, up to a
certain limit. Once it runs out of permits, this code doesn’t spawn a task until
one of the tasks completes. The permit is moved into the task and is dropped
once the computation completes.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;then&lt;/code&gt;-stream above is also practically the equivalent of &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.buffered&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffered&lt;/code&gt;&lt;/a&gt;. It
yields tasks that can then be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;ed to get their results.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// snip: semaphore and stream setup&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// This time, we do something else that maps the value to another.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_something_else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u32&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Get a `Stream` of tasks that can be `await`ed to get their value.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffered_stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_stream&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Borrow the semaphore and executor.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// Wait for a semaphore permit.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;permit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.acquire_arc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;c&quot;&gt;// Spawn the future on the executor.&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c&quot;&gt;// Run our future.&lt;/span&gt;
                &lt;span class=&quot;c&quot;&gt;// NEW: This now returns a value.&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_something_else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;c&quot;&gt;// Drop the permit to let another task run.&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;permit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

                &lt;span class=&quot;c&quot;&gt;// NEW: Return the result of the inner future.&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// NEW: Because the stream uses an unpinned async closure,&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// we have to pin it.&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;pin!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffered_stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// NEW: We can now wait on this stream for its values.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffered_stream&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Value: {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is all practically more efficient than &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.buffered&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffered&lt;/code&gt;&lt;/a&gt; while giving you much
greater control over how it runs.&lt;/p&gt;

&lt;h2 id=&quot;parting-shots&quot;&gt;Parting Shots&lt;/h2&gt;

&lt;p&gt;Unfortunately there’s not much documentation for the fact that &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.for_each_concurrent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for_each_concurrent&lt;/code&gt;&lt;/a&gt;
and &lt;a href=&quot;https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.buffered&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffered&lt;/code&gt;&lt;/a&gt; spawn their own separate executors. Raising awareness of proper
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code is powerful, in my opinion, as it unlocks a whole new world of
computations for intermediately experienced Rustaceans. I hope this makes it
clearer what should be happening in well-formed code.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="async" /><category term="rust" /><category term="smol" /><summary type="html">futures comes with many additional combinators that smol doesn’t have out of the box. We can rebuild them, better.</summary></entry><entry><title type="html">Eyra is an interesting Rust project</title><link href="http://2023.notgull.net/eyra/" rel="alternate" type="text/html" title="Eyra is an interesting Rust project" /><published>2023-09-25T00:00:00+00:00</published><updated>2023-09-25T00:00:00+00:00</updated><id>http://2023.notgull.net/eyra</id><content type="html" xml:base="http://2023.notgull.net/eyra/">&lt;p&gt;In the eternal quest to rewrite everything in Rust, even the C standard library isn’t safe from &lt;a href=&quot;https://en.wikipedia.org/wiki/Carcinisation&quot;&gt;carcinisation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Modern Rust programs are, for the most part, written mostly in Rust. For networking applications, the entire asynchronous stack is Rusty; no &lt;a href=&quot;https://en.wikipedia.org/wiki/Libuv&quot;&gt;libuv&lt;/a&gt; in sight, only &lt;a href=&quot;https://crates.io/crates/mio&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mio&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/polling&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;polling&lt;/code&gt;&lt;/a&gt;. There is a robust rendering stack based on &lt;a href=&quot;https://crates.io/crates/tiny-skia&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tiny-skia&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt;. Even if you need FFI, the story is still pretty good. &lt;a href=&quot;https://crates.io/crates/x11rb&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x11rb&lt;/code&gt;&lt;/a&gt; provides a robust wrapper around &lt;a href=&quot;https://xcb.freedesktop.org/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxcb&lt;/code&gt;&lt;/a&gt; with a fully Rust-based alternative, and &lt;a href=&quot;https://github.com/Smithay/wayland-rs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wayland-rs&lt;/code&gt;&lt;/a&gt; is the same with Wayland.&lt;/p&gt;

&lt;p&gt;Still, if you want to write &lt;em&gt;pure&lt;/em&gt; Rust programs, there is one annoying dependency that nearly every Rust program has. Let’s take a basic &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;-based program, written top-to-bottom in Rust. Or so I think. Let’s see what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldd&lt;/code&gt; says.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ldd linux-timerfd
        linux-vdso.so.1 (0x00007fff58fae000)
        libgcc_s.so.1 =&amp;gt; /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe7681bb000)
        libc.so.6 =&amp;gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe767e00000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe7682d4000)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Blech, disgusting! Let’ go over each of those libraries:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linux-vdso&lt;/code&gt; is the &lt;a href=&quot;https://en.wikipedia.org/wiki/VDSO&quot;&gt;vDSO&lt;/a&gt;, which is used to implement certain system calls that can be reasonably implemented in user space. This object is used to prevent needing to incur syscall overhead unless it’s needed.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libgcc&lt;/code&gt; provides implementations for certain operations, like floating point operations and exception handling. The “_s” stands for “shared”, since it is a shared library.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ld-linux-x86-64&lt;/code&gt; is the dynamic linker runtime. It’s what holds everything together.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; is the C standard library, which contains wrappers around every relevant system call as well as a handful of C-oriented routines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re going to spend most of our time talking about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;what-is-libc&quot;&gt;What is libc?&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; wears a lot of hats. It provides an extensive library of functions that are useful for C programmers, like &lt;a href=&quot;https://cplusplus.com/reference/cstdio/fopen/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fopen&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://cplusplus.com/reference/cstring/memchr/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memchr&lt;/code&gt;&lt;/a&gt;. It also contains more platform-specific wrappers around OS-specific functionality, like &lt;a href=&quot;https://man.openbsd.org/kqueue.2&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt;&lt;/a&gt;. In addition, for many operating systems, it’s the only stable interface between the user space and the kernel.&lt;/p&gt;

&lt;p&gt;This part is important. Usually system calls, special interrupt instructions, are used to tell the kernel to do something important. However, these system call interfaces are usually unstable and prone to rapid, undocumented changes. This means that anyone trying to access kernel functionality has to go through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;, even if they aren’t actually C. This isn’t a suggestion; Go tried to use direct system calls on macOS a while back and got burned by it. It turns out, when they say “unstable”, they actually do mean “will change in inconsistent, backwards-incompatible ways”.&lt;/p&gt;

&lt;p&gt;There are two important exceptions to this. The first is Windows, which has its own Win32 API that its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; is just a thin-ish wrapper over. This wrapper is how C programs written for Linux can sometimes still be used on Windows if it just uses the portable parts of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;. For our purposes it isn’t important. The second exception is Linux, which actually does have a stable system-call interface. You can call it from anywhere without going through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;, and you don’t have to worry about the actual calls changing out from under you.&lt;/p&gt;

&lt;h2 id=&quot;musl-melee&quot;&gt;Musl Melee&lt;/h2&gt;

&lt;p&gt;Because the userspace interface for Linux is the system calls and not the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;, you actually have a choice in what implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; to use aside from “whatever the OS developer wants you to use”. There are two prominent implementations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The GNU C Library (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glibc&lt;/code&gt;), which is the battle-tested full-featured implementation.&lt;/li&gt;
  &lt;li&gt;Musl &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;, which aims to be a simpler implementation focused on static linking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, if you were wondering what the “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gnu&lt;/code&gt;” at the end of “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86_64-unknown-linux-gnu&lt;/code&gt;” means, it stands for the GNU C Library that Rust is using as an interface to the system. If we have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86_64-unknown-linux-musl&lt;/code&gt; target installed, we can switch that out for Musl pretty easily.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rustup target add x86_64-unknown-linux-musl
$ cargo build --target x86_64-unknown-linux-musl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I wonder what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldd&lt;/code&gt; says instead now?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ldd linux-timerfd
        statically linked
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Well, look at that! By default, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*-musl&lt;/code&gt; option automatically statically links the binary. No more dependencies! Everything is good, forever!&lt;/p&gt;

&lt;h2 id=&quot;rustix-revelation&quot;&gt;Rustix Revelation&lt;/h2&gt;

&lt;p&gt;Hmm, there’s something gnawing at the edge of my mind, like there’s something still &lt;em&gt;wrong&lt;/em&gt; with this program. I just can’t put my finger on it.&lt;/p&gt;

&lt;p&gt;It must be that there’s still C in there. Even though it’s statically linked, Musl is &lt;em&gt;still&lt;/em&gt; a massive blob of unsafe, unsound, &lt;em&gt;filthy&lt;/em&gt; C code.&lt;/p&gt;

&lt;p&gt;Well, actually, Musl, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glibc&lt;/code&gt; for that matter, are extraordinarily well tested. Being that it’s a C standard library, it’s actually held to a very high standard for security and soundness.&lt;/p&gt;

&lt;p&gt;But after my exposure to the &lt;a href=&quot;https://doc.rust-lang.org/nomicon/&quot;&gt;Rustonomicon&lt;/a&gt;, my sanity has begun to decay like a flower wilting in winter. So let’s leave the realm of rational thought and imagine what &lt;em&gt;can&lt;/em&gt; be. A veil lifts in my mind, revealing the Platonic ideal of a perfect program:&lt;/p&gt;

&lt;p&gt;All Rust. Down to the very last bit. Perfect, &lt;em&gt;clean&lt;/em&gt; Rust.&lt;/p&gt;

&lt;p&gt;If only there was some way that we could tear that C code out by the teeth and leave it rotting at the wayside. But alas, our program needs that little bit of C code to run. Even if we were to rewrite our Rust code to use only syscalls, there would still need to be some glue code for program initialization, signal handling and threading. All written in Assembly and dirty, dirty C.&lt;/p&gt;

&lt;p&gt;No, I see something wondrous. The answer to my prayers. What will &lt;em&gt;purify&lt;/em&gt; my unclean executables and let them ascend into His Light!&lt;/p&gt;

&lt;p&gt;The answer is &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; is a set of libraries that aim to replace the role of the traditional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; in modern programs. It is written entirely in Rust, not counting the bits of Assembly necessary to tie the entire thing together. Not even a trace of C.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; was written by &lt;a href=&quot;https://github.com/sunfishcode&quot;&gt;Dan Gohman&lt;/a&gt;, who is also the primary author of &lt;a href=&quot;https://github.com/bytecodealliance/rustix/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustix&lt;/code&gt;&lt;/a&gt;. &lt;a href=&quot;https://github.com/bytecodealliance/rustix/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustix&lt;/code&gt;&lt;/a&gt; is a safe wrapper around either raw system calls on Linux or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; on other platforms, and is a very fascinating piece of software that deserves its own blogpost. The point is, &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; is &lt;a href=&quot;https://github.com/bytecodealliance/rustix/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustix&lt;/code&gt;&lt;/a&gt; taken to its logical conclusion: a complete replacement for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main drawback of &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; is that the process of integrating it into your program is more involved than just setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--target&lt;/code&gt;. But, it’s not so bad. Let’s write an &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; example program.&lt;/p&gt;

&lt;h2 id=&quot;enabling-eyra&quot;&gt;Enabling Eyra&lt;/h2&gt;

&lt;p&gt;First things first, let’s let &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo&lt;/code&gt; take care of scaffolding for us.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cargo new --bin eyra-example
     Created binary (application) `eyra-example` package
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s make it a &lt;em&gt;little&lt;/em&gt; bit more complex than a “Hello, world!” program. Say, a &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;-based TCP server that tells bad jokes.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cargo add smol fastrand eyre  
    Updating crates.io index
      Adding smol v1.3.0 to dependencies.
      Adding fastrand v2.0.1 to dependencies.
             Features:
             + alloc
             + std
             - getrandom
             - js
      Adding eyre v0.6.8 to dependencies.
             Features:
             + auto-install
             + track-caller
             - pyo3
    Updating crates.io index
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/main.rs&lt;/code&gt;, we write a simple TCP server:&lt;/p&gt;

&lt;div class=&quot;language-rs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// in src/main.rs&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;eyre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BufReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TcpListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TcpStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BAD_JOKES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;What do you call a fly without wings? A walk.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Did you hear about the dull pencil? It was pointless.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Why did the golfer bring two pairs of pants? In case he got a hole in one.&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/// Handle an incoming connection.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle_connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TcpStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Wrap the stream in a BufReader to ease reading lines.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;BufReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Read a line from the stream.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.read_line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Remove the newline at the end if there is one.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.ends_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Send a joke if the user asked for one.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.make_ascii_lowercase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;tell me a joke&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Choose a joke and send it.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;joke&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;fastrand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BAD_JOKES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.unwrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.get_mut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.write_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;joke&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Otherwise, send an error message.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;I only know how to tell jokes.&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.get_mut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.write_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(())&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;eyre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;block_on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Listen on a random port.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;TcpListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;127.0.0.1:0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.local_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Listening at address {:?}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;// Start running an executor.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c&quot;&gt;// Accept a new connection.&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.accept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;c&quot;&gt;// Spawn a task to handle the connection.&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;c&quot;&gt;// If an error occurs while running the task, print it.&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle_connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;An error occurred: {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.detach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See the comments for a breakdown of how the program works, for those unfamiliar with &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;’s API.&lt;/p&gt;

&lt;p&gt;When we run the program, it tells us the IP address that it’s listening on:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cargo run
   Compiling eyra-example v0.1.0 (/home/jtnunley/Programming/eyra-example)
    Finished dev [unoptimized + debuginfo] target(s) in 0.64s
     Running `/home/jtnunley/Programming/CargoTarget/debug/eyra-example`
Listening at address 127.0.0.1:44439
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In lieu of a dedicated client, we can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netcat&lt;/code&gt; to test out the server.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ echo &quot;tell me a joke&quot; | nc 127.0.0.1 44439
Why did the golfer bring two pairs of pants? In case he got a hole in one.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By checking with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldd&lt;/code&gt;, we can see that we’ve compiled this program against &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glibc&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ldd /home/jtnunley/Programming/CargoTarget/debug/eyra-example
        linux-vdso.so.1 (0x00007ffe8334d000)
        libgcc_s.so.1 =&amp;gt; /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f4bb8376000)
        libc.so.6 =&amp;gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4bb8000000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f4bb850a000)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s try to integrate with &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt;! (Not &lt;a href=&quot;https://crates.io/crates/eyre&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyre&lt;/code&gt;&lt;/a&gt;, which I use to simplify error handling.) First, we need to add the latest version of &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; to our project. Let’s also add logging so we can see what &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; is doing under the hood.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cargo add eyra -F log,env_logger
    Updating crates.io index
      Adding eyra v0.15.2 to dependencies.
             Features:
             + env_logger
             + log
             - experimental-relocate
             - max_level_off
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo tree&lt;/code&gt;, we can see that this pulls in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c-gull&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c-scape&lt;/code&gt; and a bunch of other things.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cargo tree
eyra-example v0.1.0 (/home/jtnunley/Programming/eyra-example)
├── eyra v0.15.2
│   └── c-gull v0.15.3
│       ├── c-scape v0.15.3
│       │   ├── &amp;lt; like, a lot of packages &amp;gt;
&amp;lt; snip rest out the output &amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, we add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extern crate eyra&lt;/code&gt; to the top of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.rs&lt;/code&gt; file so that Rust knows to link to &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt;, even if we don’t directly use anything from it.&lt;/p&gt;

&lt;div class=&quot;language-rs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// in src/main.rs&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eyra&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// &amp;lt;snip rest of file&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, we have to add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.rs&lt;/code&gt; file, which is a little build script that runs before your Rust crate is compiled. We ue this to tell Rust to link using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-nostartfiles&lt;/code&gt; argument, which tells Rust not to bring in any of the C runtime. This is because &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; has its own initializing runtime, written in Rust.&lt;/p&gt;

&lt;div class=&quot;language-rs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// in build.rs&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cargo:rustc-link-arg=-nostartfiles&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo build&lt;/code&gt;, which builds a significantly greater number of dependencies. Afterwards, we still have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra-example&lt;/code&gt; executable. Let’s see what’s inside.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ldd /home/jtnunley/Programming/CargoTarget/debug/eyra-example
        statically linked
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Nice! It’s been statically linked, hopefully with 100% Rust code. Let’s run the executable with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RUST_LOG=trace&lt;/code&gt; and see how it works.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ RUST_LOG=trace cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `/home/jtnunley/Programming/CargoTarget/debug/eyra-example`
[TRACE origin::program] Program started
[TRACE origin::thread] Main Thread[Pid(89539)] initialized
[TRACE origin::program] Calling `.init_array`-registered function `0x563e1d8a5600(1, 0x7ffc4fff5d78, 0x7ffc4fff5d88)`
[TRACE origin::program] Calling `origin_main(1, 0x7ffc4fff5d78, 0x7ffc4fff5d88)`
[TRACE async_io::driver] block_on()
[TRACE origin::thread] Thread[Pid(89539)] launched thread Thread[89541] with stack_size=2097152 and guard_size=16384
[TRACE origin::thread] Thread[89541] marked as detached by Thread[Pid(89539)]
[TRACE polling::epoll] add: epoll_fd=4, fd=6, ev=Event { key: 18446744073709551615, readable: false, writable: false }
[TRACE polling::epoll] add: epoll_fd=4, fd=5, ev=Event { key: 18446744073709551615, readable: true, writable: false }
&amp;lt; snip: lots of logs from smol being initialized &amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s break it down:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[TRACE origin::program] Program started
[TRACE origin::thread] Main Thread[Pid(89539)] initialized
[TRACE origin::program] Calling `.init_array`-registered function `0x563e1d8a5600(1, 0x7ffc4fff5d78, 0x7ffc4fff5d88)`
[TRACE origin::program] Calling `origin_main(1, 0x7ffc4fff5d78, 0x7ffc4fff5d88)`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These logs come from the program starting up and setting everything up. It initializes the main threads, calls the program constructors (see the &lt;a href=&quot;https://crates.io/crates/ctor&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctor&lt;/code&gt;&lt;/a&gt; crate if you want to know more about that), and launches the program’s entry point, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin_main&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[TRACE async_io::driver] block_on()
[TRACE origin::thread] Thread[Pid(89539)] launched thread Thread[89541] with stack_size=2097152 and guard_size=16384
[TRACE origin::thread] Thread[89541] marked as detached by Thread[Pid(89539)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/async-io&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-io&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;’s I/O driver, works by spawning a thread and then running &lt;a href=&quot;https://en.wikipedia.org/wiki/Epoll&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt;&lt;/a&gt; from that. This is used to deliver events throughout the program. Here we can see the driver being started, then a thread being launched to run &lt;a href=&quot;https://en.wikipedia.org/wiki/Epoll&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt;&lt;/a&gt; on.&lt;/p&gt;

&lt;p&gt;As we can see, our program is now running on pure-Rust (and a little assembly) software. Does it work?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ echo &quot;tell me a joke&quot; | nc 127.0.0.1 37279
What do you call a fly without wings? A walk.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Works like a charm!&lt;/p&gt;

&lt;h2 id=&quot;final-tally&quot;&gt;Final Tally&lt;/h2&gt;

&lt;p&gt;Although it’s certainly a neat project that’s treading a lot of new ground, I probably wouldn’t recommend using &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; for a production grade project. It’s still wet behind the ears and it doesn’t add much practical value to projects. Still, it’s &lt;em&gt;cool&lt;/em&gt; to be able to say that my project is 100% Rust.&lt;/p&gt;

&lt;p&gt;The setup is somewhat convoluted. It would be nice if there was some subcommand that set up &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; for a project temporarily, like &lt;a href=&quot;https://crates.io/crates/cargo-hack&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo-hack&lt;/code&gt;&lt;/a&gt; does.&lt;/p&gt;

&lt;p&gt;Also, &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; still doesn’t support &lt;em&gt;every&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; function. It’s a slow uphill battle. They are open for contributions if you’re missing something important.&lt;/p&gt;

&lt;p&gt;Until then, I’m very excited for what &lt;a href=&quot;https://github.com/sunfishcode/eyra/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eyra&lt;/code&gt;&lt;/a&gt; will bring for Rust programs in the future.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="async" /><category term="rust" /><category term="smol" /><summary type="html">In the eternal quest to rewrite everything in Rust, even the C standard library isn’t safe from carcinisation.</summary></entry><entry><title type="html">Why you might actually want async in your project</title><link href="http://2023.notgull.net/why-you-want-async/" rel="alternate" type="text/html" title="Why you might actually want async in your project" /><published>2023-09-09T00:00:00+00:00</published><updated>2023-09-09T00:00:00+00:00</updated><id>http://2023.notgull.net/why-you-want-async</id><content type="html" xml:base="http://2023.notgull.net/why-you-want-async/">&lt;p&gt;There is a common sentiment I’ve seen over and over in the Rust community that I think is ignorant at best and harmful at worst.&lt;/p&gt;

&lt;p&gt;This blogpost is largely a response to &lt;a href=&quot;https://bitbashing.io/async-rust.html&quot;&gt;this post&lt;/a&gt; by Matt Kline, but I’ve seen this kind of sentiment all over the Rust community. I’ve found that, in almost every case where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; is mentioned, at least one person says this. It always gets on my nerves a little bit.&lt;/p&gt;

&lt;p&gt;The guilty phrase is as follows: “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; rust is only useful for a small number of programs, so why do library authors insist on using it in their APIs?”&lt;/p&gt;

&lt;p&gt;I can understand where this kind of thinking comes from. Especially for newer Rustaceans, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; is quite a bit of complexity up front. But, I think actively shying away from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; is the wrong way to go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I am one of the maintainers for &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;, a small and fast &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; runtime for Rust. So, obviously, I am somewhat biased. However, I think that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; can be cool, small and fun; it’s just the presence of complicated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code used commonly across the ecosystem that scared people off.&lt;/p&gt;

&lt;h2 id=&quot;why-async&quot;&gt;Why async?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule&quot;&gt;Greenspun’s tenth rule&lt;/a&gt; comes to mind quite often. For those unfamiliar, Greenspun’s tenth rule of programming is that every sufficiently complicated program contains a bug-ridden version of half of Common Lisp. Likewise, there are a worrying number of Rust programs that contain a bug-ridden version of half of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; runtime.&lt;/p&gt;

&lt;p&gt;I call this “poor man’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;”. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; is a natural pattern for doing multiple things at once; usually, non-&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code tends to evolve into something closer and closer to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code, like &lt;a href=&quot;https://en.wikipedia.org/wiki/Carcinisation&quot;&gt;carcinisation&lt;/a&gt;. It’s all over the place in the Rust ecosystem, once you start looking for it.&lt;/p&gt;

&lt;p&gt;It happens like this: programs are naturally complicated. Even the simple, Unix-esque atomic programs can’t help but do two or three things at once. Okay, now you set it up so, instead of waiting on &lt;a href=&quot;https://man7.org/linux/man-pages/man2/read.2.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://www.man7.org/linux/man-pages/man2/accept.2.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;accept&lt;/code&gt;&lt;/a&gt; or whatnot, you register your file descriptors into &lt;a href=&quot;https://www.man7.org/linux/man-pages/man2/poll.2.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;poll&lt;/code&gt;&lt;/a&gt; and wait on that, then switching on the result of &lt;a href=&quot;https://www.man7.org/linux/man-pages/man2/poll.2.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;poll&lt;/code&gt;&lt;/a&gt; to figure out what you actually want to do.&lt;/p&gt;

&lt;p&gt;Eventually, two or three sockets becomes a hundred, or even an unlimited amount. Guess it’s time to bring in &lt;a href=&quot;https://man7.org/linux/man-pages/man7/epoll.7.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt;&lt;/a&gt;! Or, if you want to be cross-platform, it’s now time to write a wrapper around that, &lt;a href=&quot;https://en.wikipedia.org/wiki/Kqueue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt;&lt;/a&gt; and, if you’re brave, &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports&quot;&gt;IOCP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Great, now you need a way to organize all of this work, because switching on it means you have to add two hundred lines to your program every time you want to handle some other corner case. No problem, let’s set up a queue of tasks. Whoops, turns out that queueing strategy is inefficient. Better make a new one. Let’s hope it’s thread safe!&lt;/p&gt;

&lt;p&gt;At the end of this process, you’ve re-invented &lt;a href=&quot;https://crates.io/crates/async-io&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-io&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/async-executor&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-executor&lt;/code&gt;&lt;/a&gt;, two of the core components of &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This isn’t a knock on anyone in particular; this is a knock on me too! I’ve written quite a few Rust projects where I expect it to only involve blocking primitives, only to find out that, actually, I’m starting to do a lot of things at once, guess I’d better use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;. The original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; setup at the beginning of the project is somewhat annoying, but it’s a walk in the park compared to going back and rewriting my entire program setup to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The point being, many people say that only five percent of Rust projects use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;, and the remaining ninety-five percent have to put up with it. I disagree. Many of the remaining ninety-five percent (if that is an accurate number) are currently using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;; they just haven’t admitted it yet!&lt;/p&gt;

&lt;h2 id=&quot;why-dont-people-like-async&quot;&gt;Why don’t people like async?&lt;/h2&gt;

&lt;p&gt;Now here’s where I speculate &lt;em&gt;why&lt;/em&gt; this attitude is so pervasive in the Rust community. I personally think it’s a combination of poor advertising on the part of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; combined with poor standard library support.&lt;/p&gt;

&lt;p&gt;I’d argue that, if you walked up to your average Rustacean on the street and asked what they thought of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; programming, they’d argue that it’s just a obtuse, niche way to create web servers.&lt;/p&gt;

&lt;p&gt;That’s not true! Even if you ignore the benefits of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; from a network clients, you can still definitely use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; for desktop apps. &lt;a href=&quot;https://crates.io/crates/async-winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-winit&lt;/code&gt;&lt;/a&gt; is my attempt at bringing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; to desktop apps in a managable way. I just think that too many people see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; as part of Rust’s whole web shindig, instead of a reasonable way to structure highly concurrent applications.&lt;/p&gt;

&lt;p&gt;In addition, the standard library is definitely built around synchronous code first and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code second. This means that a lot of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code that &lt;em&gt;should&lt;/em&gt; be in the standard library ends up being pushed into external crates. This is definitely a problem that, thankfully, is being fixed as traits like &lt;a href=&quot;https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt;&lt;/a&gt; are now finally making their way into &lt;a href=&quot;https://doc.rust-lang.org/std/async_iter/trait.AsyncIterator.html&quot;&gt;the standard library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even if you’re writing one of the simple programs that doesn’t explicitly need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;, it’s not too difficult to move between the two worlds. &lt;a href=&quot;https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/&quot;&gt;Function colors&lt;/a&gt; get brought up a lot in this area of debate. However, personally, I find it much easier to go from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; to sync and vice versa than JavaScript does. For instance, to run an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; function in synchronous code, you can bring in the zero-dependency &lt;a href=&quot;https://crates.io/crates/pollster&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pollster&lt;/code&gt;&lt;/a&gt; crate and run this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pollster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FutureExt&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello world!&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.block_on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Likewise, to run sync code in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; world, it’s usually easy to spawn it onto a &lt;a href=&quot;https://crates.io/crates/blocking&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocking&lt;/code&gt;&lt;/a&gt; task and then poll it from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code. There’s some thread-safety subtlety I’m papering over here, but overall it looks something like this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;blocking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unblock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(||&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello world!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Another benefit of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; that I don’t know how to bring up organically above: it translates a lot better to web targets. Blocking synchronous code isn’t allowed in WASM in browsers, so by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; code, you can be reasonably sure that your algorithm can be ported to the web very easily.&lt;/p&gt;

&lt;p&gt;Generally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; makes things more portable and easier to work into different application setups. I think that, if more Rustaceans invested the effort into learning how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; ticks, we’d see it used in much more programs.&lt;/p&gt;

&lt;h2 id=&quot;keeping-the-faith&quot;&gt;Keeping the Faith&lt;/h2&gt;

&lt;p&gt;I’ve been dancing around it for too long, let’s finally dive into &lt;a href=&quot;https://bitbashing.io/async-rust.html&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main complaint that the author has around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; is that it requires your futures to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Send&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;static&lt;/code&gt;. This property tends to spread throughout the program.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;async fn foo(&amp;amp;BIG_GLOBAL_STATIC_REF_OR_SIMILAR_HORROR, sendable_chungus.clone())
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Except, this isn’t a problem with Rust’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;, it’s a problem with &lt;a href=&quot;https://crates.io/crates/tokio&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio&lt;/code&gt;&lt;/a&gt;. &lt;a href=&quot;https://crates.io/crates/tokio&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio&lt;/code&gt;&lt;/a&gt; uses a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;static&lt;/code&gt;, threaded runtime that has its benefits but requires its futures to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Send&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;static&lt;/code&gt;. In &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;, on the other hand, it’s perfectly possible to pass around things by reference.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;big&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chungus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// With smol, you can create an executor...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ...and, as long as its captured variables outlive it, you can pass things around from the stack!&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;big&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chungus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.detach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Actually, the main draw here is that this particular executor isn’t multithreaded. But it’s very easy to make it multithreaded.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Create an executor.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Create a channel used to stop the threadpool.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;bounded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Create a threadpool to run this executor on.&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Spawn 4 worker threads.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shutdown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;block_on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Run a future on this executor.&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;block_on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Variables can be passed along just like before!&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;big&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chungus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s say you don’t even want to use threads. You’re a fan of &lt;a href=&quot;https://doc.rust-lang.org/std/cell/struct.RefCell.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RefCell&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://doc.rust-lang.org/std/rc/struct.Rc.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rc&lt;/code&gt;&lt;/a&gt; so thread-safety doesn’t really fit your use-case. That’s okay too! &lt;a href=&quot;https://docs.rs/async-executor/latest/async_executor/struct.LocalExecutor.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol::LocalExecutor&lt;/code&gt;&lt;/a&gt; doesn’t require anything to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Send&lt;/code&gt; at all.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_thing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;RefCell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;smol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;LocalExecutor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Look, ma! A thread-unsafe task!&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.borrow_mut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.detach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Really, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Send&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;static&lt;/code&gt; are not intrinsic properties of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; Rust; it’s just what the biggest runtime decided on. If you’re not a fan of that, consider taking &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; for a spin!&lt;/p&gt;

&lt;h2 id=&quot;wrap-it-up&quot;&gt;Wrap it up&lt;/h2&gt;

&lt;p&gt;Really, I think that most Rustacean’s fears of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; are unjustified. Yes, there are complicated semantics at play, but really no more complicated than, say, a borrow checker. In exchange, you gain access to much more powerful program semantics (that you’re probably trying to use anyways!)&lt;/p&gt;

&lt;p&gt;So, consider using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; today! Even if you’ve been turned of by it in the past, there may be parts of the ecosystem that fit your use cases better.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="async" /><category term="rust" /><category term="smol" /><summary type="html">There is a common sentiment I’ve seen over and over in the Rust community that I think is ignorant at best and harmful at worst.</summary></entry><entry><title type="html">What to expect from smol 2.0</title><link href="http://2023.notgull.net/expect-smol-2/" rel="alternate" type="text/html" title="What to expect from smol 2.0" /><published>2023-08-22T00:00:00+00:00</published><updated>2023-08-22T00:00:00+00:00</updated><id>http://2023.notgull.net/expect-smol-2</id><content type="html" xml:base="http://2023.notgull.net/expect-smol-2/">&lt;p&gt;The tree of robust software must be refreshed from time to time with the blood of breaking changes. &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; is no exception.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; version 1.0 was originally released on September 7th, 2020. Since then, we’ve seen almost thirty new minor version bumps of Rust and a small handful of ecosystem changes. Some of these changes are so important that it necessitates changes to the way that &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; is built.&lt;/p&gt;

&lt;p&gt;In addition to hype building, the purpose of this blog post is to outline the changes that will be coming in &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; v2.0. If you are a &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; user, you should be ready for these changes when they come. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol-rs&lt;/code&gt; team is planning on releasing &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; v2.0 in the near future, although we don’t have a concrete date yet.&lt;/p&gt;

&lt;h2 id=&quot;io-safety&quot;&gt;I/O Safety&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.rust-lang.org/2022/08/11/Rust-1.63.0.html&quot;&gt;Rust v1.63&lt;/a&gt; was released with a new landmark feature: &lt;a href=&quot;https://blog.rust-lang.org/2022/08/11/Rust-1.63.0.html#rust-ownership-for-raw-file-descriptorshandles-io-safety&quot;&gt;I/O safety&lt;/a&gt;. Prior to I/O safety, I/O resources were handled by passing around raw file descriptors and &lt;em&gt;hoping&lt;/em&gt; that they were valid file resources. Here’s how a safe interface to the &lt;a href=&quot;https://man7.org/linux/man-pages/man2/read.2.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read&lt;/code&gt;&lt;/a&gt; syscall would be defined without I/O safety.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawFd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In theory, this all works out fine. In practice, it is very possible for the file descriptor to be taken out from under you, through other threads or processes. Being ready for this essentially makes it impossible to write safe code that uses I/O resources.&lt;/p&gt;

&lt;p&gt;I/O safety fixes this by assigning a lifetime to the file descriptor and guaranteeing that the underlying I/O resource will be valid for that lifetime. This shifts the burden of keeping those resources alive onto the borrow checker. The above function would be rewritten as follows:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BorrowedFd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&apos;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I/O safety is very important to &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt;. In order to handle async I/O, I/O resources are registered into a &lt;a href=&quot;https://crates.io/crates/async-io&quot;&gt;global reactor&lt;/a&gt;. It is possible for the resources to be deallocated while they are still in this global reactor, which can lead to missing or spurious events. Now that we can assign a lifetime to the file descriptor before we register it into the reactor, this isn’t a problem anymore. &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; v2.0 will have its &lt;a href=&quot;https://docs.rs/async-io/latest/async_io/struct.Async.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Async&lt;/code&gt;&lt;/a&gt; type take &lt;a href=&quot;https://doc.rust-lang.org/std/os/fd/trait.AsFd.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsFd&lt;/code&gt;&lt;/a&gt; types instead of &lt;a href=&quot;https://doc.rust-lang.org/std/os/fd/trait.AsRawFd.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsRawFd&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This new advantage comes with a catch. Previously, &lt;a href=&quot;https://docs.rs/async-io/latest/async_io/struct.Async.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Async&lt;/code&gt;&lt;/a&gt; allowed for easy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;mut&lt;/code&gt; access to the inner I/O resource. However, this isn’t allowed now, as it is possible to move out and then drop the underlying I/O resource while it is still registered into the reactor, which voids the entire point. Therefore mutable access through methods like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_mut&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readable_with_mut&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;writable_with_mut&lt;/code&gt; are now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe&lt;/code&gt;, with the condition that the user is not allowed to move out or drop the underlying file descriptor.&lt;/p&gt;

&lt;p&gt;Unfortunately this change is very harsh and will likely break a lot of code in the wild. I’ve seen many real-world use cases use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readable_with_mut&lt;/code&gt; for efficiently polling some I/O resource. Not to mention, the only real fix that can be done while still ensuring I/O safety holds is to use interior mutability, which is a code smell.&lt;/p&gt;

&lt;p&gt;In any case, it is recommended for users of &lt;a href=&quot;https://crates.io/crates/async-io&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-io&lt;/code&gt;&lt;/a&gt;, especially ones that implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; wrappers around I/O resources like &lt;a href=&quot;https://en.wikipedia.org/wiki/Inotify&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inotify&lt;/code&gt;&lt;/a&gt;, to expect this change and start thinking about how the architecture should be changed.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/smol-rs/polling/pull/123&quot;&gt;this pull request for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;polling&lt;/code&gt;&lt;/a&gt; for more information on why this was done and how it was considered.&lt;/p&gt;

&lt;h2 id=&quot;async-channel-and-async-lock-unpin-futures&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-channel&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-lock&lt;/code&gt; !Unpin Futures&lt;/h2&gt;

&lt;p&gt;Previously, &lt;a href=&quot;https://crates.io/crates/async-channel&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-channel&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/async-lock&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-lock&lt;/code&gt;&lt;/a&gt; (aka &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol::channel&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol::lock&lt;/code&gt;) had several methods that returned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unpin&lt;/code&gt; futures. These futures can be polled without pinning them to the stack or heap. Once &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; v2.0 releases, these futures will now be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!Unpin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I expect this to have a low impact on your average bear, as most of the time these futures are immediately &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.await&lt;/code&gt;ed, which doesn’t care about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unpin&lt;/code&gt; at all. However I am aware of some use cases that rely on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unpin&lt;/code&gt;-ness of these futures. Fortunately this breakage can be ameliorated in the short term by just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Box::pin&lt;/code&gt;ning the future and polling it from there.&lt;/p&gt;

&lt;p&gt;The reason for this change is that it allows the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; primitives underlying these libraries to be implemented in a much more efficient way. These libraries work by storing waiters- tasks waiting for the channel to receive a value or the &lt;a href=&quot;https://doc.rust-lang.org/std/sync/struct.Mutex.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mutex&lt;/code&gt;&lt;/a&gt; to unlock- in a linked list. Previously, this linked list used a strategy where every node in the list was heap allocated. Now, these nodes use stack storage when possible, which avoids allocations on the heap.&lt;/p&gt;

&lt;p&gt;This optimization is a massive win for performance, doubling it in some cases. However, this strategy requires that the futures be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!Unpin&lt;/code&gt;, as the stack storage cannot be moved without invalidating every other node in the linked list.&lt;/p&gt;

&lt;h2 id=&quot;async-channel-and-async-lock-on-no_std&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-channel&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-lock&lt;/code&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no_std&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Previously, &lt;a href=&quot;https://crates.io/crates/async-channel&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-channel&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/async-lock&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-lock&lt;/code&gt;&lt;/a&gt; were only available for platforms with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std&lt;/code&gt; enabled. This is because they internally made use of &lt;a href=&quot;https://doc.rust-lang.org/std/sync/struct.Mutex.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::sync::Mutex&lt;/code&gt;&lt;/a&gt; for synchronization. Once &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; v2.0 released, these crates can now be used on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no_std&lt;/code&gt; platforms.&lt;/p&gt;

&lt;p&gt;All features from these crates should still be available on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no_std&lt;/code&gt; platform, except for blocking methods (like &lt;a href=&quot;https://docs.rs/async-channel/latest/async_channel/struct.Sender.html#method.send_blocking&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send_blocking&lt;/code&gt;&lt;/a&gt;). The main drawback is that both of these crates still require a global allocator, which probably can’t be removed until &lt;a href=&quot;https://doc.rust-lang.org/unstable-book/library-features/allocator-api.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allocator_api&lt;/code&gt;&lt;/a&gt; is stabilized. So unfortunately it probably won’t be used on embedded systems any time soon.&lt;/p&gt;

&lt;p&gt;Once again this win comes from the underlying event notification primitive. The previous implementation used an &lt;a href=&quot;https://doc.rust-lang.org/std/sync/struct.Mutex.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::sync::Mutex&lt;/code&gt;&lt;/a&gt; to synchronize the state of the inner linked list of wakers. Although the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std&lt;/code&gt; implementation still uses this mutex, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no_std&lt;/code&gt; uses another strategy. The state is protected by a spinlock, but put away your &lt;a href=&quot;https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html&quot;&gt;blogpost links&lt;/a&gt; for now. Only a limited amount of spinning is allowed, and it falls back to a fully atomic queue after the spinlock fails too many times. This strategy was based on analysis that the spinlock is the most efficient strategy for low contention, and the atomic queue can act as a fallback for when the contention is high.&lt;/p&gt;

&lt;p&gt;However, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no_std&lt;/code&gt; strategy is significantly slower than the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std&lt;/code&gt; strategy. Therefore users should use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std&lt;/code&gt; strategy whenever possible. Users of these crates should consider exposing an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std&lt;/code&gt; default feature in turn that allows for users to opt-out of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no_std&lt;/code&gt; applications.&lt;/p&gt;

&lt;p&gt;Although this win and the previous one were developed over a long series of pull requests, &lt;a href=&quot;https://github.com/smol-rs/event-listener/pull/51&quot;&gt;this one&lt;/a&gt; is the most relevant.&lt;/p&gt;

&lt;h2 id=&quot;futures-lite-now-re-exports-ready-and-pending-from-libstd&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures-lite&lt;/code&gt; now re-exports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ready&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pending&lt;/code&gt; from libstd&lt;/h2&gt;

&lt;p&gt;When &lt;a href=&quot;https://crates.io/crates/futures-lite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures-lite&lt;/code&gt;&lt;/a&gt; was originally written, &lt;a href=&quot;https://doc.rust-lang.org/std/future/fn.ready.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ready&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://doc.rust-lang.org/std/future/fn.pending.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pending&lt;/code&gt;&lt;/a&gt; were not available on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libstd&lt;/code&gt; yet. However, as of Rust v1.63, they can be imported from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;core::future&lt;/code&gt;. Therefore, &lt;a href=&quot;https://crates.io/crates/futures-lite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures-lite&lt;/code&gt;&lt;/a&gt; will now re-export these functions from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;core::future&lt;/code&gt; instead of defining them itself.&lt;/p&gt;

&lt;p&gt;This is a small but significant win, as it represents less functionality needed on the part of &lt;a href=&quot;https://crates.io/crates/futures-lite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;futures-lite&lt;/code&gt;&lt;/a&gt;. However, our v1.63 MSRV stops us from re-exporting &lt;a href=&quot;https://doc.rust-lang.org/std/future/fn.poll_fn.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;poll_fn&lt;/code&gt;&lt;/a&gt; as well, which was introduced in v1.64.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/smol-rs/futures-lite/pull/73&quot;&gt;this PR&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2 id=&quot;esp-idf-support&quot;&gt;ESP-IDF Support&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://github.com/ivmarkov&quot;&gt;Ivan Markov&lt;/a&gt;, the underlying machinery of &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; now has better support for ESP-IDF. This is a big win for the embedded community, as it allows for &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; to be used on embedded systems that use ESP-IDF.&lt;/p&gt;

&lt;h2 id=&quot;new-logo&quot;&gt;New Logo&lt;/h2&gt;

&lt;p&gt;We now have a new logo! The old &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; logo was a smol, cute orange tabby cat. To represent the new capabilities that &lt;a href=&quot;https://crates.io/crates/smol&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smol&lt;/code&gt;&lt;/a&gt; has for version 2.0, we’ve decided to change the logo into a cyborg cat!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/smol-rs/smol/blob/master/assets/images/logo_fullsize_transparent.png?raw=true&quot; alt=&quot;new logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://twitter.com/star_nebulous&quot;&gt;NebulousStar&lt;/a&gt; on X for drawing this!&lt;/p&gt;

&lt;h2 id=&quot;and-much-more&quot;&gt;…and much more!&lt;/h2&gt;

&lt;p&gt;There are a handful of other minor, non-breaking changes as well. This includes the task system now having a metadata slot available, and the &lt;a href=&quot;https://crates.io/crates/async-executor&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async-executor&lt;/code&gt;&lt;/a&gt; crate using thread-local queue optimizations. These changes are not as important as the ones listed above, but they are still worth mentioning.&lt;/p&gt;

&lt;p&gt;I’ll have a more complete changelog once the release actually takes out. Until then, you would be well advised to start thinking about how these changes will affect your code.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="async" /><category term="rust" /><category term="smol" /><summary type="html">The tree of robust software must be refreshed from time to time with the blood of breaking changes. smol is no exception.</summary></entry><entry><title type="html">Announcing Theo</title><link href="http://2023.notgull.net/theo/" rel="alternate" type="text/html" title="Announcing Theo" /><published>2023-08-04T00:00:00+00:00</published><updated>2023-08-04T00:00:00+00:00</updated><id>http://2023.notgull.net/theo</id><content type="html" xml:base="http://2023.notgull.net/theo/">&lt;p&gt;Today I’m happy to officially announce a project that has been the culmination of about five months of work. This makes it probably the most involved programming project I’ve ever done, and I’m proud of the final result.&lt;/p&gt;

&lt;p&gt;The GUI ecosystem in Rust is still in a nascent stage. There are well-defined ecosystem crates for doing certain things, like &lt;a href=&quot;`winit`&quot;&gt;window management&lt;/a&gt;. On the other hand, other essential GUI components are still wanting for a good solution. In my own travels, I’ve found that there’s no good out-of-the-box solution to &lt;em&gt;vector graphics&lt;/em&gt; yet, which is an essential part of any GUI. The closest thing is &lt;a href=&quot;https://crates.io/crates/piet-common&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-common&lt;/code&gt;&lt;/a&gt;, but it’s hard to integrate into non-&lt;a href=&quot;https://crates.io/crates/druid&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;druid&lt;/code&gt;&lt;/a&gt; systems like &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; is my attempt at resolving this issue. It’s an implementation of &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt;, a common vector graphics API, that can be used with any windowing system that implements the &lt;a href=&quot;https://crates.io/crates/raw-window-handle&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw-window-handle&lt;/code&gt;&lt;/a&gt; traits. The goal is to provide a system that can be effortlessly plugged into whatever system you already have in place, and provide a simple, easy-to-use API for drawing vector graphics.&lt;/p&gt;

&lt;p&gt;It has a number of benefits over &lt;a href=&quot;https://crates.io/crates/piet-common&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-common&lt;/code&gt;&lt;/a&gt; and other contemporary solutions. First of all, as mentioned, it works with the &lt;a href=&quot;https://crates.io/crates/raw-window-handle&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw-window-handle&lt;/code&gt;&lt;/a&gt; interoperability traits, meaning that it should, in theory, work anywhere. Another primary benefit is its use of GPU acceleration. Where possible, it uses either &lt;a href=&quot;https://crates.io/crates/wgpu&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wgpu&lt;/code&gt;&lt;/a&gt; or OpenGL as the underlying drawing backend, which should provide benefits for systems with lower CPU power, like Risc-V boxes. However, it is able to fall back to a software rasterization backend based on &lt;a href=&quot;https://crates.io/crates/tiny-skia&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tiny-skia&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/softbuffer&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;softbuffer&lt;/code&gt;&lt;/a&gt;, which should work on any system that can run &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; also uses very few system libraries. &lt;a href=&quot;https://crates.io/crates/piet-common&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-common&lt;/code&gt;&lt;/a&gt; brings in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cairo&lt;/code&gt; on Linux. On the other hand, aside from GPU libraries like Vulkan and windowing libraries like X11, &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; depends on very little.&lt;/p&gt;

&lt;p&gt;If you’re building a GUI system, consider giving it a try! See the examples in the repository for &lt;a href=&quot;https://github.com/notgull/theo/blob/main/examples/winit.rs&quot;&gt;an example&lt;/a&gt; of how to use it.&lt;/p&gt;

&lt;h2 id=&quot;the-vellophant-in-the-room&quot;&gt;The Vellophant in the Room&lt;/h2&gt;

&lt;p&gt;At the time of writing, the Linebender team is working on a similar vector graphics system named &lt;a href=&quot;https://github.com/linebender/vello&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vello&lt;/code&gt;&lt;/a&gt;. It uses GPU acceleration via &lt;a href=&quot;https://crates.io/crates/wgpu&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wgpu&lt;/code&gt;&lt;/a&gt; and is designed to work with systems like &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt; as well. So why did I go to all the effort? Why not just wait for &lt;a href=&quot;https://github.com/linebender/vello&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vello&lt;/code&gt;&lt;/a&gt; to be ready?&lt;/p&gt;

&lt;p&gt;First of all, &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/linebender/vello&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vello&lt;/code&gt;&lt;/a&gt; use different strategies. &lt;a href=&quot;https://github.com/linebender/vello&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vello&lt;/code&gt;&lt;/a&gt; is a &lt;em&gt;compute&lt;/em&gt;-based renderer, while &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; uses a &lt;em&gt;rasterize&lt;/em&gt; renderer. The difference comes down to strategy: &lt;a href=&quot;https://github.com/linebender/vello&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vello&lt;/code&gt;&lt;/a&gt; tries to use the GPU to the fullest extent by uploading vector data to the GPU and then rendering it there. On the other hand, &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; uses a more traditional strategy: converting shapes on the CPU to textured triangles and then pushing those to the GPU. It is this author’s opinion that the rasterization-based strategy is more ergonomic and easier to cache, so I created &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt; around this strategy. Your mileage may vary.&lt;/p&gt;

&lt;p&gt;There are some other minor differences, but overall once &lt;a href=&quot;https://github.com/linebender/vello&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vello&lt;/code&gt;&lt;/a&gt; is actually released it should work similarly to &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt;. It’s a matter of API preference, really.&lt;/p&gt;

&lt;h2 id=&quot;was-it-hard-to-make&quot;&gt;Was it hard to make?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/quest-for-piet&quot;&gt;Yes.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;other-crates&quot;&gt;Other Crates&lt;/h2&gt;

&lt;p&gt;While building &lt;a href=&quot;https://crates.io/crates/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt;, I had to write a handful of other crates to make the current Rust rendering ecosystem easier to work with. Here’s a quick rundown of them:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/line-straddler&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;line-straddler&lt;/code&gt;&lt;/a&gt;, which generates underlines and strikethroughs for glyphs.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/piet-cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cosmic-text&lt;/code&gt;&lt;/a&gt;, which provides a uniform text rendering interface for &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; using &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/piet-tiny-skia&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-tiny-skia&lt;/code&gt;&lt;/a&gt;, which implements a &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; backend using &lt;a href=&quot;https://crates.io/crates/tiny-skia&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tiny-skia&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/piet-hardware&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-hardware&lt;/code&gt;&lt;/a&gt;, which converts &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; rendering calls to buffering textured triangles.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/piet-glow&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-glow&lt;/code&gt;&lt;/a&gt;, which implements a &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; backend using OpenGL.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/piet-wgpu&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-wgpu&lt;/code&gt;&lt;/a&gt;, which implements a &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; backend using &lt;a href=&quot;https://crates.io/crates/wgpu&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wgpu&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>John Nunley</name></author><category term="gui" /><category term="rust" /><category term="piet" /><category term="drawing" /><summary type="html">Today I’m happy to officially announce a project that has been the culmination of about five months of work. This makes it probably the most involved programming project I’ve ever done, and I’m proud of the final result.</summary></entry><entry><title type="html">The Quest for Piet 3, or, Text Rendering Madness</title><link href="http://2023.notgull.net/quest-for-piet-part-3/" rel="alternate" type="text/html" title="The Quest for Piet 3, or, Text Rendering Madness" /><published>2023-08-03T00:00:00+00:00</published><updated>2023-08-03T00:00:00+00:00</updated><id>http://2023.notgull.net/quest-for-piet-part-3</id><content type="html" xml:base="http://2023.notgull.net/quest-for-piet-part-3/">&lt;p&gt;Whenever I’ve talked to someone else who writes a drawing interface like this, it seems like they always say text is the hardest part. But obviously, &lt;em&gt;I’m&lt;/em&gt; built different, right?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/quest-for-piet-part-2/&quot;&gt;Last time&lt;/a&gt;, I integrated gradients more completely into my &lt;a href=&quot;https://crates.io/crates/piet-hardware&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-hardware&lt;/code&gt;&lt;/a&gt; crate. Today, we’re moving onto a subject that’s much more likely to be bad for my blood pressure: text rendering!&lt;/p&gt;

&lt;p&gt;For the most part, I offload text loading, shaping and rendering onto the &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; crate. It’s a pretty complete implementation of the whole “text” thing. Not to mention, it’s been created by people far smarter than I am.&lt;/p&gt;

&lt;p&gt;So far, it’s worked well. In my limited tests, it’s created a decent layout  system for text. The rendering has also worked out pretty well.&lt;/p&gt;

&lt;p&gt;Unfortunately, especially when it comes to the GPU backend, there’s a lot of things that we have to take care of. Principally, the &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; text API needs to be translated to &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; calls. I’ve created a crate to handle this translation: &lt;a href=&quot;https://crates.io/crates/piet-cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cosmic-text&lt;/code&gt;&lt;/a&gt;. But I’ve long suspected that something is wrong.&lt;/p&gt;

&lt;p&gt;There’s also the fact that we need to draw the text onto the window. By default, &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; draws to an array of pixels, but that doesn’t translate well to OpenGL. What I do is render those pixels to a texture, and then draw portions of that texture to the screen. This technique is called &lt;a href=&quot;https://en.wikipedia.org/wiki/Texture_atlas&quot;&gt;texture atlassing&lt;/a&gt;, and it’s very common when using this kind of drawing code.&lt;/p&gt;

&lt;p&gt;So! Without further ado, let’s find out what’s gone wrong.&lt;/p&gt;

&lt;h2 id=&quot;number-5-coloring-cascade&quot;&gt;Number 5: Coloring Cascade&lt;/h2&gt;

&lt;p&gt;The purpose of this one, I think, is to test how text rendering deals with multiple colors and styles in one block of text. Here’s the reference image from &lt;a href=&quot;https://crates.io/crates/piet-cairo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cairo&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cairo-test-05-2.00.png&quot; alt=&quot;Reference&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s what &lt;a href=&quot;https://crates.io/crates/piet-glow&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-glow&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://crates.io/crates/piet-wgpu&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-wgpu&lt;/code&gt;&lt;/a&gt; spit out:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-2.00.png&quot; alt=&quot;Glow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Right! A few issues I can spot right off the bat:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The text is too big.&lt;/li&gt;
  &lt;li&gt;The text stops being blue way too soon.&lt;/li&gt;
  &lt;li&gt;The font is too bold throughout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one seems like the easiest to tackle. In the code for &lt;a href=&quot;https://crates.io/crates/piet-cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cosmic-text&lt;/code&gt;&lt;/a&gt;, there’s a function for converting the &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; font size to the &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; font size:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;points_to_pixels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;points&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;points&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;96.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;72.0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This seems to be making it too big, so maybe I remove the ratio?&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;points_to_pixels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;points&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;points&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This seems to go the other way; the output is now too small?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-too-smol.png&quot; alt=&quot;Glow v2.0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It looks like the ratio depends on the DPI of the screen, which varies from place to place. If you don’t have access to that information, you should assume that it’s 96 DPI. So, what I was doing originally was right?&lt;/p&gt;

&lt;p&gt;To me it seems like this should be an adjustable option on the part of the user. The windowing framework is generally what controls the DPI, so it should be able to tell the drawing code what it is. So far &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt; doesn’t support a straight way to fetch the DPI (it exclusively uses scaled pixels, which doesn’t really help us here). So I’ll just keep it ratio-free for now, since that seems to get us reasonably close to what we want.&lt;/p&gt;

&lt;p&gt;Anyways, the next item on the list: the text stops being blue. I think this is because I mistranslate the &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; attributes to &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; attributes. There’s no real excuse here outside of me just misunderstanding the math. After rewriting the algorithm I used to choose text attributes, everything seems to be fixed… except for one thing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-indifferent.png&quot; alt=&quot;Glow v3.0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The underlines and the strikethroughs are in the wrong places. I use a crate called &lt;a href=&quot;https://crates.io/crates/line-straddler&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;line-straddler&lt;/code&gt;&lt;/a&gt; to figure out where the underline should go, but it seems to be off.&lt;/p&gt;

&lt;p&gt;What kind of hack designed this broken crate? I oughta- oh, it’s me. I wrote &lt;a href=&quot;https://crates.io/crates/line-straddler&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;line-straddler&lt;/code&gt;&lt;/a&gt;. Whoops.&lt;/p&gt;

&lt;p&gt;One rewrite later…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-shorty.png&quot; alt=&quot;Glow v3.0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Oh whoops, the lines are too skinny. Easy enough fix.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-long.png&quot; alt=&quot;Glow v3.1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No, Kronk! The other lever!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-evwhy.png&quot; alt=&quot;Glow v3.2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Okay, pros: the lines are now at an appropriate thickness! Cons: the lines put themselves just about wherever they please.&lt;/p&gt;

&lt;p&gt;Why is it so hard to draw lines under text?&lt;/p&gt;

&lt;p&gt;Let’s- wait a second, &lt;a href=&quot;https://github.com/pop-os/cosmic-text/releases/tag/0.9.0&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt; v0.9.0&lt;/a&gt; just released with breaking changes. Normally I’d complain about this happening right in the middle of what I’m doing, but it removes the bespoke &lt;a href=&quot;https://crates.io/crates/ouroboros&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ouroboros&lt;/code&gt;&lt;/a&gt; dependency, so I’m a happy camper.&lt;/p&gt;

&lt;p&gt;After all of that and a little math adjustment, I get this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-evhow.png&quot; alt=&quot;Glow v3.3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Looks good, but a few small issues:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Why is the text justified all of a sudden?&lt;/li&gt;
  &lt;li&gt;The underlines are too thick.&lt;/li&gt;
  &lt;li&gt;The lines start from the top down instead of the bottom up like they do in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cairo&lt;/code&gt; implementation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issues 2 and 3 are a matter of changing a few lines of math. Issue 1 looks to be an actual &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; bug introduced in v0.9.0. &lt;a href=&quot;https://github.com/pop-os/cosmic-text/issues/151&quot;&gt;Let’s file that.&lt;/a&gt; Until then…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-05-almost.png&quot; alt=&quot;Glow v3.4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Close enough for government work. The bug seems to be localized to when fonts are switched mid-paragraph, so I’ll just avoid doing that for now.&lt;/p&gt;

&lt;p&gt;Holy hell, that was an ordeal. Good God, please give me something easy next…&lt;/p&gt;

&lt;h2 id=&quot;number-7-alignment-ailment&quot;&gt;Number 7: Alignment Ailment&lt;/h2&gt;

&lt;p&gt;This test aims to test how text alignment works, for both left-to-right and right-to-left text.&lt;/p&gt;

&lt;p&gt;Here is the sample version, from &lt;a href=&quot;https://crates.io/crates/piet-cairo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cairo&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cairo-test-07-2.00.png&quot; alt=&quot;Reference&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Mhmm, seems like there is some overlapping text. Let’s see how we did…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-07-2.00.png&quot; alt=&quot;Glow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Great! We’re halfway there already, thanks to all the work we did on the last sample. The only thing left to do is to fix the right-to-left text at the bottom.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; doesn’t have an option out of the box. Implementing it doesn’t look too hard, though. &lt;a href=&quot;https://github.com/pop-os/cosmic-text/pull/152&quot;&gt;That’s a PR!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s been merged, but it’s not in release yet. So I guess we’ll just wait for that.&lt;/p&gt;

&lt;h2 id=&quot;number-8-font-size-frenzy&quot;&gt;Number 8: Font Size Frenzy&lt;/h2&gt;

&lt;p&gt;The catch with this one appears to be testing multiple different font sizes. There’s also different colors and fonts, but we’ve already tested those.&lt;/p&gt;

&lt;p&gt;Here’s what it looks like under &lt;a href=&quot;https://crates.io/crates/piet-cairo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cairo&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cairo-test-08-2.00.png&quot; alt=&quot;Reference&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And here’s what it looks like under &lt;a href=&quot;https://crates.io/crates/piet-glow&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-glow&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;…nothing! That’s right, nothing at all! It throws an error and outputs nothing!&lt;/p&gt;

&lt;p&gt;This is because &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; doesn’t actually support multiple font sizes in one block of text. Apparently it’s harder to lay out like that. In fact, here’s the code I wrote to handle that:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;TextAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FontSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// TODO: cosmic-text does not support variable sized text yet.&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// https://github.com/pop-os/cosmic-text/issues/64&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;error!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cosmic-text does not support variable size fonts yet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unimplemented&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Bah, humbug! Who cares about one little sample. Gotta crack a few omelette to make an egg, right? Let’s just move on to the next sample.&lt;/p&gt;

&lt;h2 id=&quot;number-9-unsizing-ultimatum&quot;&gt;Number 9: Unsizing Ultimatum&lt;/h2&gt;

&lt;p&gt;This one can’t be too bad, right? It’s just—&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cairo-test-09-2.00.png&quot; alt=&quot;Reference&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Oh, no. Those font sizes look a little bit &lt;em&gt;variable&lt;/em&gt;, don’t they? That means that…&lt;/p&gt;

&lt;p&gt;Yep! Nothing! That’s right, I got the exact same error!&lt;/p&gt;

&lt;p&gt;So, I guess this means we &lt;em&gt;have&lt;/em&gt; to deal with variable sized font in some way. One failing sample would be reasonable. Two would be criminal.&lt;/p&gt;

&lt;p&gt;There’s a &lt;a href=&quot;https://github.com/pop-os/cosmic-text/pull/150&quot;&gt;pull request&lt;/a&gt; that adds support for variable sized fonts, but it’s still in its early stages and touches a &lt;em&gt;lot&lt;/em&gt; of code. I’d also like to avoid depending on git repositories for now.&lt;/p&gt;

&lt;p&gt;Implementing it myself would require a &lt;em&gt;lot&lt;/em&gt; of code to be written. Code that would be thrown away once the PR is merged and released.&lt;/p&gt;

&lt;p&gt;A simple patch is just to remove the error and make it ignore the changes in font size. It’s not ideal, but for now it has to work.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-09-2.00.png&quot; alt=&quot;Glow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Oh, the little red and green lines are all wrong, aren’t they?&lt;/p&gt;

&lt;p&gt;I’ve taken a look at the code, and I think I’ve decoded what it means:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For each line of text, it returns &lt;a href=&quot;https://docs.rs/piet/latest/piet/struct.LineMetric.html&quot;&gt;line metrics&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;The red line represents the “top” of the line.&lt;/li&gt;
  &lt;li&gt;The green line represents the “baseline”, where the bottom of most letters end.&lt;/li&gt;
  &lt;li&gt;The blue line represents the bottom of the line. I’m not sure why this only appears once?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it’s only a matter of adjusting the metrics. Easy enough. Right now, my definition of metrics were somewhat off-the-cusp, mostly just to fill in the text rendering trait.&lt;/p&gt;

&lt;p&gt;After reviewing the definitions of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LineMetrics&lt;/code&gt; struct and adjusting accordingly, here’s what I found:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-09-improved.png&quot; alt=&quot;Glow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Whoops, I added the line height to a couple of them by accident. Allow me to fix this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-09-improved2.png&quot; alt=&quot;Glow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There we are! The last line seems misplaced to me… but you know what, it’s close enough for government work.&lt;/p&gt;

&lt;p&gt;For all those reading, in case you’ve wondered why there are hundreds of thousands of lines of code in a text rendering library, this is why. “Correct” text rendering is a very complicated subject.&lt;/p&gt;

&lt;p&gt;Say, we never checked in on sample number eight after we “fixed” text sampling, did we? Before we move on, let’s check in on it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-08-kinda.png&quot; alt=&quot;Glow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wait, is part of the text just missing? &lt;em&gt;Grooooaaan&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;revenge-of-the-eighth&quot;&gt;Revenge of the Eighth&lt;/h2&gt;

&lt;p&gt;Our text is missing! Why is is missing? Well, why not? Why not have text randomly disappear without as much as a warning log message? That seems sensible.&lt;/p&gt;

&lt;p&gt;After some slight trial and error, it looks like if I disable the bolding on the latter portion of the text, it renders fine.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-08-nobold.png&quot; alt=&quot;NoBold&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Maybe &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; just doesn’t like it when you have a font with weird bolding like that? I don’t know, and from looking at the code it isn’t immediately obvious why this happens.&lt;/p&gt;

&lt;p&gt;Why is this happening? Why isn’t the text showing up? Why isn’t there as much as a log message when this happens? Is it a bug? Is it a feature? What’s wrong with this project? Why have I poured so much time into this? Does everyone spend this much time on text rendering? What happened to Site-13?&lt;/p&gt;

&lt;h2 id=&quot;the-long-haul&quot;&gt;The Long Haul&lt;/h2&gt;

&lt;p&gt;Seriously, &lt;a href=&quot;https://scpwiki.com/scp-1730&quot;&gt;what happened to Site-13?&lt;/a&gt; When it was originally released in 2015, it was something completely new for the SCP Foundation. It took the long exploration logs previously explored in articles like &lt;a href=&quot;https://scpwiki.com/scp-093&quot;&gt;SCP-093&lt;/a&gt; and really &lt;em&gt;ran with it&lt;/em&gt;. The viscerally terrifying exploration logs were like something right out of a Raimi movie, and the sheer scale is still almost unmatched to this day.&lt;/p&gt;

&lt;p&gt;But then, in 2018, the original author, &lt;a href=&quot;https://scpwiki.com/the-based-god&quot;&gt;djkaktus&lt;/a&gt;, added more to the story. He added a handful of exploration logs, followed by a mouthful of interviews. In my opinion, this is one of the worst mistakes in the history of the SCP canon. SCP-1730 already had a very complete arc to it, and these new logs unnecessarily prolonged it. Not to mention, the new logs didn’t really fit the tone all too well.&lt;/p&gt;

&lt;p&gt;I don’t want to spoil it, but imagine if &lt;em&gt;Evil Dead&lt;/em&gt; ended with an hour-long scene where a handful of cyborg ninjas shows up and beats up all of the Deadites, followed by another hour-long scene where they interview all of the teenagers to figure to what happened.&lt;/p&gt;

&lt;p&gt;This tragedy has always been the prime example for me on why you need to reduce your scope. Making your projects too large is hazardous to both your health and your final quality. Even &lt;em&gt;if&lt;/em&gt; you manage to finish your project (and for someone as easily distracted as me that’s a &lt;em&gt;big&lt;/em&gt; if), what’s left will probably be a bloated mess that’s not worth the effort.&lt;/p&gt;

&lt;p&gt;When I originally started getting into Rust in 2019, I identified that there wasn’t a real good solution to GUI in Rust. Therefore, I naively set out to single-handedly create an entire GUI framework, top to bottom, from scratch.&lt;/p&gt;

&lt;p&gt;It took a year on flailing about in various aspects of GUI management to find out that this was a bad idea. A GUI framework touches on an absolutely massive number of subjects, from windowing systems to vector graphics to text rendering to fundamental data structures. That’s not even all of it; that’s just the underlying plumbing. When it comes to the parts of the GUI that &lt;em&gt;matter&lt;/em&gt;, you need to come up with an incrementalization framework. Good luck doing it in a way that works with Rust’s object model &lt;em&gt;and&lt;/em&gt; isn’t an absolute mess to use.&lt;/p&gt;

&lt;p&gt;At this point I decide that scope reduction is a good idea. Okay, maybe I &lt;em&gt;don’t&lt;/em&gt; want to write the entire windowing system. &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt; already exists and works well enough; I can just patch it until it fits all of my use cases. Maybe I don’t want to deal with making my own underlying graphics API. &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; is in use by &lt;a href=&quot;https://crates.io/crates/druid&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;druid&lt;/code&gt;&lt;/a&gt; and it seems to be working for them. Actually, hmm, the default &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; implementation, &lt;a href=&quot;https://crates.io/crates/piet-common&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-common&lt;/code&gt;&lt;/a&gt;, doesn’t play well with &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, here’s a scope that I can shrink down to! It should be easy enough to just write a &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt;, I foolishly said to myself. Once I implement all of the &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; traits, it’ll just be easy, right? Right?&lt;/p&gt;

&lt;p&gt;So I put myself to work. The hardest part was writing the OpenGL-based implementation. I explicitly wrote it so that it would be portable to &lt;a href=&quot;https://crates.io/crates/wgpu&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wgpu&lt;/code&gt;&lt;/a&gt;, so I could just swap out the backend and it would work. For text rendering I figured I could just throw &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; at it  Then I wrote a software rasterization backend so that it could work pretty much everywhere. It took a couple of months, but it seemed to work, right? I even used it in a school project of mine.&lt;/p&gt;

&lt;p&gt;But then, bug reports started flowing in. Clipping wasn’t working properly, colors weren’t matching up quite right, and text rendering? Forget about it.&lt;/p&gt;

&lt;p&gt;So in lieu of tracking all of these bugs down, I noticed that &lt;a href=&quot;https://crates.io/crates/piet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet&lt;/code&gt;&lt;/a&gt; had a bunch of samples that it used to test itself. I figured that if I could get all of those samples to work, then I could be reasonably sure that my implementation was correct.&lt;/p&gt;

&lt;p&gt;It wouldn’t take too long, right? Just a few little tweaks right? Since I’d already dogfooded it in a school project, it should be fine, right?&lt;/p&gt;

&lt;p&gt;Well, you’ve been there for the rest of it.&lt;/p&gt;

&lt;p&gt;Frankly, I’m not even sure I want to continue developing that GUI framework I’d planned after this. Not only is the GUI situation much better than it was back in 2019, but I think it’s just too much work for one person to do. Especially as I’ve graduated college now and entered full-time employment, I’m often lacking the time and energy to do it.&lt;/p&gt;

&lt;p&gt;I’m not sure what to do at this impasse. I think that this package I’m writing, &lt;a href=&quot;https://github.com/notgull/theo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theo&lt;/code&gt;&lt;/a&gt;, will be a net positive for the Rust community, as something like it for &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winit&lt;/code&gt;&lt;/a&gt; doesn’t really exist yet. So I’ll at least finish it. Maybe that’s just the sunk cost fallacy speaking; I don’t know.&lt;/p&gt;

&lt;p&gt;Anyways, we’ve got some text to fix.&lt;/p&gt;

&lt;h2 id=&quot;fixing-cosmic-texts-disappearing-font-problem&quot;&gt;Fixing cosmic-text’s Disappearing Font Problem&lt;/h2&gt;

&lt;p&gt;Anyways, I think I’ve figured out what the issue is, at least on the &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; side.&lt;/p&gt;

&lt;p&gt;In text rendering, there is a concept of “font fallback”. It first tries to load whatever font you requested. This loading keeps parameters like boldness, italics and font size in mind. If it can’t find the font you want, or if you’re rendering characters that aren’t in that font, it tries to find another //fallback// font. It starts off with fonts that &lt;em&gt;look&lt;/em&gt; like the original font, and eventually starts moving onto whatever fonts it’s hardcoded into the system, just to get //something// onto the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; has a system like this, but it turns out that the fonts that it uses as a fallback are missing on my system. Hence, the missing text. Although it is annoying that it didn’t log anything as an error, there’s only one entry buried in the debug log.&lt;/p&gt;

&lt;p&gt;I could “fix” this on my system by just installing the fonts, but I’d also like to fix this across all systems. Text not showing up is a pretty big deal, after all. So what if I embed the fonts that I need into the executable itself, so that you’re never without the font that you need to fall back on?&lt;/p&gt;

&lt;p&gt;The strategy I ended up using was to download the &lt;a href=&quot;https://dejavu-fonts.github.io/&quot;&gt;DejaVu&lt;/a&gt; font collection. Then, in the build script I take these fonts, compress them using the Zlib compression scheme (which saved the most space in my experiments) and then put them in the output directory. &lt;a href=&quot;https://crates.io/crates/piet-cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cosmic-text&lt;/code&gt;&lt;/a&gt; then uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include_bytes!&lt;/code&gt; to embed these fonts into the executable.&lt;/p&gt;

&lt;p&gt;From there, it’s just a matter of telling &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt; to use these fonts as a fallback. Did that fix it?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/pct-incorrect-lines.png&quot; alt=&quot;Nope!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;No, it did not.&lt;/p&gt;

&lt;p&gt;Apparently, the disappearing font comes not from the font fallback, but from shaping. After some review of &lt;a href=&quot;https://crates.io/crates/cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cosmic-text&lt;/code&gt;&lt;/a&gt;’s source code, I think I’ve figured out the real issue. Apparently if the shaper fails to find the ideal glyph ID, it’ll try to shape it again but with another font. If it can’t find that glyph ID in any of the fonts, it’ll just give up and not render anything.&lt;/p&gt;

&lt;p&gt;So I set up a loop that checks each rendered glyph to see if they have a “glyph ID” of zero. If they do, it indicates that we need to change the ID for the better.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-08-kinda-fixed.png&quot; alt=&quot;Kinda&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Okay, we’re &lt;em&gt;almost&lt;/em&gt; there now. It’s justified again (not my fault) and the spacing between the lines is weirdly bolded (is my fault). A simple patch fixes it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-08-final.png&quot; alt=&quot;There&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Close enough for me, for now. The font size is still off, but that’s a job for a later version of myself.&lt;/p&gt;

&lt;h2 id=&quot;sample-10-font-decoration-frolic&quot;&gt;Sample 10: Font Decoration Frolic&lt;/h2&gt;

&lt;p&gt;Alright, this has gone on for long enough, and had far too many tangents. This sample aims to demonstrate how text decorations work, especially with Zalgo text. Please, let this be an easy one.&lt;/p&gt;

&lt;p&gt;Here’s the reference image from &lt;a href=&quot;https://crates.io/crates/piet-cairo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cairo&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cairo-test-10-2.00.png&quot; alt=&quot;Reference&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s what &lt;a href=&quot;https://crates.io/crates/piet-glow&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-glow&lt;/code&gt;&lt;/a&gt; spits out:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-10-2.00.png&quot; alt=&quot;Glow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Augh! So close! Aside from being unnecessarily blurry (and maybe rendering a couple of the decorations wrong, but I figure, &lt;em&gt;close enough&lt;/em&gt;), it seems that the bounding box of the text is wrong. The white rectangle containing the text should be smaller.&lt;/p&gt;

&lt;p&gt;Apparently the black outer rectangle corresponds to the “ink rectangle”, which represents the total extent of the text. The rectangle should go around everywhere the text touches. Meanwhile, the white text is the “logical extent”. Remember when you were writing text between the lines in middle school, before they all switched to using Chromebooks for everything? The logical extent would go from the top line to the bottom line.&lt;/p&gt;

&lt;p&gt;The logical extent is relatively easy; hell, when we calculated the line metrics above, we basically already got that. The ink metrics are the harder part, because it’s hard to tell from the parsed font alone. For vector graphics you can figure out the bounding box, and we can take a similar strategy from the raster image.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-10-bad-bbox.png&quot; alt=&quot;BboxIssues&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wow, not even close.&lt;/p&gt;

&lt;p&gt;Actually, you know what? We’re long past the point of “doing things right”. You know what the bulletproof way of doing this is? Actually rendering the text, then taking the bounding box of that.&lt;/p&gt;

&lt;p&gt;Here’s the candidate for the worst code I’ve written so far:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;font_system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;SwashCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.y0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.y0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.x1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.y1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ink_rectangle&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, I’m not proud of this code. It basically goes through the entire rendering process and created a new cache &lt;em&gt;just&lt;/em&gt; to calculate the ink rectangle. Let’s clean it up a little:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Rather than using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Buffer::draw&lt;/code&gt;, I use &lt;a href=&quot;https://docs.rs/swash/latest/swash/scale/struct.Scaler.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swash::Scaler&lt;/code&gt;&lt;/a&gt;, which is how &lt;a href=&quot;https://crates.io/crates/swash&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swash&lt;/code&gt;&lt;/a&gt; calculates the bounding boxes of the text in the first place. Unfortunately a small amount of rendering takes place, but that’s okay. It puts a permanent dependency on &lt;a href=&quot;https://crates.io/crates/swash&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swash&lt;/code&gt;&lt;/a&gt; for &lt;a href=&quot;https://crates.io/crates/piet-cosmic-text&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cosmic-text&lt;/code&gt;&lt;/a&gt;, which may make it harder to swap out the renderer for downstream crates.&lt;/li&gt;
  &lt;li&gt;Rather than creating a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SwashCache&lt;/code&gt; every time, the shaping context is cached inside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Text&lt;/code&gt; handle.&lt;/li&gt;
  &lt;li&gt;We use a hash map to store the bounding boxes of each glyph, so that we don’t have to calculate them every time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After all of that, we get a decent enough performance boost, followed by a decent enough result:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/piet-glow-10-final.png&quot; alt=&quot;Final&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If anything, I’d argue that it’s &lt;em&gt;more&lt;/em&gt; accurate than &lt;a href=&quot;https://crates.io/crates/piet-cairo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piet-cairo&lt;/code&gt;&lt;/a&gt;’s sample.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Well, this has been a roller coaster so far, and it’s still far from over. This isn’t even the last we’ll see of text rendering, but I think I’ll try to take a break from it for now. &lt;a href=&quot;/quest-for-piet-part-4/&quot;&gt;Next time&lt;/a&gt;, we’ll see if we can figure out the rest of the samples.&lt;/p&gt;</content><author><name>John Nunley</name></author><category term="gui" /><category term="rust" /><category term="piet" /><category term="drawing" /><category term="questforpiet" /><summary type="html">Tantrum over Text</summary></entry></feed>