<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Crystal Durham</title>
    <description>The latest articles on DEV Community by Crystal Durham (@cad97).</description>
    <link>https://dev.to/cad97</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F22216%2F417d1d62-736b-47e2-b618-ffcad5782a5e.png</url>
      <title>DEV Community: Crystal Durham</title>
      <link>https://dev.to/cad97</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cad97"/>
    <language>en</language>
    <item>
      <title>dyn* doesn't need to be special</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Thu, 07 Apr 2022 16:05:39 +0000</pubDate>
      <link>https://dev.to/cad97/dyn-doesnt-need-to-be-special-3ldm</link>
      <guid>https://dev.to/cad97/dyn-doesnt-need-to-be-special-3ldm</guid>
      <description>&lt;p&gt;or: more storage API propaganda&lt;/p&gt;

&lt;p&gt;A response to &lt;a href="https://twitter.com/nikomatsakis" rel="noopener noreferrer"&gt;@nikomatsakis&lt;/a&gt;'s &lt;a href="https://smallcultfollowing.com/babysteps//blog/2022/03/29/dyn-can-we-make-dyn-sized/" rel="noopener noreferrer"&gt;dyn*: can we make dyn sized?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dyn* Trait&lt;/code&gt; is a way to own a value of &lt;code&gt;dyn Trait&lt;/code&gt; without knowing how the pointee is stored. In short, &lt;code&gt;dyn* Trait&lt;/code&gt; acts as "&lt;code&gt;&amp;amp;move dyn Trait&lt;/code&gt;", owning the pointee and dropping it, while also containing a clever feature I'm calling "owning vtables" allowing it to also transparently own the memory the pointee is stored in.&lt;/p&gt;

&lt;p&gt;When you have a normal &lt;code&gt;Box&amp;lt;dyn Trait&amp;gt;&lt;/code&gt;, the pointer itself looks something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Trait&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NonNull&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vtable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="n"&gt;TraitVtable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the vtable something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;TraitVtable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Trait&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;new&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;drop_in_place&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;drop_in_place&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ... the contents of Trait&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so that &lt;code&gt;dyn Trait&lt;/code&gt; can recover the type information needed to interact with the pointee. The trick of &lt;code&gt;dyn*&lt;/code&gt; is in using an owning vtable, best explained with a simple example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Box&amp;lt;T as dyn Trait&amp;gt;&lt;/code&gt;'s vtable's &lt;code&gt;drop_in_place&lt;/code&gt; is &lt;code&gt;ptr::drop_in_place::&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Box&amp;lt;T as dyn Trait&amp;gt; as dyn* Trait&lt;/code&gt;'s vtable's &lt;code&gt;drop_in_place&lt;/code&gt; is &lt;code&gt;Box::drop&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this manner, any smart pointer with an &lt;code&gt;into_raw(self) -&amp;gt; *mut T&lt;/code&gt; can be owned transparently as &lt;code&gt;dyn* Trait&lt;/code&gt; by generating a new vtable which replaces &lt;code&gt;drop_in_place&lt;/code&gt; with a shim that &lt;code&gt;from_raw&lt;/code&gt;s the smart pointer and then drops it&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;With more complicated vtable shims, you can even shove any pointer-sized value into a &lt;code&gt;dyn*&lt;/code&gt;, by dealing it a data "pointer" of &lt;code&gt;ptr::invalid(value)&lt;/code&gt; and the vtable shimming back to the original trait implementation on &lt;code&gt;value&lt;/code&gt; directly.&lt;/p&gt;




&lt;p&gt;And now, we need to talk about the &lt;a href="https://github.com/matthieu-m/storage-poc" rel="noopener noreferrer"&gt;storages API proposal&lt;/a&gt; for a bit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" alt="Cool Bear Says" width="68" height="90"&gt;&lt;/a&gt; But what does this have to with &lt;code&gt;dyn*&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll get there! ... Hey, does &lt;a href="https://fasterthanli.me/" rel="noopener noreferrer"&gt;Amos&lt;/a&gt; know you're here?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" alt="Cool Bear Says" width="68" height="90"&gt;&lt;/a&gt; Actually, &lt;a href="https://twitter.com/fasterthanlime/status/1512075785196081161?s=20&amp;amp;t=ZQ_QUBFQ6GlPv10Vu6WVyw" rel="noopener noreferrer"&gt;yes&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;... Anyway, on the current nightly, &lt;code&gt;Box&lt;/code&gt; and other allocating types are generic over &lt;a href="https://doc.rust-lang.org/nightly/std/alloc/trait.Allocator.html" rel="noopener noreferrer"&gt;&lt;code&gt;trait Allocator&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;Allocator&lt;/code&gt; is a fairly standard abstraction over heap allocation, providing methods &lt;code&gt;fn allocate(&amp;amp;self, Layout) -&amp;gt; Result&amp;lt;ptr::NonNull&amp;lt;[u8]&amp;gt;, AllocError&amp;gt;&lt;/code&gt; and &lt;code&gt;fn deallocate(&amp;amp;self, ptr::NonNull&amp;lt;u8&amp;gt;, Layout)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The storages API adds another layer on top of this, dealing in a generic &lt;code&gt;Self::Handle&amp;lt;T&amp;gt;&lt;/code&gt; type instead of &lt;code&gt;ptr::NonNull&amp;lt;T&amp;gt;&lt;/code&gt; directly. In short&lt;sup id="fnref2"&gt;2&lt;/sup&gt;:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nb"&gt;Sized&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Pointee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 👇&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NonNull&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To illustrate the benefit, consider a potential implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;InlineStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UnsafeCell&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MaybeUninit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="nf"&gt;.size&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PhantomAlignTo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="nf"&gt;.align&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;InlineStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nb"&gt;Sized&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Pointee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;!&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="c1"&gt;// 👇&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NonNull&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;NonNull&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_raw_parts&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.cast&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can have &lt;code&gt;Box&amp;lt;T, InlineStorage&amp;lt;Layout::new::&amp;lt;T&amp;gt;()&amp;gt;&amp;gt;&lt;/code&gt; be layout-equivalent to storing &lt;code&gt;T&lt;/code&gt; directly on the stack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" alt="Cool Bear Says" width="68" height="90"&gt;&lt;/a&gt; Amazing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More importantly, though, is that you can have &lt;code&gt;Box&amp;lt;dyn Trait, InlineStorage&amp;lt;Layout::new::&amp;lt;T&amp;gt;()&amp;gt;&amp;gt;&lt;/code&gt; &lt;em&gt;also&lt;/em&gt; be layout-equivalent to storing &lt;code&gt;T&lt;/code&gt; directly on the stack (plus a vtable pointer), but type-erased so you don't actually know about &lt;code&gt;T&lt;/code&gt; anymore.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" alt="Cool Bear Says" width="68" height="90"&gt;&lt;/a&gt; Oh, I think I see where you're going with this!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, if we add a fallback to heap allocation ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;SmallStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Allocator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Global&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InlineStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AllocStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;SmallStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nb"&gt;Sized&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NonNull&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AllocError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Pointee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AllocError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;for_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="nf"&gt;.fits_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.inline&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.outline&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;NonNull&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_raw_parts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="nf"&gt;.dangling&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="nf"&gt;.metadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;for_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="nf"&gt;.fits_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.inline&lt;/span&gt;&lt;span class="nf"&gt;.destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.outline&lt;/span&gt;&lt;span class="nf"&gt;.destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NonNull&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="nf"&gt;.metadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;for_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="nf"&gt;.fits_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LAYOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.inline&lt;/span&gt;&lt;span class="nf"&gt;.resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.outline&lt;/span&gt;&lt;span class="nf"&gt;.resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and maybe a type alias for convenience ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Dyn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nb"&gt;Sized&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SmallStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;new&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have the functionality of &lt;code&gt;dyn*&lt;/code&gt; as a library type! Instead of &lt;code&gt;dyn* Trait&lt;/code&gt;, we have &lt;code&gt;Dyn&amp;lt;dyn Trait&amp;gt;&lt;/code&gt; (the stutter is unfortunate&lt;sup id="fnref3"&gt;3&lt;/sup&gt;). This is our type that is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The size of &lt;code&gt;Box&amp;lt;dyn Trait&amp;gt;&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Stores small values of &lt;code&gt;dyn Trait&lt;/code&gt; inline, and&lt;/li&gt;
&lt;li&gt;Owns the storage of &lt;code&gt;dyn Trait&lt;/code&gt;, dellocating it on drop.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" alt="Cool Bear Says" width="68" height="90"&gt;&lt;/a&gt; But wait, you're still missing something.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What, Cool Bear?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6izja91mzp1qo6krqwz.png" alt="Cool Bear Says" width="68" height="90"&gt;&lt;/a&gt; &lt;code&gt;dyn*&lt;/code&gt; can hold &lt;em&gt;any&lt;/em&gt; smart pointer, not just &lt;code&gt;Box&lt;/code&gt;. You said so yourself!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, but there's a catch: &lt;code&gt;dyn*&lt;/code&gt; needs to be &lt;code&gt;DerefMut&lt;/code&gt; if it wants to fulfil its life goal of facilitating &lt;code&gt;Pin&amp;lt;dyn* Future&amp;gt;&lt;/code&gt; usage. This means that it's restricted to single-ownership smart pointers wait hey that sounds like &lt;code&gt;Box&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's my belief that there aren't really any &lt;code&gt;Pin&amp;lt;P&amp;lt;dyn Future&amp;gt;&amp;gt;&lt;/code&gt; types out there for a &lt;code&gt;P&lt;/code&gt; that's not &lt;code&gt;&amp;amp;mut&lt;/code&gt; or &lt;code&gt;Box&lt;/code&gt;. I don't have any proof, just a feeling.&lt;/p&gt;

&lt;p&gt;But the storages &lt;code&gt;Dyn&lt;/code&gt; can be extended to support other &lt;code&gt;DerefMut&lt;/code&gt; smart pointers, though it &lt;em&gt;might&lt;/em&gt; require a second vtable pointer without the language support for easily wrapping the vtable into an owning vtable&lt;sup id="fnref4"&gt;4&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;So, storages get us the benefit of &lt;code&gt;dyn*&lt;/code&gt; without any of the main problems with &lt;code&gt;dyn*&lt;/code&gt;. I think that more than justifies bringing the storages API to std so we can properly spin the wheels on this design and find where it falls short. There's definitely flaws in the storages proposal I haven't spotted yet&lt;sup id="fnref5"&gt;5&lt;/sup&gt;, but we need to use it to find the rest of them.&lt;/p&gt;

&lt;p&gt;Oh, and &lt;code&gt;&amp;amp;move&lt;/code&gt; also falls out of storages as &lt;code&gt;Box&amp;lt;T, &amp;amp;mut MaybeUninit&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;, so that's even more proposed language features handled by the library feature. The storage API is good.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;You can do clever things to avoid the &lt;code&gt;from_raw&lt;/code&gt; shim, like with &lt;code&gt;Box&lt;/code&gt;, where you can just call &lt;code&gt;Box::drop&lt;/code&gt; directly, by patching up the other vtable members to take into account the container the smart pointer puts it in. However, since you use the &lt;code&gt;dyn*&lt;/code&gt; many times and only drop it once, it seems better to just shim &lt;code&gt;drop_in_place&lt;/code&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;For brevity, I omit a lot of details included in the full proposal. Notably, I omit a lot of safety concerns that are put on the user, and the full proposal has static controls for whether a storage can only create a single handle at a time or manages multiple handles, whether a handle is to a single element or to a slice of elements, as well as whether you need exclusive access to the storage to get mutable access to the pointee. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;In the olden days (before Rust 2018), we didn't have &lt;code&gt;dyn Trait&lt;/code&gt;, it was just &lt;code&gt;&amp;amp;Trait&lt;/code&gt;. &lt;code&gt;dyn Trait&lt;/code&gt; is better, because you can immediately know that you're dealing with a &lt;code&gt;dyn&lt;/code&gt; type rather than a fixed type. However, in this &lt;em&gt;one&lt;/em&gt; specific case, omitting the &lt;code&gt;dyn&lt;/code&gt; &lt;em&gt;would&lt;/em&gt; allow us to write &lt;code&gt;Dyn&amp;lt;Trait&amp;gt;&lt;/code&gt; instead, so it's impossible to say if it's good or not,, ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Then remaining concern is actually unowning references like &lt;code&gt;&amp;amp;mut dyn Trait&lt;/code&gt;. The important thing to note here is that &lt;code&gt;Box&amp;lt;Type, Storage&amp;gt;&lt;/code&gt; gives us two axis of customization: I've talked here about &lt;code&gt;Storage&lt;/code&gt; for customization of the owning memory, but &lt;code&gt;Type&lt;/code&gt; still gives us customization over how its used. For &lt;code&gt;fn(&amp;amp;mut dyn Trait) -&amp;gt; Dyn&amp;lt;dyn Trait&amp;gt;&lt;/code&gt;, you can wrap the vtable to remove any drop glue with e.g. &lt;code&gt;ManuallyDrop&amp;lt;dyn Trait&amp;gt;&lt;/code&gt;. This is where language support would be useful. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;In fact, I &lt;a href="https://github.com/matthieu-m/storage-poc/issues/3" rel="noopener noreferrer"&gt;spotted one while drafting this post&lt;/a&gt;; as currently prototyped, storages are unsound, because the only handle resolution option is by-shared-ref and inline storages aren't using &lt;code&gt;UnsafeCell&lt;/code&gt;, thus ultimately violating the aliasing guarantees 💣💥😱 ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>design</category>
    </item>
    <item>
      <title>Dynamically Aligned Types?</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Mon, 11 Jan 2021 03:54:35 +0000</pubDate>
      <link>https://dev.to/cad97/dynamically-aligned-types-360i</link>
      <guid>https://dev.to/cad97/dynamically-aligned-types-360i</guid>
      <description>&lt;p&gt;At this point, you're probably aware of what a &lt;em&gt;dynamically sized type&lt;/em&gt;, or &lt;em&gt;DST&lt;/em&gt;, is. They're types like &lt;code&gt;[Type]&lt;/code&gt; (&lt;em&gt;slices&lt;/em&gt;) or &lt;code&gt;dyn Trait&lt;/code&gt; (&lt;em&gt;trait object&lt;/em&gt;) which don't have a singular known size at compile time. As a result, you can't have a binding with a DST type (e.g. &lt;code&gt;let x: [u8]&lt;/code&gt;); every DST has to be behind an indirection (e.g. &lt;code&gt;let x: &amp;amp;[u8]&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Currently in stable Rust, the only dynamically sized types are slices, trait objects, and structs that contain one of those two DSTs. For these, references are "fat": whereas &lt;code&gt;&amp;amp;u8&lt;/code&gt; is physically just a &lt;code&gt;*const u8&lt;/code&gt; pointer to a memory location, &lt;code&gt;&amp;amp;[u8]&lt;/code&gt; is a &lt;code&gt;(*const u8, usize)&lt;/code&gt; pair, where the second number is the length of the slice. &lt;code&gt;&amp;amp;dyn Trait&lt;/code&gt; is roughly &lt;code&gt;(*const ?, &amp;amp;'static VTable)&lt;/code&gt;, where the pointer is to the object, and the vtable reference holds all of the information about the trait impl. The size is then calculated (in the case of slices) or retrieved (in the case of vtables) when asked for (e.g. by &lt;code&gt;mem::size_of_val&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;But what about alignment (and &lt;code&gt;mem::align_of_val&lt;/code&gt;)? For slices, it's still statically known; &lt;code&gt;[T]&lt;/code&gt; has the same alignment as &lt;code&gt;T&lt;/code&gt;. But for trait objects, alignment can vary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nb"&gt;Sync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;0u16&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nb"&gt;Sync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;0u64&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;align_of_val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;align_of_val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[src/main.rs:6] mem::align_of_val(a) = 2
[src/main.rs:7] mem::align_of_val(b) = 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entering the picture, though, are &lt;em&gt;custom&lt;/em&gt; DSTs. There's no specific design that the lang team have endorsed, but there are &lt;a href="https://github.com/rust-lang/rfcs/pull/2594" rel="noopener noreferrer"&gt;various RFCs&lt;/a&gt; already available, and we can think about what we would like from such a feature and what restrictions the language already places on it.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;I am not necessarily endorsing the linked RFC specifically, just using it as an example.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;The headlining feature for custom DST proposals is the ability to have "thin" DSTs: ones where the pointer is just a pointer, without any extra metadata. (Equivalently, with zero-sized metadata, probably &lt;code&gt;()&lt;/code&gt;.) Optimally (using the above-linked RFC's terms) we could have something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[repr(C)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Thin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nb"&gt;Sized&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Pointee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so you could have e.g. &lt;code&gt;&amp;amp;Thin&amp;lt;_&amp;gt;&lt;/code&gt; to create a thin-reference supporting value for &lt;em&gt;any&lt;/em&gt; type, by just storing the pointer metadata alongside it.&lt;/p&gt;

&lt;p&gt;While that specific definition won't ever work (as &lt;code&gt;&amp;amp;Thin&amp;lt;_&amp;gt;&lt;/code&gt; inherit pointee metadata from its tail), if alignment is statically known, this is a fairly simple task to accomplish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example only; uses imaginary made up APIs&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nb"&gt;Sized&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Deref&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Thin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;deref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Thin is repr(C), so meta is&lt;/span&gt;
        &lt;span class="c1"&gt;//   the first field without extra padding&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Pointee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Calculate the offset to T&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;meta_layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;new&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;T&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;meta_layout&lt;/span&gt;&lt;span class="nf"&gt;.size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;meta_layout&lt;/span&gt;&lt;span class="nf"&gt;.padding_needed_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;align_of&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="c1"&gt;// Assemble pointer to T&lt;/span&gt;
        &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_raw_parts&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but as we showed above, for &lt;code&gt;dyn Trait&lt;/code&gt;, the alignment &lt;em&gt;isn't&lt;/em&gt; statically known! For &lt;code&gt;dyn Trait&lt;/code&gt;, you need to have the metadata to look up the alignment. Should be simple enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;        &lt;span class="c1"&gt;// Calculate the offset to T&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;meta_layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;new&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;T&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data_align&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Pointee&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;align_with_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;meta_layout&lt;/span&gt;&lt;span class="nf"&gt;.size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;meta_layout&lt;/span&gt;&lt;span class="nf"&gt;.padding_needed_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_align&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this runs into a problem: how do I get the alignment of a &lt;code&gt;Thin&amp;lt;_&amp;gt;&lt;/code&gt;? If it's &lt;code&gt;Pointee::align_with_meta(Metadata)&lt;/code&gt;, you can't: &lt;code&gt;Thin&lt;/code&gt; doesn't have any pointer metadata, and the information you need to find the alignment is behind the pointer. So, change this to be &lt;code&gt;Pointee::align_of_val(&amp;amp;self)&lt;/code&gt;, then? But that runs into a chicken-and-egg problem: when composing the value in a containing type, you need to know the alignment to know the offset of the value in order to get a pointer to it!&lt;/p&gt;

&lt;p&gt;So, one of two things has to be true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For any type, it's possible to get its alignment with just the pointer metadata, independent of whether you have a valid pointer to an instance of the type, or&lt;/li&gt;
&lt;li&gt;The above is true for &lt;code&gt;T: ?Sized&lt;/code&gt;, and a new &lt;code&gt;?&lt;/code&gt; bound is added for unsized types that &lt;em&gt;actually&lt;/em&gt; can't be held by value / composed around, only behind an indirection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second option, tbh, sounds horrible. This "&lt;code&gt;?SimpleAlignment&lt;/code&gt;" is &lt;em&gt;less&lt;/em&gt; motivated than &lt;code&gt;?DynSized&lt;/code&gt; (for actually unknowable size, e.g. &lt;code&gt;extern type&lt;/code&gt;), and even &lt;code&gt;?DynSized&lt;/code&gt; is fighting tooth and nail (and losing) to avoid being added to the do-not-call list. It would be really nice to have an inline &lt;code&gt;Thin&amp;lt;dyn Trait&amp;gt;&lt;/code&gt; so that composition can just work — &lt;code&gt;&amp;amp;[mut] Thin&amp;lt;dyn Trait&amp;gt;&lt;/code&gt;, &lt;code&gt;Box&amp;lt;Thin&amp;lt;dyn Trait&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;Rc&amp;lt;Thin&amp;lt;dyn Trait&amp;gt;&amp;gt;&lt;/code&gt; — but it's not worth the extra pain.&lt;/p&gt;

&lt;p&gt;But it doesn't mean that all is lost, either! By taking a page from &lt;code&gt;Pin&lt;/code&gt;'s playbook, we turn it around, and wrap the pointer rather than the pointee: &lt;code&gt;Thin&amp;lt;&amp;amp;[mut] dyn Trait&amp;gt;&lt;/code&gt;, &lt;code&gt;Thin&amp;lt;Rc&amp;lt;dyn Trait&amp;gt;&amp;gt;&lt;/code&gt;, etc. This doesn't &lt;em&gt;quite&lt;/em&gt; just work, since we do need to add extra data to the heap part, so it'd be &lt;code&gt;Thin&amp;lt;&amp;amp;Thinnable&amp;lt;dyn Trait&amp;gt;&amp;gt;&lt;/code&gt;, which is a bit repetitive, but it shows that it's still possible if really desired.&lt;/p&gt;

&lt;p&gt;By the way, I have a &lt;a href="https://docs.rs/erasable/1/erasable/struct.Thin.html" rel="noopener noreferrer"&gt;crate that does exactly this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;TL;DR takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm a shill, use &lt;a href="https://github.com/CAD97/pointer-utils" rel="noopener noreferrer"&gt;my crates&lt;/a&gt;; numbers go up make me feel good.&lt;/li&gt;
&lt;li&gt;Requiring a pointer to get a pointee's alignment is a chicken-and-egg problem; you need the alignment to calculate the offset to produce the pointer. Any custom DST proposal should be &lt;code&gt;Metadata -&amp;gt; Alignment&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It's still possible to use thin pointers to types with dynamic alignment. You just have to un-thin them before actually doing interesting things with them.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.rust-lang.org/core/mem/fn.align_of_val_raw.html" rel="noopener noreferrer"&gt;&lt;code&gt;align_of_val_raw&lt;/code&gt;&lt;/a&gt; can be safe, or at least inherits the safety from &lt;code&gt;Pointee::align_with_meta&lt;/code&gt;, as it's just a different accessor for the same data.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>languagedesign</category>
    </item>
    <item>
      <title>String interners in Rust</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Fri, 10 Jul 2020 04:43:31 +0000</pubDate>
      <link>https://dev.to/cad97/string-interners-in-rust-797</link>
      <guid>https://dev.to/cad97/string-interners-in-rust-797</guid>
      <description>&lt;p&gt;This is basically a direct followup to Amos/fasterthanlime's blog post &lt;a href="https://fasterthanli.me/articles/small-strings-in-rust" rel="noopener noreferrer"&gt;Small strings in Rust&lt;/a&gt;. If you haven't read that, I'd highly suggest reading it first: it covers the techniques that I've &lt;del&gt;stolen&lt;/del&gt; used here, which I won't go over in much detail.&lt;/p&gt;

&lt;p&gt;Amos covers two Rust crates that offer the "small string" optimization: small strings (of less than around 22 bytes) can be stored inline rather than on the heap, like the standard &lt;code&gt;String&lt;/code&gt; type. If you have a large number of small strings, this can greatly reduce allocation pressure.&lt;/p&gt;

&lt;p&gt;Rather than small string optimization, though, for certain use cases an &lt;a href="https://en.wikipedia.org/wiki/String_interning" rel="noopener noreferrer"&gt;interner&lt;/a&gt; is useful. An interner associates a "symbol" with each unique string that you want to manage. You can then very cheaply copy the symbol around and compare symbols, as they're just a single integer (typically 32 bits). If you need the actual contents of the string again (such as for display), you just ask the interner to translate back from your symbol to a string.&lt;/p&gt;

&lt;p&gt;I took a look at a few of the top interning crates for Rust (there are quite a few!) &lt;a href="https://lib.rs/search?q=interner" rel="noopener noreferrer"&gt;as ranked by lib.rs&lt;/a&gt; and compared them to see what their allocation behavior was. The testing harness is basically a direct copy of the one Amos used for small strings.&lt;/p&gt;

&lt;p&gt;Specifically, I've tested&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;string-interner version 0.7.1*&lt;/li&gt;
&lt;li&gt;lasso version 0.2.2*&lt;/li&gt;
&lt;li&gt;lalrpop-intern version 0.15.1&lt;/li&gt;
&lt;li&gt;intaglio version 1.1.0&lt;/li&gt;
&lt;li&gt;strena commit 1ddbf48b9f639ffbb4c89b0d51cb005fc0e3a4f7&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;* These crates have later versions published after this article -- see the postscript for updates.&lt;/p&gt;

&lt;p&gt;I couldn't get the ASCII plot to reproduce properly here, so instead you get some &lt;a href="https://www.chrisstucchio.com/blog/2014/why_xkcd_style_graphs_are_important.html" rel="noopener noreferrer"&gt;xkcd-style plots&lt;/a&gt;. All measurements were done on a Windows machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CAD97/string-interner-comparison/tree/a8fe9effb1838256e538e95d3d68132ec2a68ae0" rel="noopener noreferrer"&gt;Measurement code is available on GitHub.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;std::string::String&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;As a baseline, here's the process with just the standard &lt;code&gt;String&lt;/code&gt; type. We just create a list of owned strings for each of the strings on a word list of 7776 words.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;std_collect_words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORDS&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8kk3cb1vrjeekmqwbn5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8kk3cb1vrjeekmqwbn5h.png" alt="String allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 7777
  peak bytes  | 241.0 KB
 ----------------------------
 alloc events | 7777
 alloc bytes  | 241.0 KB
 ----------------------------
 freed events | 0
 freed bytes  | 0 B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I see a ~190 KB allocation for the words vector, and then a small allocation for each string after.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://lib.rs/crates/string-interner" rel="noopener noreferrer"&gt;&lt;code&gt;string-interner&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A data structure to cache strings efficiently, with minimal memory footprint and the ability to assicate the interned strings with unique symbols. These symbols allow for constant time comparisons and look-ups to the underlying interned string contents. Also, iterating through the interned strings is cache efficient.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note the changing y axis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;interner_collect_words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;string_interner&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;DefaultStringInterner&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORDS&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="nf"&gt;.get_or_intern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnnauw64p4bq45mkh325n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnnauw64p4bq45mkh325n.png" alt="string-interner allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 7778
  peak bytes  | 588.4 KB
 ----------------------------
 alloc events | 7778
 alloc bytes  | 588.4 KB
 ----------------------------
 freed events | 0
 freed bytes  | 0 B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I see a ~540 KB allocation in two chunks for the interner, and then a small allocation for each string after.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://lib.rs/crates/lasso" rel="noopener noreferrer"&gt;&lt;code&gt;lasso&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A multithreaded and single threaded string interner that allows strings to be cached with a minimal memory footprint, associating them with a unique key that can be used to retrieve them at any time. A &lt;code&gt;Rodeo&lt;/code&gt; allows &lt;strong&gt;&lt;em&gt;O&lt;/em&gt;(1)&lt;/strong&gt; internment and resolution and can be turned into a &lt;code&gt;RodeoReader&lt;/code&gt; to allow for contention-free resolutions with both key to str and str to key operations. It can also be turned into a &lt;code&gt;RodeoResolver&lt;/code&gt; with only key to str operations for the lowest possible memory usage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lasso is the only library in this set that has special support for interning from multiple threads. All other libraries always require exclusive access to intern new symbols. We measure the single-thread interner here to be more fair.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lasso_collect_words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;lasso&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Rodeo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;lasso&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Rodeo&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORDS&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="nf"&gt;.get_or_intern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvd5semg09c00y2ys1gl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvd5semg09c00y2ys1gl7.png" alt="lasso allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 23
  peak bytes  | 591.8 KB
 ----------------------------
 alloc events | 20
 alloc bytes  | 592.1 KB
 ----------------------------
 freed events | 3
 freed bytes  | 312 B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I see a ~540 KB allocation in three chunks for the interner, and then a chunked allocation of ~4 KiB around every 550 symbols.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://lib.rs/crates/lalrpop-intern" rel="noopener noreferrer"&gt;&lt;code&gt;lalrpop-intern&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Simple string interner used by LALRPOP&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This test is designed to be a best-case scenario: we know the number of symbols ahead of time and tell the interner about it so it can hopefully pre-allocate. Lalrpop's interner is purely global, though, so we can't do that. This results in a very unfair comparison, so I'm going to defer showing LALRPOP's results until the section without pre-allocation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://lib.rs/crates/intaglio" rel="noopener noreferrer"&gt;&lt;code&gt;intaglio&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;UTF-8 string and bytestring interner and symbol table. Used to implement storage for the &lt;a href="https://ruby-doc.org/core-2.6.3/Symbol.html" rel="noopener noreferrer"&gt;Ruby &lt;code&gt;Symbol&lt;/code&gt;&lt;/a&gt; table and the constant name table in &lt;a href="https://github.com/artichoke/artichoke" rel="noopener noreferrer"&gt;Artichoke Ruby&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;intaglio_collect_words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;intaglio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;SymbolTable&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORDS&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="nf"&gt;.intern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgug15f8ehiasutlxduqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgug15f8ehiasutlxduqa.png" alt="intaglio allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 2
  peak bytes  | 606.2 KB
 ----------------------------
 alloc events | 2
 alloc bytes  | 606.2 KB
 ----------------------------
 freed events | 0
 freed bytes  | 0 B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;... wait, what‽ Oh, right, intaglio has special handling when interning &lt;code&gt;&amp;amp;'static str&lt;/code&gt; which doesn't bother to copy the strings and just refers to the static string you gave it. Smart, but for a fair comparison we need to stop it from doing that...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;intaglio_dyn_collect_words&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;intaglio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;SymbolTable&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORDS&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="nf"&gt;.intern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyc1k03klm99pfsipwd5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyc1k03klm99pfsipwd5i.png" alt="intaglio allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 7778
  peak bytes  | 660.6 KB
 ----------------------------
 alloc events | 7778
 alloc bytes  | 660.6 KB
 ----------------------------
 freed events | 0
 freed bytes  | 0 B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I see a ~610 KB allocation in two chunks for the interner, and then a small allocation for each string after.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/cad97/strena" rel="noopener noreferrer"&gt;&lt;code&gt;strena&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;As opposed to most other interners, this interner stores all of the interned strings in a single concatenated string. This reduces allocation space required for the interned strings, as well as fragmentation of the memory held by the interner.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a new string interner I've written with the intent of reducing the amount of fragmented memory a string interner has to hold (thus this comparison). Hopefully it does well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;strena_collect_words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;strena&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Interner&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;strena&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Capacity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// google says average word length is 4.7&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="nf"&gt;.get_or_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.mark_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALLOCATOR&lt;/span&gt;&lt;span class="nf"&gt;.set_active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjqpznc47oxqasqagvi4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjqpznc47oxqasqagvi4z.png" alt="strena allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 5
  peak bytes  | 260.8 KB
 ----------------------------
 alloc events | 4
 alloc bytes  | 260.8 KB
 ----------------------------
 freed events | 1
 freed bytes  | 38.9 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I see a ~180 KB allocation in three chunks for the interner, and then a single realloc around 5.5k symbols in, likely because our wordlist has an average word length greater than five.&lt;/p&gt;

&lt;p&gt;The benchmark was basically chosen to show off strena's strong side, though, so digest it with that in mind. I can tell it exactly how to pre-allocate to fit the incoming data.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what?
&lt;/h2&gt;

&lt;p&gt;We've learned that intaglio is the only interner (of these highly ranked ones) that has special support for interning already-&lt;code&gt;'static&lt;/code&gt; strings, and that lasso is the only published one that doesn't allocate every interned string separately. However, we also see that using an &lt;strong&gt;&lt;em&gt;O&lt;/em&gt;(1)&lt;/strong&gt; interner does have a noticeable memory impact over just a list of strings. At this scale, string-interner has approximately a 145% overhead; lasso, 145%; intaglio, 175%; strena, 10%.&lt;/p&gt;

&lt;p&gt;lasso is already doing half of the clever things strena is doing, though; I'll see if it's possible to reduce lasso's memory overhead before publishing strena myself.&lt;/p&gt;

&lt;p&gt;But this is a deliberately-crafted best-case scenario for strena, so&lt;/p&gt;

&lt;h2&gt;
  
  
  What if it's not best-case?
&lt;/h2&gt;

&lt;p&gt;I've adjusted each of the test cases to default-construct the interner. Rapid-fire, how do each of the interners perform in this situation?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc04zzli4c71zpwmjmdfj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc04zzli4c71zpwmjmdfj.png" alt="string allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 7799
  peak bytes  | 323.4 KB
 ----------------------------
 alloc events | 7788
 alloc bytes  | 447.5 KB
 ----------------------------
 freed events | 11
 freed bytes  | 196.5 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F75jw7ybu3onpnxv45w7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F75jw7ybu3onpnxv45w7m.png" alt="string-interner allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 7826
  peak bytes  | 795.6 KB
 ----------------------------
 alloc events | 7802
 alloc bytes  | 1.1 MB
 ----------------------------
 freed events | 24
 freed bytes  | 540.8 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff1ullaf5vxldh83qqr3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff1ullaf5vxldh83qqr3r.png" alt="lasso allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 71
  peak bytes  | 799.1 KB
 ----------------------------
 alloc events | 44
 alloc bytes  | 1.1 MB
 ----------------------------
 freed events | 27
 freed bytes  | 541.1 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7e2uo52r9eytvb500l74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7e2uo52r9eytvb500l74.png" alt="lalrpop allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 15602
  peak bytes  | 1.1 MB
 ----------------------------
 alloc events | 15578
 alloc bytes  | 1.6 MB
 ----------------------------
 freed events | 24
 freed bytes  | 737.3 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0ivmz63qrziov9v1p6xf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0ivmz63qrziov9v1p6xf.png" alt="intaglio (static) allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 6
  peak bytes  | 811.0 KB
 ----------------------------
 alloc events | 4
 alloc bytes  | 909.3 KB
 ----------------------------
 freed events | 2
 freed bytes  | 303.1 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Intaglio has a default capacity of 4096, so it &lt;em&gt;really&lt;/em&gt; cheats this measurement. I've used a starting capacity of 0 for the dynamic test for a fair comparison, but keep in mind that you probably do want to prime the interner with a decent capacity estimate you plan to fill.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0s354t3gaiurxklhn43y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0s354t3gaiurxklhn43y.png" alt="intaglio (dyn) allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 7828
  peak bytes  | 861.2 KB
 ----------------------------
 alloc events | 7803
 alloc bytes  | 1.3 MB
 ----------------------------
 freed events | 25
 freed bytes  | 606.3 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj0blvog5vcxellqyad7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj0blvog5vcxellqyad7u.png" alt="strena allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 75
  peak bytes  | 254.0 KB
 ----------------------------
 alloc events | 39
 alloc bytes  | 426.1 KB
 ----------------------------
 freed events | 36
 freed bytes  | 213.1 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  So what? (again)
&lt;/h2&gt;

&lt;p&gt;For a simple overview, here's the overhead over the simple string collecting approach for each library, in peak memory usage, total bytes allocated, and total bytes freed:&lt;/p&gt;

&lt;p&gt;string-interner: 145% / 145% / 175%&lt;br&gt;
lasso: 150% / 145% / 175%&lt;br&gt;
lalrpop: 240% / 260% / 275%&lt;br&gt;
intaglio (dyn): 165% / 190% / 205%&lt;br&gt;
strena: -10% / -5% / 5%&lt;/p&gt;

&lt;p&gt;Whoops, I accidentally made my library look really good again. And keep in mind: this is something of a worst-case for interners, as we just straight insert a single symbol at a time for 7776 symbols.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;I'll leave a final interpretation of the data I've gathered here to you, the reader. For me, I think I'd recommend using lasso currently, and I plan to see if I can upstream some of the cleverness in strena to lasso to decrease their memory usage closer to strena's.&lt;/p&gt;




&lt;h2&gt;
  
  
  One weekend later...
&lt;/h2&gt;

&lt;p&gt;and we've got new versions of both string-interner (v0.11) and lasso (v0.3) taking advantage the approach strena uses to minimize memory usage!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2r6p2b96w04f02x5ryhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2r6p2b96w04f02x5ryhz.png" alt="string-interner allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 66
  peak bytes  | 319.9 KB
 ----------------------------
 alloc events | 41
 alloc bytes  | 492.3 KB
 ----------------------------
 freed events | 25
 freed bytes  | 213.4 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9v6v02ow7vralxkeke90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9v6v02ow7vralxkeke90.png" alt="lasso allocation graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; total events | 41
  peak bytes  | 409.7 KB
 ----------------------------
 alloc events | 24
 alloc bytes  | 634.0 KB
 ----------------------------
 freed events | 17
 freed bytes  | 285.8 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The remaining difference in memory usage is likely down to different cache growth strategies. The different libraries are "ahead" at different points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7sd7lz99vpdi9g3wjsws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7sd7lz99vpdi9g3wjsws.png" alt="allocation comparison graph" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, both libraries have added (the ability to take advantage of) the &lt;code&gt;&amp;amp;'static str&lt;/code&gt; optimization from intaglio. The fastest allocation is one you don't have to do, after all!&lt;/p&gt;

&lt;p&gt;Open Source really did work in this instance, and I feel strena has served its purpose as a research project and doesn't need to be published. string-interner and lasso are better for it and you can take advantage of one of those instead.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>review</category>
      <category>interners</category>
    </item>
    <item>
      <title>"try fn" without special-casing Result</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Thu, 09 Apr 2020 03:01:07 +0000</pubDate>
      <link>https://dev.to/cad97/try-fn-without-special-casing-result-4m5b</link>
      <guid>https://dev.to/cad97/try-fn-without-special-casing-result-4m5b</guid>
      <description>&lt;p&gt;There has been much talk recently about "&lt;code&gt;try fn&lt;/code&gt;" in Rust. This is to add some fuel to the fire and address one major argument against &lt;code&gt;try&lt;/code&gt;-like sugar for functions: the special casing of &lt;code&gt;Result&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is explicitly not supposed to be a proposal. This is just meant to open discussion on a new avenue of the "&lt;code&gt;try fn&lt;/code&gt;" design space I haven't seen mentioned yet.&lt;/p&gt;

&lt;p&gt;Quickly summarizing the potential feature (but please, don't focus on the concrete syntax):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;initial_buffer_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="nf"&gt;.read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;essentially would desugar to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;read_to_string&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Return&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;
    &lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Try&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;initial_buffer_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="nf"&gt;.read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;except &lt;code&gt;return&lt;/code&gt; would be subject to the &lt;a href="https://github.com/rust-lang/rust/issues/70941" rel="noopener noreferrer"&gt;exact same "ok wrapping" behavior as the trailing expression&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;So, how do we make this feature "worth it"? This would make a lot of code generic that would not necessarily have been generic if it were written as a normal &lt;code&gt;fn() -&amp;gt; Result&amp;lt;Ok, Error&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first step is to realize that &lt;code&gt;Try&lt;/code&gt; is just "isomorphic to &lt;code&gt;Result&lt;/code&gt;," at least in the current definition. The compiler could just compile the function as a &lt;code&gt;-&amp;gt; Result&amp;lt;Ok, Error&amp;gt;&lt;/code&gt; function, and then insert the required &lt;code&gt;Try&lt;/code&gt; conversion boilerplate into the caller if it wanted a different &lt;code&gt;Try&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;But more importantly, I think the value of a &lt;code&gt;try fn&lt;/code&gt; goes hand-in-hand with an "error side-channel" / &lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf" rel="noopener noreferrer"&gt;"lightweight exception"&lt;/a&gt; mechanism. &lt;code&gt;try fn&lt;/code&gt; would be the way you explicitly suggest the compiler use this mechanism.&lt;/p&gt;

&lt;p&gt;I don't want to go into exactly what an alternate ABI for &lt;code&gt;Result&lt;/code&gt;/&lt;code&gt;Try&lt;/code&gt; would look like for Rust; I don't perfectly understand it myself. What I do understand, though, is that it's an optimization of the happy path over the cold path. It's &lt;em&gt;purely&lt;/em&gt; an optimization over &lt;code&gt;-&amp;gt; Result&lt;/code&gt; semantics, and should be viewed as such: something the compiler can turn on and off depending on whether it thinks the optimization is beneficial (to the non-error path).&lt;/p&gt;

&lt;p&gt;But I do think this kind of &lt;code&gt;try fn&lt;/code&gt; is useful to explicitly say "hey, the &lt;code&gt;Try::Error&lt;/code&gt; case here is cold," and "optimize for the &lt;code&gt;Try::Ok&lt;/code&gt; case." But at the same time, it's mostly useful when most calls into &lt;code&gt;try fn&lt;/code&gt; are immediately just annotated with &lt;code&gt;?&lt;/code&gt; themselves, passing along the error.&lt;/p&gt;

&lt;p&gt;And I think that may be where the disconnect on the usefulness or "viability" of &lt;code&gt;try fn&lt;/code&gt; is. For the majority case, I think &lt;em&gt;library code should not be using &lt;code&gt;try fn&lt;/code&gt;&lt;/em&gt;. &lt;code&gt;try fn&lt;/code&gt; should be used for functions that are primarily just "application style," passing up some mostly opaque &lt;code&gt;eyre::ErrReport&lt;/code&gt; that will be caught and logged at some top level. For applications, the error case is an expected failure, but one that you can't really do much about other than acknowledge and move on.&lt;/p&gt;




&lt;p&gt;As a final step: say we decide &lt;code&gt;try fn&lt;/code&gt; is worth it on the argument above, and send it off to the bikeshed factory to await (pun intended) its final syntax form. How do we make it actually useful, rather than just theoretically desirable?&lt;/p&gt;

&lt;p&gt;The main one will be defaulting the return type to be &lt;code&gt;Result&lt;/code&gt; if the concrete return type is needed (i.e. it's not immediately &lt;code&gt;?&lt;/code&gt; applied). Doing so might allow the standard library to use &lt;code&gt;try fn&lt;/code&gt; for things like &lt;code&gt;fs::read_to_string&lt;/code&gt; above.&lt;/p&gt;

&lt;p&gt;But I also think that it ties in to the greater error handling story in Rust, which is far from a solved problem. The utility of a &lt;code&gt;try fn&lt;/code&gt; mechanism is inherently tied to the shape of errors it carries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reddit.com/r/rust/comments/fxkpjd/try_fn_without_specialcasing_result" rel="noopener noreferrer"&gt;Discuss this on Reddit&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>languagedesign</category>
    </item>
    <item>
      <title>Lossless Syntax Trees</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Sun, 27 Oct 2019 21:18:03 +0000</pubDate>
      <link>https://dev.to/cad97/lossless-syntax-trees-280c</link>
      <guid>https://dev.to/cad97/lossless-syntax-trees-280c</guid>
      <description>&lt;p&gt;So you want to parse a programming language. You want to turn some text into a semantic data structure representing the structure of the program as written by the user.&lt;/p&gt;

&lt;p&gt;But how exactly do you structure such a semantic model? A Parse Tree (sometimes called a Concrete Syntax Tree, or CST) is what a grammar-based parsing tool like &lt;a href="https://www.antlr.org/" rel="noopener noreferrer"&gt;ANTLR&lt;/a&gt; typically produces for this purpose. This faithfully represents the structure of the formal parse tree, including &lt;q&gt;meaningless&lt;/q&gt; syntax that’s there for disambiguation but often excluding &lt;q&gt;trivia&lt;/q&gt; that's allowed to be anywhere, such as whitespace and comments. The traditional improvement to this approach is something called an &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" rel="noopener noreferrer"&gt;Abstract Syntax Tree&lt;/a&gt;, or AST for short, which models only the meaningful parts of the grammar.&lt;/p&gt;

&lt;p&gt;However, for our IDE-ready compiler, there are two key properties that we have to fulfill: the parser needs to be error-tolerant, and it should be roundtripable. We need error-tolerance because even in the face of an incomplete or incorrect input, we need to produce a syntax tree so we can provide things like syntax highlighting and completion on in-progress code. Code in the IDE spends most of its time in an incomplete state as it is being written. As for roundtrippable, we want to be able to transform the syntax tree in the IDE and maintain things like formatting and comments. To get both of these properties, we use &lt;a href="https://crates.io/crates/rowan" rel="noopener noreferrer"&gt;rowan&lt;/a&gt;, a library implementing a more recent syntax tree design called a Lossless Syntax Tree&lt;sup&gt;†&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;The key trick of the rowan LST is structuring a &lt;q&gt;dynamically typed&lt;/q&gt; CST such that we can provide a &lt;q&gt;structurally typed&lt;/q&gt; AST &lt;em&gt;view&lt;/em&gt; into the CST. The untyped nature of the CST also provides for representation of our error tolerance: any node can have arbitrary children, so long as our parser is smart enough to figure out what node is where.&lt;/p&gt;

&lt;p&gt;This uses a kind of &lt;a href="https://blogs.msdn.microsoft.com/ericlippert/2012/06/08/persistence-facades-and-roslyns-red-green-trees/" rel="noopener noreferrer"&gt;red-green tree&lt;/a&gt; like is used &lt;a href="https://github.com/KirillOsenkov/Bliki/wiki/Roslyn-Immutable-Trees" rel="noopener noreferrer"&gt;in Roslyn&lt;/a&gt;. The &lt;q&gt;green tree&lt;/q&gt; is the CST, and is structured like a normal singly-linked tree: each node has a list of its children. The tree is dynamically typed, as it only stores a &lt;code&gt;#[repr(u16)] enum SyntaxKind&lt;/code&gt;&lt;sup&gt;‡&lt;/sup&gt; alongside the textual width of the node. The &lt;q&gt;red tree&lt;/q&gt; is a view into the green tree which is dynamically constructed on-demand, and contains parent pointers along with absolute offsets. The AST layer adds extra type information onto the red tree for what you can do with any given node, though all accessors necessarily return an &lt;code&gt;Option&lt;/code&gt; to represent the dynamicism of the concrete tree that allows for it to represent incorrect source code.&lt;/p&gt;




&lt;p&gt;To build our compiler to this point, we need to first do a bit of refactoring. The design so far is solid, but a few tweaks will prepare it for the parser. First, we should update any out-of-date dependencies. &lt;a href="https://crates.io/crates/cargo-edit#cargo-upgrade" rel="noopener noreferrer"&gt;&lt;code&gt;cargo upgrade&lt;/code&gt;&lt;/a&gt;&lt;code&gt;--all --allow-prerelease&lt;/code&gt; does the trick, giving at the time of writing, just an upgrade from &lt;code&gt;tera@1.0.0-beta.16&lt;/code&gt; to &lt;code&gt;tera@1.0.0-beta.18&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's remind ourselves of the grammar we're working with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Program = Statement*;
Statement =
  | If:{ "if" cond:(Expression::Parenthesized) then:Statement { "else" else:Statement }? }
  | While:{ "while" cond:(Expression::Parenthesized) then:Statement }
  | Block:{ "{" then:Statement* "}" }
  | Expression:{ then:Expression? ";" }
  ;
Expression =
  | Parenthesized:{ "(" Expression ")" }
  | Assignment:{ id:Identifier "=" val:Expression }
  | Comparison: #[associativity(left)] { lhs:Expression "&amp;lt;" rhs:Expression }
  | Addition: #[associativity(left)] { lhs:Expression "+" rhs:Expression }
  | Subtraction: #[associativity(left)] { lhs:Expression "-" rhs:Expression }
  | Term:Term
  ;
Term =
  | Identifier:Identifier // token
  | Integer:Integer // token
  | Expression:(Expression::Parenthesized)
  ;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(If you're following along as these are posted, you may note that this is different than the grammar I've used so far; this comes from starting implementing the parser and finding improvements.)&lt;/p&gt;

&lt;p&gt;Here we see that a &lt;code&gt;Program&lt;/code&gt; is made up of zero-or-more &lt;code&gt;Statement&lt;/code&gt;; a &lt;code&gt;Statement&lt;/code&gt; is either &lt;code&gt;Statement::If&lt;/code&gt;, &lt;code&gt;Statement::While&lt;/code&gt;, &lt;code&gt;Statement::Block&lt;/code&gt;, or &lt;code&gt;Statement::Expression&lt;/code&gt;; and &lt;code&gt;Statement::If&lt;/code&gt; is a literal &lt;code&gt;if&lt;/code&gt; followed by an &lt;code&gt;Expression::Parenthesized&lt;/code&gt; and a &lt;code&gt;Statement&lt;/code&gt;, optionally followed by a literal &lt;code&gt;else&lt;/code&gt; and another &lt;code&gt;Statement&lt;/code&gt;. This describes the structure of a correct tree. We add the nonterminal symbols to our &lt;code&gt;syntax.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;nonterminals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"statement if"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"statement while"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"statement block"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"statement expression"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"expression parenthesized"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"expression assignment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"expression comparison"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"expression addition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"expression subtraction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"expression term"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"term identifier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"term integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"term expression"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, I upgraded the &lt;code&gt;error&lt;/code&gt; kind from being listed in the metadata file to being explicitly listed last in the template file. While it is a node kind, it's different than the &lt;q&gt;real&lt;/q&gt; nodes of a proper tree, and should be treated specially. Now, we should rename our existing &lt;code&gt;SyntaxKind&lt;/code&gt; to &lt;code&gt;TokenKind&lt;/code&gt; to clarify that it's just for tokens, then create a new template for &lt;code&gt;SyntaxKind&lt;/code&gt;, which includes the nonterminals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Separate variables for terminals and nonterminals&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;terminals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;literals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;punctuation&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;all_kinds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;terminals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nonterminals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[repr(u16)]&lt;/span&gt;
&lt;span class="nd"&gt;#[allow(missing_docs)]&lt;/span&gt;
&lt;span class="c1"&gt;// Add serde to runtime dependencies.&lt;/span&gt;
&lt;span class="c1"&gt;// TokenKind should impl `Serialize` as well.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(serde::Serialize)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Copy,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Hash)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_kinds&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// The name of this syntax kind.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_kinds&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::{{&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"{{ kind | camel_case }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"ERROR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// We need to convert from TokenKind to SyntaxKind.&lt;/span&gt;
&lt;span class="c1"&gt;// This could be explicitly zero-cost by using a transmute,&lt;/span&gt;
&lt;span class="c1"&gt;// but we stick here to the safe version and let it optimize.&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;From&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TokenKind&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TokenKind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;terminals&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;TokenKind&lt;/span&gt;&lt;span class="p"&gt;::{{&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::{{&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;TokenKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// For rowan, we also want conversions to/from u16.&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;From&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This could be explicitly zero-cost by using a transmute,&lt;/span&gt;
&lt;span class="c1"&gt;// but we stick here to the safe version and let it optimize.&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;From&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_kinds&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;loop&lt;/span&gt;&lt;span class="py"&gt;.index&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::{{&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also want to pull the &lt;code&gt;Token&lt;/code&gt; struct from &lt;code&gt;tinyc_lexer&lt;/code&gt; into &lt;code&gt;tinyc_grammar&lt;/code&gt;, and re-export it from &lt;code&gt;tinyc_lexer&lt;/code&gt; instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;include!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;concat!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;env!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OUT_DIR"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"/token_kinds.rs"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nd"&gt;include!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;concat!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;env!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OUT_DIR"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"/syntax_kinds.rs"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Copy,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Hash)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TokenKind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Serialize&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;S&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;S&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;where&lt;/span&gt;
        &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="nf"&gt;.serialize_newtype_variant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nn"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt;&lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It fits better in &lt;code&gt;tinyc_grammar&lt;/code&gt;, which is our crate for raw data boxes than &lt;code&gt;tinyc_lexer&lt;/code&gt;, which is our crate implementing the lexer. Other crates could easily want to consume &lt;code&gt;Token&lt;/code&gt; without depending on the lexer.&lt;/p&gt;




&lt;p&gt;With these improvements, we're ready to start implementing the parser next time.&lt;/p&gt;

&lt;p&gt;Discuss this below! | &lt;a href="https://github.com/CAD97/tinyc/tree/blog-03" rel="noopener noreferrer"&gt;See the result on GitHub!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How did I do on code density this time? Last time felt a bit too much &lt;q&gt;here's the code&lt;/q&gt;, so this one tries to focus a bit more on concepts and less on concrete implementation.&lt;/p&gt;




&lt;p&gt;† You may also see a Lossless Syntax Tree referred to as a Concrete Syntax Tree. I prefer LST for this concept as a Parse Tree is somewhat commonly called a CST (as mentioned above) and is explicitly not what the LST is. Often times, an LST will simply be called Syntax Tree as well. whether &lt;q&gt;Syntax Tree&lt;/q&gt; means CST, AST, or LST is left up to context. There are, of course, also alternate approaches to syntax trees that fall somewhere in-between these three categories.&lt;/p&gt;

&lt;p&gt;‡ Actually, rowan uses a &lt;code&gt;struct SyntaxKind(u16)&lt;/code&gt; internally and translates between that and the user's syntax kind enum at a higher level. This reduces generics proliferation and allows the library user to use a more complicated sum type than just a C-style enum if desired.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Matklad's &lt;a href="https://matklad.github.io/2018/06/06/modern-parser-generator.html" rel="noopener noreferrer"&gt;Modern Parser Generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;rust-analyzer's &lt;a href="https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/architecture.md" rel="noopener noreferrer"&gt;architecture overview&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;[video] &lt;a href="https://youtu.be/DGAuLWdCCAI" rel="noopener noreferrer"&gt;rust analyzer syntax trees&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Rust &lt;a href="https://github.com/rust-lang/rfcs/pull/2256" rel="noopener noreferrer"&gt;"libsyntax 2.0" RFC&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;oilshell's &lt;a href="https://www.oilshell.org/blog/2017/02/11.html" rel="noopener noreferrer"&gt;From AST to Lossless Syntax Tree&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;Case Studies:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.jetbrains.org/intellij/sdk/docs/reference_guide/custom_language_support/implementing_parser_and_psi.html" rel="noopener noreferrer"&gt;JetBrains Program Structure Interface&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Kotlin &lt;a href="https://github.com/JetBrains/kotlin/blob/6a679d86ab375054ce29a98ac2f2cd8be4ccbcc1/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java" rel="noopener noreferrer"&gt;PSI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Swift &lt;a href="https://github.com/apple/swift/tree/master/lib/Syntax" rel="noopener noreferrer"&gt;libSyntax&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;rust-analyzer &lt;a href="https://github.com/rust-analyzer/rust-analyzer/tree/c48b467eff0e18f3b8fa1b65a21abb19f800f56a/crates/ra_parser" rel="noopener noreferrer"&gt;ra_parser&lt;/a&gt; and &lt;a href="https://github.com/rust-analyzer/rust-analyzer/tree/c48b467eff0e18f3b8fa1b65a21abb19f800f56a/crates/ra_syntax" rel="noopener noreferrer"&gt;ra_syntax&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;Roslyn &lt;a href="https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis" rel="noopener noreferrer"&gt;Syntax API&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>parsing</category>
      <category>languagedesign</category>
      <category>compilers</category>
    </item>
    <item>
      <title>What is a Lexer, Anyway?</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Fri, 11 Oct 2019 18:58:50 +0000</pubDate>
      <link>https://dev.to/cad97/what-is-a-lexer-anyway-4kdo</link>
      <guid>https://dev.to/cad97/what-is-a-lexer-anyway-4kdo</guid>
      <description>&lt;p&gt;The first task when implementing any language (that is already specified) is to turn the source code into some sort of Syntax Tree that's meaningful to the computer, rather than the human-optimized surface language.&lt;/p&gt;

&lt;p&gt;This is the task of Parsing. Parsing is a wide and well studied field in computer science, and formally, is the problem of just &lt;em&gt;recognizing&lt;/em&gt; if any given string is a member of some language.&lt;/p&gt;

&lt;p&gt;Slightly more concretely, parsing is the task of turning a list of &lt;em&gt;symbols&lt;/em&gt; into a data structure representing some higher level of structure. In the case of parsing, the set of input symbols are characters†.&lt;/p&gt;

&lt;p&gt;Traditionally, parsing of programming languages is split up into two phases: the lexing stage and the parsing stage. In truth, both of these stages are parsers: they both take an input list of symbols and produce a higher level of structure. It's just that the lexer's output is used as the parser's input.&lt;/p&gt;

&lt;p&gt;This separation is useful because the lexer's job is simpler than the parser's. The lexer just turns the meaningless string into a flat list of things like "number literal", "string literal", "identifier", or "operator", and can do things like recognizing reserved identifiers ("keywords") and discarding whitespace. Formally, a lexer recognizes some set of &lt;a href="https://en.wikipedia.org/wiki/Regular_language" rel="noopener noreferrer"&gt;Regular languages&lt;/a&gt;. A "regular" language is one that can be parsed without any extra state in a single non-backtracking pass. This makes it very efficient: you only have to look at one byte at a time to make decisions, and all of the decisions can even be packed into a decision matrix called a &lt;a href="https://en.wikipedia.org/wiki/Deterministic_finite_automaton" rel="noopener noreferrer"&gt;Finite Automaton&lt;/a&gt;. If you've ever used a regular expression, you've written a recognizer for a regular language‡.&lt;/p&gt;

&lt;p&gt;The parser has the much harder job of turning the stream of "tokens" produced by the lexer into a parse tree representing the structure of the parsed language. The separation of the lexer and the parser allows the lexer to do its job well and for the parser to work on a simpler, more meaningful input than the raw text.&lt;/p&gt;




&lt;p&gt;While there are many ways to generate lexers, we'll be implementing our lexer by hand so that the structure of it can be seen. The simplest form of the lexer is &lt;code&gt;fn(&amp;amp;str) -&amp;gt; Token&lt;/code&gt;, where &lt;code&gt;Token&lt;/code&gt; is a &lt;code&gt;(Kind, Length)&lt;/code&gt; pair. That's the API we'll implement, though for convenience we also provide a &lt;code&gt;fn(&amp;amp;str) -&amp;gt; impl Iterator&amp;lt;Item=Token&amp;gt;&lt;/code&gt; access point. Note that this is an infallible transform: on unexpected characters we just return an error token.&lt;/p&gt;

&lt;p&gt;Let's look at our Tiny-C grammar again to determine what our lexer has to recognize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Program = Statement;
Statement =
  | If:{ "if" cond:ParenExpr then:Statement else:{ "else" then:Statement } }
  | While:{ "while" cond:ParenExpr then:Statement }
  | Block:{ "{" then:Statement* "}" }
  | Expr:{ then:Statement? ";" }
  ;
ParenExpr = "(" Expr ")";
Expr =
  | Assign:{ id:Id "=" val:Expr }
  | Test:{ lhs:Expr "&amp;lt;" rhs:Expr }
  | Sum:{ lhs:Expr "+" rhs:Term }
  | Diff:{ lhs:Expr "-" rhs:Term }
  ;
Term =
  | Id:{ 'a'..='z'+ }
  | Int:{ '0'..='9'+ }
  | Expr:ParenExpr
  ;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The terminal productions in the grammar are those without any inner structure, and those are what the lexer produces. We have the literal strings/keywords of &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;else&lt;/code&gt;, and &lt;code&gt;while&lt;/code&gt;; punctuation of &lt;code&gt;{&lt;/code&gt;/&lt;code&gt;}&lt;/code&gt;, &lt;code&gt;;&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt;/&lt;code&gt;)&lt;/code&gt;, &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, and &lt;code&gt;-&lt;/code&gt;; and the terminal productions of &lt;code&gt;Id&lt;/code&gt; (one or more lowercase ascii characters) and &lt;code&gt;Int&lt;/code&gt; (one or more ascii digits).&lt;/p&gt;

&lt;p&gt;Now that we know what we're implementing, we have to decide how we want to structure our workspace. For typical development, I use &lt;a href="https://www.jetbrains.com/idea/" rel="noopener noreferrer"&gt;IntelliJ IDEA&lt;/a&gt; with &lt;a href="https://intellij-rust.github.io/" rel="noopener noreferrer"&gt;IntelliJ Rust&lt;/a&gt;. For this series, though, I will be assuming an environment of &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt; with &lt;a href="https://github.com/rust-analyzer/rust-analyzer" rel="noopener noreferrer"&gt;rust-analyzer&lt;/a&gt;, due to VSCode's utility for developing language servers. The canonical repo is located at &lt;a href="https://github.com/cad97/tinyc" rel="noopener noreferrer"&gt;https://github.com/cad97/tinyc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since we want to build a modular compiler, we're going to want to split things up into separate crates. So set up a &lt;a href="https://doc.rust-lang.org/cargo/reference/manifest.html#the-workspace-section" rel="noopener noreferrer"&gt;virtual manifest&lt;/a&gt; in a new directory and create our first crate, &lt;code&gt;tinyc_grammar&lt;/code&gt;. The grammar crate will hold the definition of our grammar types and be almost exclusively generated from metadata. We're only going to set up the terminal token types right now, but this sets up the framework for continuing onward. The build-dependencies we'll need (managed with &lt;a href="https://lib.rs/crates/cargo-edit" rel="noopener noreferrer"&gt;&lt;code&gt;cargo-edit&lt;/code&gt;&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo add -sB glob heck serde tera toml --allow-prerelease
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of writing, that gives &lt;code&gt;glob@0.3&lt;/code&gt;, &lt;code&gt;heck@0.3&lt;/code&gt;, &lt;code&gt;serde@1.0&lt;/code&gt;, &lt;code&gt;tera@1.0.0-beta.16&lt;/code&gt;, and &lt;code&gt;toml@0.5&lt;/code&gt;. We also need to enable &lt;code&gt;serde&lt;/code&gt;'s &lt;code&gt;"derive"&lt;/code&gt; feature.&lt;/p&gt;

&lt;p&gt;We now need a folder to hold our metadata about the language. In it, we create &lt;code&gt;syntax.toml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# The keywords of our language.&lt;/span&gt;
&lt;span class="py"&gt;keywords&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"else"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"if"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"while"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;# Literal data embedded in the source.&lt;/span&gt;
&lt;span class="py"&gt;literals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;# Symbols alongside names for them.&lt;/span&gt;
&lt;span class="py"&gt;punctuation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'{'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"left curly bracket"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"right curly bracket"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'('&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"left parenthesis"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;')'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"right parenthesis"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"plus sign"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hyphen minus"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'&amp;lt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"less than sign"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"semicolon"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="py"&gt;['&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;', "equals sign"],&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;# Tokens that don't fall into one of the above categories.&lt;/span&gt;
&lt;span class="c"&gt;# "error" is for errors: when we encounter something unexpected.&lt;/span&gt;
&lt;span class="c"&gt;# "whitespace" is the white space between tokens, and is explicit in our lexer.&lt;/span&gt;
&lt;span class="py"&gt;tokens&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"whitespace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to create the &lt;a href="https://tera.netlify.com/" rel="noopener noreferrer"&gt;Tera&lt;/a&gt; template for our syntax kind enum, &lt;code&gt;syntax_kinds.rs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This is just a workaround: for some reason&lt;/span&gt;
&lt;span class="c1"&gt;// a tera filter expression cannot start with a literal empty array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Create a variable for accessing every kind&lt;/span&gt;
&lt;span class="c1"&gt;// by concatenating each individual kind&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;all_kinds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;literals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;punctuation&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Rowan internally stores kind as a u16&lt;/span&gt;
&lt;span class="nd"&gt;#[repr(u16)]&lt;/span&gt;
&lt;span class="c1"&gt;// We won't be generating docs&lt;/span&gt;
&lt;span class="nd"&gt;#[allow(missing_docs)]&lt;/span&gt;
&lt;span class="c1"&gt;// Derive all of the standard traits we can&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Copy,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Hash)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_kinds&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// list each kind in camel_case&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%-&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Tera syntax, &lt;code&gt;{% %}&lt;/code&gt; is a control statement. At the top, we &lt;code&gt;set all_kinds&lt;/code&gt; to define an array of every kind to allow us to use the list multiple times without constructing it every time. In the enum definition, we iterate over every &lt;code&gt;kind in all_kinds&lt;/code&gt; and use &lt;code&gt;{{ }}&lt;/code&gt; to paste in each kind transformed into &lt;code&gt;camel_case&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that we've set up our metadata, we can actually generate our &lt;code&gt;grammar&lt;/code&gt; crate! Create a &lt;code&gt;build.rs&lt;/code&gt; and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;heck&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
        &lt;span class="nn"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;path&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PathBuf&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nn"&gt;tera&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Tera&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;toml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cd"&gt;/// The manifest directory.&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MANIFEST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;env!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CARGO_MANIFEST_DIR"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cd"&gt;/// Project-relative path to the syntax metadata.&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SYNTAX_CONFIG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"meta/syntax.toml"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cd"&gt;/// Directory containing the Tera templates.&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TEMPLATE_DIR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// The sytnax kinds enum template.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SYNTAX_KINDS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"syntax_kinds.rs"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// Easy access to the project root path.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;project_root&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// We take the 2nd ancestor as our crate's manifest is two folders deep.&lt;/span&gt;
    &lt;span class="nn"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MANIFEST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.ancestors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// The structured syntax metadata.&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// We derive Serialize to serialize to a Tera config object&lt;/span&gt;
&lt;span class="cd"&gt;/// and Deserialize to deserialize from the metadata file.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;SyntaxConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;literals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;punctuation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PunctuationConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// A punctuation config item, represented in toml as `["character", "name"]`.&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// We derive Serialize so the Tera config object has named members,&lt;/span&gt;
&lt;span class="cd"&gt;/// but implement Deserialize manually to deserialize from an unnamed sequence.&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// Note that this means `de::from_str(ser::to_string(punctuation_config))`&lt;/span&gt;
&lt;span class="cd"&gt;/// does not work, as the two formats do not line up. This is only ok to do&lt;/span&gt;
&lt;span class="cd"&gt;/// here because these are the _only_ de/serialization tasks we care about.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Serialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PunctuationConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;character&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;PunctuationConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;D&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;where&lt;/span&gt;
        &lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;de&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Deserializer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;#[derive(Deserialize)]&lt;/span&gt;
        &lt;span class="nd"&gt;#[serde(rename&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"PunctuationConfig"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;Helper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// We implement deserialize by just delegating to a helper tuple struct type.&lt;/span&gt;
        &lt;span class="nn"&gt;Helper&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PunctuationConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;character&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="na"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// A helper function to make Tera filter functions `(value, keys) -&amp;gt; Value`&lt;/span&gt;
&lt;span class="cd"&gt;/// out of a simpler `(T) -&amp;gt; T` transformation.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;make_filter_fn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Into&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;de&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;DeserializeOwned&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nf"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Sync&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nn"&gt;tera&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Filter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;tera&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;tera&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;try_get_value!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;project_root&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;templates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEMPLATE_DIR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"**/*.rs"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;syntax_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SYNTAX_CONFIG&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// All generated files go into `$OUT_DIR` and are `include!`d from there.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;PathBuf&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OUT_DIR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// We have to tell cargo we depend on these files&lt;/span&gt;
    &lt;span class="c1"&gt;// so that cargo will rerun the build script when the files change.&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cargo:rerun-if-changed={}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syntax_config&lt;/span&gt;&lt;span class="nf"&gt;.to_string_lossy&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="nf"&gt;.to_string_lossy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cargo:rerun-if-changed={}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.to_string_lossy&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Initialize Tera.&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;tera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Tera&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.to_string_lossy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Add the `camel_case` filter using `heck`.&lt;/span&gt;
        &lt;span class="n"&gt;tera&lt;/span&gt;&lt;span class="nf"&gt;.register_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"camel_case"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;make_filter_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"camel_case"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.to_camel_case&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;tera&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Read in the context file.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SyntaxConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;toml&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;syntax_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// And convert it into the Tera-compatible form.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Write out the generated file.&lt;/span&gt;
    &lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SYNTAX_KINDS&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;tera&lt;/span&gt;&lt;span class="nf"&gt;.render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SYNTAX_KINDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we just have to &lt;code&gt;include!&lt;/code&gt; the generated file from our &lt;code&gt;lib.rs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;include!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;concat!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;env!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OUT_DIR"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"/syntax_kinds.rs"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we have our &lt;code&gt;grammar&lt;/code&gt; crate up and running! At this point you can do &lt;code&gt;cargo doc&lt;/code&gt; to see our progress so far.&lt;/p&gt;




&lt;p&gt;The next step is actually writing the lexer, so we can actually &lt;em&gt;run&lt;/em&gt; something. So let's create our lexer!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo new --lib crates/lexer --name tinyc_lexer
cd crates/lexer
cargo add ../grammar
code src/lib.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Re-export for ease of use.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;grammar&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// A single token in the document stream.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Copy,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Hash)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// The kind of token.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cd"&gt;/// How many bytes this token is.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Convenience function for repeatedly applying `lex`.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Iterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;'_&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Our compiler tooling assumes source files &amp;lt; 4 GiB in size.&lt;/span&gt;
    &lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nn"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.is_empty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="py"&gt;.len&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Lex the first token off of the source string.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;debug_assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.is_empty&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nd"&gt;debug_assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nn"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Classify the token.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.starts_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_whitespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Whitespace token.&lt;/span&gt;
        &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Whitespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_not_whitespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.starts_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_digit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Integer token.&lt;/span&gt;
        &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_not_digit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.starts_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Identifier token.&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_not_ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// This is a new function on `SyntaxKind` we'll add next.&lt;/span&gt;
            &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_identifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Punctuation token.&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sc"&gt;'{'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LeftCurlyBracket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;'}'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RightCurlyBracket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;'('&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LeftParenthesis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;')'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RightParenthesis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;'+'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PlusSign&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;'-'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HyphenMinus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;'&amp;lt;'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LessThanSign&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;';'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Semicolon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sc"&gt;'='&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;EqualsSign&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="c1"&gt;// Unknown tokens are an error.&lt;/span&gt;
                &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="nf"&gt;.len_utf8&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Helper functions for classifying characters.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_whitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="nf"&gt;.is_whitespace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_not_whitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;is_whitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_digit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="nf"&gt;.is_ascii_digit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_not_digit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;is_digit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_ident&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="sc"&gt;'z'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_not_ident&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;is_ident&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to add a couple new functions to our &lt;code&gt;syntax_kinds.rs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// The syntax kind for a keyword.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="s"&gt;"{{ keyword }}"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::{{&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}}),&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/// The syntax kind for an identifer.&lt;/span&gt;
    &lt;span class="cd"&gt;///&lt;/span&gt;
    &lt;span class="cd"&gt;/// Note that this doesn't do any validation of the identifier,&lt;/span&gt;
    &lt;span class="cd"&gt;/// it just uses whatever you give it.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from_identifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, we have our lexer written! Again, use &lt;code&gt;cargo doc&lt;/code&gt; to see the API of the lexer.&lt;/p&gt;




&lt;p&gt;But to truly show that the lexer works, we need to write some tests. To do so easily, we'll be using the &lt;a href="https://lib.rs/crates/conformance" rel="noopener noreferrer"&gt;conformance::tests&lt;/a&gt; testing library (disclaimer: I am the author). So add &lt;code&gt;conformance&lt;/code&gt; and &lt;code&gt;serde_yaml&lt;/code&gt; as dev-dependencies to our lexer crate and create a new test file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo add -sD conformance serde_yaml
code ./tests/conformance.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;conformance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serde_yaml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;tinyc_lexer&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;#[conformance::tests(exact,&lt;/span&gt; &lt;span class="nd"&gt;serde=serde_yaml,&lt;/span&gt; &lt;span class="nd"&gt;file=&lt;/span&gt;&lt;span class="s"&gt;"tests/main.yaml.test"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lex_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll use the examples from the &lt;a href="https://gist.github.com/KartikTalwar/3095780" rel="noopener noreferrer"&gt;canonical implementation&lt;/a&gt; as our tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code ./tests/main.yaml.test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="s"&gt;===&lt;/span&gt;
&lt;span class="s"&gt;a=b=c=2&amp;lt;3;&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;# empty tests for now&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="s"&gt;===&lt;/span&gt;
&lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;i=1; while (i&amp;lt;100) i=i+i;&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="s"&gt;===&lt;/span&gt;
&lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;i=125; j=100; while (i-j) if (i&amp;lt;j) j=j-i; else i=i-j;&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="s"&gt;===&lt;/span&gt;
&lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;i=1; do i=i+10; while (i&amp;lt;50);&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="m"&gt;5&lt;/span&gt;
&lt;span class="s"&gt;===&lt;/span&gt;
&lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;i=1; while ((i=i+10)&amp;lt;50) ;&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="m"&gt;6&lt;/span&gt;
&lt;span class="s"&gt;===&lt;/span&gt;
&lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;i=7; if (i&amp;lt;5) x=1; if (i&amp;lt;10) y=2;&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the test now, you'll get an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error[E0277]: the trait bound `tinyc_lexer::Token: serde::ser::Serialize` is not satisfied
   --&amp;gt; crates\lexer\tests\conformance.rs:6:1
    |
6   | #[conformance::tests(exact, serde=serde_yaml, file="tests/main.yaml.test")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `serde::ser::Serialize` is not implemented for `tinyc_lexer::Token`
    | 
   ::: D:\usr\.cargo\registry\src\github.com-1ecc6299db9ec823\serde_yaml-0.8.11\src\ser.rs:421:8
    |
421 |     T: ser::Serialize,
    |        -------------- required by this bound in `serde_yaml::ser::to_string`
    |
    = note: required because of the requirements on the impl of `serde::ser::Serialize` for `std::vec::Vec&amp;lt;tinyc_lexer::Token&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Serialize&lt;/code&gt; implementation is what we use to compare the expected output with what we actually produce. So we add a new helper in the &lt;code&gt;syntax_kinds.rs&lt;/code&gt; template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SyntaxKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// The name of this syntax kind.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_kinds&lt;/span&gt; &lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;::{{&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;camel_case&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"{{ kind | camel_case }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nd"&gt;#[allow(unreachable_patterns)]&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// For the future&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and for &lt;code&gt;tinyc_lexer::Token&lt;/code&gt;, we implement &lt;code&gt;Serialize&lt;/code&gt; manually. Why? Because we can get a much nicer serialization (&lt;code&gt;Token: length&lt;/code&gt;) than the default one if we didn't change it (&lt;code&gt;{ kind: "Token", len: length }&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo add -s serde
code src/serde.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Serialize&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;S&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;S&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;where&lt;/span&gt;
        &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="nf"&gt;.serialize_newtype_variant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="c1"&gt;// The name of the type&lt;/span&gt;
            &lt;span class="s"&gt;"Token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// TokenKind is `#[repr(u16)]`, so this cast is legal&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// Using our added helper to get the name of the kind&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt;&lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="c1"&gt;// The data payload of the serialized newtype variant&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This serializes &lt;code&gt;Token&lt;/code&gt; as if it were &lt;code&gt;enum Token { Kind(u32) }&lt;/code&gt;, which is really what it acts like; we just separate it to a &lt;code&gt;(kind, length)&lt;/code&gt; tuple because generating and manipulating the kind without the length is useful for the compiler. (Don't forget to include the file with &lt;code&gt;mod serde&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;If you run the test now, the tests will compile but fail, as we're asserting that the examples lex into an empty sequence of tokens. Unfortunately, the diff provided by the default &lt;code&gt;assert_eq!&lt;/code&gt; is really hard to read for large data like this without IDE integration like IntelliJ-Rust has.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---- main_yaml_1 stdout ----
thread 'main_yaml_1' panicked at 'assertion failed: `(left == right)`
  left: `"---\n- Identifier: 1\n- EqualsSign: 1\n- Identifier: 1\n- EqualsSign: 1\n- Identifier: 1\n- EqualsSign: 1\n- Integer: 1\n- LessThanSign: 1\n- Integer: 1\n- Semicolon: 1"`,
 right: `"---\n[]"`', crates\lexer\tests\conformance.rs:6:1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8e7sdheqy2xqcf47lim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8e7sdheqy2xqcf47lim.png" alt="Example conformance failure (visual)" width="575" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, an &lt;a href="https://www.freeformatter.com/javascript-escape.html" rel="noopener noreferrer"&gt;unescape tool&lt;/a&gt; along with a &lt;a href="https://www.diffchecker.com/" rel="noopener noreferrer"&gt;diff tool&lt;/a&gt; makes sense of the output. Check that the produced output is what it's supposed to be, then copy it into the test file to insure you know if it changes in the future.&lt;/p&gt;

&lt;p&gt;And with that, we have a working lexer! Next time, we'll take the first steps towards parsing the tokens into a syntax tree.&lt;/p&gt;

&lt;p&gt;Discuss this below! | &lt;a href="https://github.com/CAD97/tinyc/tree/blog-02" rel="noopener noreferrer"&gt;See the result on GitHub!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;†  Characters are a lie. Rather, we work on Unicode &lt;a href="https://unicode.org/glossary/#abstract_character" rel="noopener noreferrer"&gt;Abstract Character&lt;/a&gt;s, or codepoints. That's the 32 bit value that Rust's &lt;code&gt;char&lt;/code&gt; datatype represents. Unfortunately, a human-perceived character is a nebulous concept and not even consistent between human languages. Unicode has the concept of an &lt;a href="https://unicode.org/glossary/#extended_grapheme_cluster" rel="noopener noreferrer"&gt;(Extended) Grapheme Cluster&lt;/a&gt; which attempts to roughly approximate this, but that requires a parser of its own and is beyond what we need; working on codepoints is enough. Anyway, outside of literal strings, most programming languages don't allow anything other than ASCII.&lt;/p&gt;

&lt;p&gt;‡  Some regular expression engines allow non-regular extensions to the regular expression language. Regular expressions are convenient, and having to stick to regular parsing techniques is restrictive, so features like backreferences were introduced for a limited form of context-sensitive parsing. Some engines like Rust's &lt;a href="https://lib.rs/crates/regex" rel="noopener noreferrer"&gt;regex crate&lt;/a&gt; don't implement these nonregular features, and that allows them to completely eliminate "regex performance pitfalls".&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Matklad's &lt;a href="https://github.com/rust-lang/rust/pull/59706" rel="noopener noreferrer"&gt;The Essence of Lexer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;oilshell's &lt;a href="https://www.oilshell.org/blog/2019/02/07.html" rel="noopener noreferrer"&gt;How to Parse Shell Like a Programming Language&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/q/2842809/3019990" rel="noopener noreferrer"&gt;lexers vs parsers&lt;/a&gt; on StackOverflow&lt;/li&gt;
&lt;li&gt;Wikipedia on &lt;a href="https://en.wikipedia.org/wiki/Lexical_analysis" rel="noopener noreferrer"&gt;Lexical Analysis&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;KartikTalwar's &lt;a href="https://gist.github.com/KartikTalwar/3095780" rel="noopener noreferrer"&gt;Tiny-C Compiler&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>languagedesign</category>
      <category>parsing</category>
      <category>compilers</category>
    </item>
    <item>
      <title>Conformance Testing in Rust</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Fri, 04 Oct 2019 21:20:28 +0000</pubDate>
      <link>https://dev.to/cad97/conformance-testing-in-rust-3h5m</link>
      <guid>https://dev.to/cad97/conformance-testing-in-rust-3h5m</guid>
      <description>&lt;p&gt;I'm excited to announce &lt;a href="https://crates.io/crates/conformance" rel="noopener noreferrer"&gt;&lt;code&gt;conformance::tests&lt;/code&gt;&lt;/a&gt;, a new crate I've published as part of building the Tiny-C compiler for the &lt;a href="https://dev.to/cad97/crafting-ide-ready-compilers-500o"&gt;Crafting IDE-Ready-Compilers&lt;/a&gt; series.&lt;/p&gt;

&lt;p&gt;The idea of this crate is to make it simpler to test any API which takes the shape of a &lt;code&gt;&amp;amp;str -&amp;gt; impl serde::Serialize + serde::Deserialize&lt;/code&gt; function. It works with any serde compatible data format, though I find that &lt;a href="https://lib.rs/crates/serde_yaml" rel="noopener noreferrer"&gt;&lt;code&gt;serde_yaml&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://lib.rs/crates/ron" rel="noopener noreferrer"&gt;&lt;code&gt;ron&lt;/code&gt;&lt;/a&gt; give the most readable diffs for a failed test.&lt;/p&gt;

&lt;p&gt;Using the Tiny-C lexer and YAML for serialization, here's what a test looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;simple_test&lt;/span&gt;
&lt;span class="s"&gt;===&lt;/span&gt;
&lt;span class="s"&gt;a=b=c=2&amp;lt;3;&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;EqualsSign&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;EqualsSign&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;EqualsSign&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Integer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;LessThanSign&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Integer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Semicolon&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and to hook it up to the standard Rust test runner, all that has to be written is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[conformance::tests(exact,&lt;/span&gt;
    &lt;span class="nd"&gt;ser&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;serde_yaml::to_string,&lt;/span&gt;
    &lt;span class="nd"&gt;de&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;serde_yaml::from_str,&lt;/span&gt;
    &lt;span class="nd"&gt;file&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"tests/yaml.test"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lex_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A test in the test file is represented by a test name (which needs to be a valid rust identifier continuation), terminated by a &lt;code&gt;===&lt;/code&gt; on its own line, the test input string, terminated by a &lt;code&gt;---&lt;/code&gt; on its own line, and the serialized expected output, terminated by a &lt;code&gt;...&lt;/code&gt; on its own line. A test file contains any number of these tests. (The extension of the file does not matter, but idiomatically should be &lt;code&gt;format.test&lt;/code&gt;.) The file name (excluding the extension) is also required to be a valid Rust identifier (or a &lt;code&gt;.&lt;/code&gt; is also allowed).&lt;/p&gt;

&lt;p&gt;The procedural macro is applied to the function that you want to test. The function must have the shape of taking a single parameter of type &lt;code&gt;&amp;amp;str&lt;/code&gt; and returning a type that can be de/serialized by &lt;code&gt;serde&lt;/code&gt;. The arguments to the macro itself are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;exact&lt;/code&gt;: the produced value must exactly match the expected value. In the future, a separate mode where the produced value is just required to be a superset of the expected value is planned.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ser&lt;/code&gt;: a path to a function of shape &lt;code&gt;fn&amp;lt;T: serde::Serialize&amp;gt;(&amp;amp;T) -&amp;gt; String&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;de&lt;/code&gt;: a path to a function of shape &lt;code&gt;fn&amp;lt;T: serde::Deserialize&amp;gt;(&amp;amp;str) -&amp;gt; Result&amp;lt;T, impl std::error::Error&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file&lt;/code&gt;: a file path string relative to the cargo manifest directory to the intended test file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, multiple &lt;code&gt;conformance::tests&lt;/code&gt; attributes can be applied to the same function to run the tests in multiple files.&lt;/p&gt;

&lt;p&gt;If all you want to do is use the library, you now know everything you need to know to use it. But I find the details of how it works interesting to discuss, so read on to see.&lt;/p&gt;




&lt;p&gt;The Rust &lt;a href="https://github.com/rust-lang/rust/issues/50297" rel="noopener noreferrer"&gt;Custom Test Frameworks feature&lt;/a&gt; is still experimental and unstable. But, while &lt;code&gt;#[test_case]&lt;/code&gt; might simplify the implementation of &lt;code&gt;conformance&lt;/code&gt;, it's not needed and by using just &lt;code&gt;#[test]&lt;/code&gt; we work on stable.&lt;/p&gt;

&lt;p&gt;In order to integrate natively into the standard &lt;code&gt;#[test]&lt;/code&gt; test runner, a unique &lt;code&gt;#[test]&lt;/code&gt; function is emitted for each test in the test file.&lt;/p&gt;

&lt;p&gt;To do the actual testing work, we emit a single function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nf"&gt;testing_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;include_str!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;#&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nf"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nf"&gt;fn_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nf"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;de&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;tested_type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// normalize&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We call the function by the file name, such that multiple files can be tested in the same Rust namespace. The file path is &lt;code&gt;include_str!&lt;/code&gt;'d to add a data dependency onto the test file so changing it will recompile the crate. (Hopefully Rust doesn't get smart enough to just recompile the &lt;code&gt;const&lt;/code&gt; until a real API for reading files in a procedural macro in a principled way is stabilized.)&lt;/p&gt;

&lt;p&gt;For each function in the test file, we emit a function that delegates to &lt;code&gt;#testing_fn&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nf"&gt;test_name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nf"&gt;testing_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function name is assembled as &lt;code&gt;{filename}_{testname}&lt;/code&gt;, thus the requirements on naming for the filename and test name. The output and input to the test are sliced out of the test file and included as string literals in the generated token stream.&lt;/p&gt;

&lt;p&gt;Because the comparison is just done by &lt;code&gt;assert_eq&lt;/code&gt;, that's the whole macro. Complete with all the formalities, it's just under 200 lines (plus &lt;code&gt;syn{features=[full]}&lt;/code&gt;)! The test failure is best viewed with &lt;a href="https://intellij-rust.github.io/" rel="noopener noreferrer"&gt;IntelliJ Rust&lt;/a&gt; since they provide a diff view of &lt;code&gt;assert_eq!&lt;/code&gt; failures, or with some other &lt;code&gt;assert_eq&lt;/code&gt; patch like &lt;a href="https://lib.rs/crates/pretty_assertions" rel="noopener noreferrer"&gt;pretty-assertions&lt;/a&gt; to provide an in-terminal diff.&lt;/p&gt;

&lt;p&gt;There's a few features I'd like to add to &lt;code&gt;conformance::tests&lt;/code&gt; that I'd love to have community assistance in designing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Includes"/"superset" mode, as opposed to the current "strict" mode. The produced value includes at least the specified data, but is allowed to include more data. This is mostly useful for testing part of a structure, omitting data not relevant to the test.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serde =&lt;/code&gt; shortcut: give a path to a &lt;code&gt;serde_json&lt;/code&gt;/&lt;code&gt;serde_yaml&lt;/code&gt;-like module/crate, that exposes a &lt;code&gt;to_string&lt;/code&gt; and &lt;code&gt;from_str&lt;/code&gt; appropriate for &lt;code&gt;ser&lt;/code&gt; and &lt;code&gt;de&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A smarter diff algorithm. While comparing the string serialized version of data structures is nicely minimal and utilitarian, I can't help but think we can do better and use some sort of "minimizing diff" algorithm (like Longest Common Sub-sequence is for sequences) that can generally apply to the &lt;a href="https://serde.rs/data-model.html" rel="noopener noreferrer"&gt;serde data model&lt;/a&gt;. This might even be required for the "superset" mode.&lt;/li&gt;
&lt;li&gt;Remove the &lt;code&gt;Deserialize&lt;/code&gt; requirement. It's currently just used to normalize the serialized format; removing it means many more things can be tested through &lt;code&gt;conformance::tests&lt;/code&gt;, even if they can't deserialize well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're interested, check out &lt;a href="https://github.com/CAD97/tinyc/tree/master/crates/conformance" rel="noopener noreferrer"&gt;the repository&lt;/a&gt;, and get a bonus sneak peek at the content of next week's post for the Tiny-C lexer.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>testing</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Crafting IDE-Ready Compilers</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Fri, 27 Sep 2019 18:27:47 +0000</pubDate>
      <link>https://dev.to/cad97/crafting-ide-ready-compilers-500o</link>
      <guid>https://dev.to/cad97/crafting-ide-ready-compilers-500o</guid>
      <description>&lt;p&gt;This is the introductory post of a series, so normally you would find a motivational section here. Why should you learn how to build a compiler? I'm not going to bother with that; Crafting Interpreters &lt;a href="http://craftinginterpreters.com/introduction.html#why-learn-this-stuff" rel="noopener noreferrer"&gt;did it better than I could, anyway&lt;/a&gt;. The short of it is, well, writing compilers is fun, and covers a lot of techniques for solving problems.&lt;/p&gt;

&lt;p&gt;We're going to start by implementing an interpreter for the &lt;a href="https://gist.github.com/KartikTalwar/3095780" rel="noopener noreferrer"&gt;Tiny-C&lt;/a&gt; language. Tiny-C is a significantly stripped down C-style language where there is only one data type, no variable declarations, no functions, the only control flow options are &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;while&lt;/code&gt;, and the only expressions are &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, and &lt;code&gt;&amp;lt;&lt;/code&gt;. Because of this, the grammar is simple enough I can include it here inline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Program = Statement;
Statement =
  | If:{ "if" cond:ParenExpr then:Statement else:{ "else" then:Statement } }
  | While:{ "while" cond:ParenExpr then:Statement }
  | Block:{ "{" then:Statement* "}" }
  | Expr:{ then:Statement? ";" }
  ;
ParenExpr = "(" Expr ")";
Expr =
  | Assign:{ id:Id "=" val:Expr }
  | Test:{ lhs:Expr "&amp;lt;" rhs:Expr }
  | Sum:{ lhs:Expr "+" rhs:Term }
  | Diff:{ lhs:Expr "-" rhs:Term }
  ;
Term =
  | Id:{ 'a'..='z'+ }
  | Int:{ '0'..='9'+ }
  | Expr:ParenExpr
  ;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Note that this is slightly modified from the original Tiny-C to better fit how we are going to build the compiler.) The simplicity of the language allows us to focus on the structure of the compiler rather than the intricacies of the language. If you don't fully understand the above grammar, don't worry: we'll be covering it in more detail in the future.&lt;/p&gt;

&lt;p&gt;Additionally, we'll be writing the compiler in a fully IDE-ready style. This means our compiler will also serve as the intelligence engine powering a &lt;a href="https://microsoft.github.io/language-server-protocol/" rel="noopener noreferrer"&gt;language server protocol&lt;/a&gt; server. Though our language is simple, we want to write the compiler as if it were a full-fat compiler for a full-fat language. By doing so, we can transfer what we learn here to real languages' intelligence engines.&lt;/p&gt;

&lt;p&gt;Because we're trying to build a real compiler, we'll be taking full advantage of the available tooling for building compilers in Rust. Rust's ownership semantics make the compartmentalization and complex data flows through a compiler easier to see. For libraries, we'll be using at least &lt;a href="https://lib.rs/crates/rowan" rel="noopener noreferrer"&gt;rowan&lt;/a&gt;, &lt;a href="https://lib.rs/crates/salsa" rel="noopener noreferrer"&gt;salsa&lt;/a&gt;, and &lt;a href="https://lib.rs/crates/lsp-server" rel="noopener noreferrer"&gt;lsp-server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With any luck, once we've implemented the interpreter for Tiny-C, we'll continue on to write a backend with &lt;a href="https://cranelift.readthedocs.io" rel="noopener noreferrer"&gt;Cranelift&lt;/a&gt;, and maybe even continue on to designing and writing a full language 👀&lt;/p&gt;

&lt;p&gt;I plan to have a post in the series out at least every other Friday. Next time: we set up the repository structure and lex the language into its component tokens. We'll also be getting our first venture into code generation along the way.&lt;/p&gt;

&lt;p&gt;Discuss this below! | &lt;a href="https://www.reddit.com/r/rust/comments/da4gn6/im_writing_a_series_on_writing_compilers_in_rust/" rel="noopener noreferrer"&gt;on Reddit!&lt;/a&gt; | &lt;a href="https://twitter.com/CAD97_/status/1176696422965698561" rel="noopener noreferrer"&gt;on Twitter!&lt;/a&gt; | &lt;a href="https://discord.gg/FuPE9JE" rel="noopener noreferrer"&gt;on Discord!&lt;/a&gt; | &lt;a href="https://dev.to/live/cad97"&gt;Watch me live!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://craftinginterpreters.com/" rel="noopener noreferrer"&gt;Crafting Interpreters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Matklad's &lt;a href="https://matklad.github.io/2018/06/06/modern-parser-generator.html" rel="noopener noreferrer"&gt;Modern Parser Generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Matklad's &lt;a href="https://github.com/rust-lang/rust/pull/59706" rel="noopener noreferrer"&gt;The Essence of Lexer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;KartikTalwar's &lt;a href="https://gist.github.com/KartikTalwar/3095780" rel="noopener noreferrer"&gt;Tiny-C Compiler&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/architecture.md" rel="noopener noreferrer"&gt;rust-analyzer's architecture overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the &lt;a href="https://salsa-rs.github.io/salsa/html/" rel="noopener noreferrer"&gt;Salsa book&lt;/a&gt; (WIP) and &lt;a href="https://github.com/salsa-rs/salsa/blob/master/examples/hello_world" rel="noopener noreferrer"&gt;hello world&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>compilers</category>
      <category>series</category>
      <category>languagedesign</category>
    </item>
    <item>
      <title>Rust Must-Know Crates</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Tue, 07 May 2019 21:24:53 +0000</pubDate>
      <link>https://dev.to/cad97/rust-must-know-crates-5ad8</link>
      <guid>https://dev.to/cad97/rust-must-know-crates-5ad8</guid>
      <description>&lt;p&gt;This is my collection of Rust crates that I often find myself using. Not every project needs to use all of them, but most projects are better off knowing that they exist. Crates are &lt;em&gt;very&lt;/em&gt; loosely ordered within their heading from more generally useful to more niche application.&lt;/p&gt;

&lt;p&gt;This list will be kept somewhat up to date as my preferences and the ecosystem shift. This is obviously not a complete list of great crates, but just an introduction to the great ecosystem of Rust utilities available to programmers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cargo Plugins
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-edit"&gt;cargo-edit&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This tool extends Cargo to allow you to add, remove, and upgrade dependencies by modifying your Cargo.toml file from the command line.&lt;/p&gt;

&lt;p&gt;Currently available subcommands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cargo add&lt;/li&gt;
&lt;li&gt;cargo rm&lt;/li&gt;
&lt;li&gt;cargo upgrade&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-outdated"&gt;cargo-outdated&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A cargo subcommand for displaying when Rust dependencies are out of date.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-tree"&gt;cargo-tree&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A Cargo subcommand that visualizes a crate's dependency graph in a tree-like format.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-update"&gt;cargo-update&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A Cargo subcommand for checking and applying updates to installed executables.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-expand"&gt;cargo-expand&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Print out the result of macro expansion and &lt;code&gt;#[derive]&lt;/code&gt; expansion applied to the current crate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-modules"&gt;cargo-modules&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A cargo plugin for showing an overview of a crate's modules.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-tarpaulin"&gt;cargo-tarpaulin&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Tarpaulin is designed to be a code coverage reporting tool for the Cargo build system, named for a waterproof cloth used to cover cargo on a ship. Currently, tarpaulin provides working line coverage but is still in the early development stage and therefore may contain some bugs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://crates.io/crates/cargo-audit"&gt;cargo-audit&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Audit Cargo.lock for crates with security vulnerabilities reported to the RustSec Advisory Database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-crev"&gt;cargo-crev&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A tool helping Rust users review crates they use, and share it with the community. It works as a recomendation system, helps identify poor quality, protects against many attack vectors, and aims at driving the quality of Rust ecosystem even higher, by encouraging continous peer review culture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/cargo-clone"&gt;cargo-clone&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Fetch the source code of a Rust crate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;cargo clone&lt;/code&gt; will likely be added to cargo proper at some point.&lt;/p&gt;

&lt;h1&gt;
  
  
  Derives
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/derive_more"&gt;derive-more&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Rust has lots of builtin traits that are implemented for its basic types, such as &lt;code&gt;Add&lt;/code&gt;, &lt;code&gt;Not&lt;/code&gt; or &lt;code&gt;From&lt;/code&gt;. However, when wrapping these types inside your own structs or enums you lose the implementations of these traits and are required to recreate them. This is especially annoying when your own structures are very simple, such as when using the commonly advised newtype pattern (e.g. &lt;code&gt;MyInt(i32)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This library tries to remove these annoyances and the corresponding boilerplate code. It does this by allowing you to derive lots of commonly used traits for both structs and enums.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Derives for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jeltef.github.io/derive_more/derive_more/from.html"&gt;&lt;code&gt;From&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeltef.github.io/derive_more/derive_more/into.html"&gt;&lt;code&gt;Into&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeltef.github.io/derive_more/derive_more/from_str.html"&gt;&lt;code&gt;FromStr&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeltef.github.io/derive_more/derive_more/try_into.html"&gt;&lt;code&gt;TryInto&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeltef.github.io/derive_more/derive_more/display.html"&gt;&lt;code&gt;Display&lt;/code&gt;-like&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jeltef.github.io/derive_more/derive_more/index_op.html"&gt;&lt;code&gt;Index&lt;/code&gt;&lt;/a&gt;(&lt;a href="https://jeltef.github.io/derive_more/derive_more/index_mut.html"&gt;&lt;code&gt;Mut&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jeltef.github.io/derive_more/derive_more/deref.html"&gt;&lt;code&gt;Deref&lt;/code&gt;&lt;/a&gt;(&lt;a href="https://jeltef.github.io/derive_more/derive_more/deref_mut.html"&gt;&lt;code&gt;Mut&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jeltef.github.io/derive_more/derive_more/add.html"&gt;&lt;code&gt;Add&lt;/code&gt;&lt;/a&gt;(&lt;a href="https://jeltef.github.io/derive_more/derive_more/add_assign.html"&gt;&lt;code&gt;Assign&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jeltef.github.io/derive_more/derive_more/mul.html"&gt;&lt;code&gt;Mul&lt;/code&gt;&lt;/a&gt;(&lt;a href="https://jeltef.github.io/derive_more/derive_more/mul_assign.html"&gt;&lt;code&gt;Assign&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeltef.github.io/derive_more/derive_more/not.html"&gt;&lt;code&gt;Not&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and more!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/smart-default"&gt;smart-default&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Custom derive for automatically implementing the &lt;code&gt;Default&lt;/code&gt; trait with customized default values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/derive_builder"&gt;derive-builder&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Rust macro to automatically implement the builder pattern for arbitrary structs. A simple &lt;code&gt;#[derive(Builder)]&lt;/code&gt; will generate a &lt;code&gt;FooBuilder&lt;/code&gt; for your struct &lt;code&gt;Foo&lt;/code&gt; with all setter-methods and a build method.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/strum"&gt;strum&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A set of macros and traits for working with enums and strings easier in Rust.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Derives for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Peternator7/strum#Display"&gt;&lt;code&gt;Display&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Peternator7/strum#AsRefStr"&gt;&lt;code&gt;AsRefStr&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Peternator7/strum#IntoStaticStr"&gt;&lt;code&gt;IntoStaticStr&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Peternator7/strum#enumiter"&gt;&lt;code&gt;EnumIter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Peternator7/strum#enumcount"&gt;&lt;code&gt;EnumCount&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and more!&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Meta-programming (macros)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/syn"&gt;syn&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree of Rust source code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://libs.rs/crates/proc_macro2"&gt;proc-macro2&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A runtime-compatible wrapper around the procedural macro API of the compiler's &lt;code&gt;proc_macro&lt;/code&gt; crate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/proc-quote"&gt;proc-quote&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;quote!&lt;/code&gt; macro as a procedural macro, instead of the original &lt;code&gt;quote!&lt;/code&gt; macro, implemented with &lt;code&gt;macro_rules!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;quote!&lt;/code&gt; macro turns Rust syntax tree data structures into tokens of source code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/paste"&gt;paste&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A flexible way to paste together identifiers in a macro, including using pasted identifiers to define new items.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Testing
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/insta"&gt;insta&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Snapshots tests (also sometimes called approval tests) are tests that assert values against a reference value (the snapshot). This is similar to how &lt;code&gt;assert_eq!&lt;/code&gt; lets you compare a value against a reference value but unlike simple string assertions snapshot tests let you test against complex values and come with comprehensive tools to review changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/trybuild"&gt;trybuild&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Trybuild is a test harness for invoking rustc on a set of test cases and asserting that any resulting error messages are the ones intended.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/criterion"&gt;Criterion&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Helps you write fast code by detecting and measuring performance improvements or regressions, even small ones, quickly and accurately. You can optimize with confidence, knowing how each change affects the performance of your code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Other Libraries
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/regex"&gt;Regex&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A Rust library for parsing, compiling, and executing regular expressions. Its syntax is similar to Perl-style regular expressions, but lacks a few features like look around and backreferences. In exchange, all searches execute in linear time with respect to the size of the regular expression and search text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/lazy_static"&gt;lazy-static&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A macro for declaring lazily evaluated statics in Rust.&lt;/p&gt;

&lt;p&gt;Using this macro, it is possible to have statics that require code to be executed at runtime in order to be initialized. This includes anything requiring heap allocations, like vectors or hash maps, as well as anything that requires non-const function calls to be computed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/rayon"&gt;Rayon&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Rayon is a data-parallelism library for Rust. It is extremely lightweight and makes it easy to convert a sequential computation into a parallel one. It also guarantees data-race freedom.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/serde"&gt;serde&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.&lt;/p&gt;

&lt;p&gt;The Serde ecosystem consists of data structures that know how to serialize and deserialize themselves along with data formats that know how to serialize and deserialize other things. Serde provides the layer by which these two groups interact with each other, allowing any supported data structure to be serialized and deserialized using any supported data format.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://lib.rs/crates/typetag"&gt;typetag&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Serde serializable and deserializable trait objects.&lt;/p&gt;

&lt;p&gt;This crate provides a macro for painless serialization of &lt;code&gt;&amp;amp;dyn Trait&lt;/code&gt; trait objects and serialization + deserialization of &lt;code&gt;Box&amp;lt;dyn Trait&amp;gt;&lt;/code&gt; trait objects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/crossbeam"&gt;Crossbeam&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A set of tools for concurrent programming.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/itertools"&gt;Itertools&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Extra iterator adapters, functions and macros.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/rand"&gt;Rand&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A Rust library for random number generation.&lt;/p&gt;

&lt;p&gt;Rand provides utilities to generate random numbers, to convert them to useful types and distributions, and some randomness-related algorithms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/log"&gt;log&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A Rust library providing a lightweight logging facade.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/walkdir"&gt;WalkDir&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A cross platform Rust library for efficiently walking a directory recursively. Comes with support for following symbolic links, controlling the number of open file descriptors and efficient mechanisms for pruning the entries in the directory tree.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/directories"&gt;Directories&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A tiny mid-level library that provides platform-specific standard locations of directories for config, cache and other data on Linux, Windows and macOS by leveraging the mechanisms defined by the XDG base/user directory specifications on Linux, the Known Folder API on Windows, and the Standard Directory guidelines on macOS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/tempfile"&gt;tempfile&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A secure, cross-platform, temporary file library for Rust. In addition to creating temporary files, this library also allows users to securely open multiple independent references to the same temporary file (useful for consumer/producer patterns and surprisingly difficult to implement securely).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/num"&gt;num&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A collection of numeric types and traits for Rust, including bigint, complex, rational, range iterators, generic integers, and more!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/structopt"&gt;StructOpt&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Parse command line argument by defining a struct. It combines clap with custom derive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/scopeguard"&gt;ScopeGuard&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Rust crate for a convenient RAII scope guard that will run a given closure when it goes out of scope, even if the code between panics (assuming unwinding panic).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/ref-cast"&gt;ref-cast&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Safely cast &lt;code&gt;&amp;amp;T&lt;/code&gt; to &lt;code&gt;&amp;amp;U&lt;/code&gt; where the struct &lt;code&gt;U&lt;/code&gt; contains a single field of type &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lib.rs/crates/select-rustc"&gt;select-rustc&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Macros for conditional compilation according to rustc compiler version, analogous to &lt;code&gt;#[cfg(...)]&lt;/code&gt; and &lt;code&gt;#[cfg_attr(...)]&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>rust</category>
      <category>awesomelist</category>
      <category>libraries</category>
      <category>list</category>
    </item>
    <item>
      <title>On "Async Streams" in Rust</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Mon, 15 Apr 2019 20:36:10 +0000</pubDate>
      <link>https://dev.to/cad97/on-async-streams-in-rust-25eo</link>
      <guid>https://dev.to/cad97/on-async-streams-in-rust-25eo</guid>
      <description>

&lt;p&gt;Context: &lt;a href="https://internals.rust-lang.org/t/for-await-loops/9819?u=cad97"&gt;For await loops&lt;/a&gt; discussion started by @withoutboats on Internals.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: What is a &lt;code&gt;Stream&lt;/code&gt;?
&lt;/h1&gt;

&lt;p&gt;I found the most clear consise explanation comes from @withoutboats again &lt;a href="https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/10?u=cad97"&gt;on a different Internals thread&lt;/a&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            | Evaluated immediately     | Evaluated asynchronously
------------------------------------------------------------------------
Return once | `fn() -&amp;gt; T`    (Function) | `async fn() -&amp;gt; T`    (Future)
Yield many  | `fn() yield T` (Iterator) | `async fn() yield T` (Stream)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When you use a Function, you evaluate some routine to retrieve a value.&lt;/li&gt;
&lt;li&gt;When you use an Iterator, you evaluate some routine to retrieve the next value, multiple times.&lt;/li&gt;
&lt;li&gt;When you use a Future, you await some routine to retrieve a value.&lt;/li&gt;
&lt;li&gt;When you use a Stream, you await some routine to retrieve the next value, multiple times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Step 2: How do we use a &lt;code&gt;Stream&lt;/code&gt;?
&lt;/h1&gt;

&lt;p&gt;To determine this, let's look at the other points in the matrix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function
&lt;/h2&gt;

&lt;p&gt;Trivial: &lt;code&gt;function()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Iterator
&lt;/h2&gt;

&lt;p&gt;A for loop: &lt;code&gt;for item in iterator()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This effectively desugars to code using the &lt;a href="https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html"&gt;&lt;code&gt;Iterator&lt;/code&gt;&lt;/a&gt; trait (simplified):&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;__iter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;__iter&lt;/span&gt;&lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// your block&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Future
&lt;/h2&gt;

&lt;p&gt;The exact syntax to be used to await a &lt;a href="https://doc.rust-lang.org/stable/std/future/trait.Future.html"&gt;&lt;code&gt;Future&lt;/code&gt;&lt;/a&gt; is still being decided by the lang team. The only fairly decided thing is that it will involve the reserved keyword &lt;code&gt;await&lt;/code&gt;. I'll use &lt;code&gt;await!(future)&lt;/code&gt; in this document as it's the current unstable syntax and fully unambiguous.&lt;/p&gt;

&lt;p&gt;This is extremely simplified, but awaiting a future expands to roughly the following in concept:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;__future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;__stack_pin!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;__future&lt;/span&gt;&lt;span class="nf"&gt;.poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;__async_context_waker!&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Pending&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;__async_yield_execution!&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Stream
&lt;/h2&gt;

&lt;p&gt;So, how are &lt;a href="https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/prelude/trait.Stream.html"&gt;&lt;code&gt;Stream&lt;/code&gt;&lt;/a&gt;s used &lt;em&gt;before&lt;/em&gt; syntax sugar? This is important to understand the semantics we're trying to represent.&lt;/p&gt;

&lt;p&gt;We have &lt;code&gt;Iterator&lt;/code&gt;, but instead of the function &lt;code&gt;Iterator::next&lt;/code&gt;, we have the future &lt;code&gt;Stream::poll_next&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;__stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;__stack_pin!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;await!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;__future_from_poll!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;__stream&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;poll_next&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// your block&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This still hides some details in the &lt;code&gt;await!(__future_from_poll!())&lt;/code&gt;, so lets inline that:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;__stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;__stack_pin!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;__stream&lt;/span&gt;&lt;span class="nf"&gt;.poll_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;__async_context_waker!&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Pending&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;__async_yield_execution!&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// your block&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Wow&lt;/em&gt;, everything makes some amount of sense! But how do we actually use this, because this is a lot of boilerplate to use what seems like a useful data type.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3: What Not
&lt;/h1&gt;

&lt;p&gt;The logical operation happening here is awaiting the next value from the stream, for every element in the stream: a combination of iterators (&lt;code&gt;for item in iterator&lt;/code&gt;) and futures (&lt;code&gt;await!(future)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The "obvious" solution would be &lt;code&gt;async for item in stream&lt;/code&gt;. But this is the wrong direction: &lt;code&gt;async&lt;/code&gt; is the enabler, but &lt;code&gt;await&lt;/code&gt; is how you poll a future to completion.&lt;/p&gt;

&lt;p&gt;Another enticing solution is to make &lt;code&gt;for&lt;/code&gt; just work with &lt;code&gt;Stream&lt;/code&gt;s and do the equivalent of &lt;code&gt;impl&amp;lt;I: Iterator&amp;gt; Stream for I&lt;/code&gt;. But we made (are making) the await operation explicit on futures for good reason, and shouldn't lose that for streams, if for no other reason than it would be inconsistent.&lt;/p&gt;

&lt;p&gt;I've seen in multiple places the suggestion to use &lt;code&gt;for item in await!(stream)&lt;/code&gt;. Hopefully, the above expansions illustrate why that doesn't work semantically. This would instead be awaiting a &lt;code&gt;Future&amp;lt;Item=Iterator&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4: Possibilities
&lt;/h1&gt;

&lt;p&gt;I personally think that &lt;code&gt;await for item in stream&lt;/code&gt; reads perfectly for what the semantics are. Those semantics are that we &lt;code&gt;await&lt;/code&gt; "something" to get each item out of the stream, or in other words, we "(a)wait for each item in the stream". There's also no possibility of being confused with &lt;code&gt;await!(for item in stream {})&lt;/code&gt;, as &lt;code&gt;for&lt;/code&gt; loops don't (and can't) return a value.&lt;/p&gt;

&lt;p&gt;@withoutboats also suggests that we could make &lt;code&gt;await&lt;/code&gt; a pattern, giving us &lt;code&gt;for await item in stream&lt;/code&gt;. I don't hate it, but there's a problem with this.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;await&lt;/code&gt; as a pattern (here I'll still use &lt;code&gt;await!(pattern)&lt;/code&gt; for clarity) I would expect to be the same as awaiting the rhs of the pattern. Or in code, the following two statements would be equivalent:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let value = await!(future);
let await!(value) = future;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This was actually proposed previously in the venerable &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; bikeshedding thread.&lt;/p&gt;

&lt;p&gt;The problem is that this now suggests that &lt;code&gt;Stream&amp;lt;Item=T&amp;gt;&lt;/code&gt; is &lt;code&gt;Iterator&amp;lt;Item=Future&amp;lt;Item=T&amp;gt;&amp;gt;&lt;/code&gt;. Maybe some streams could meet this type. But the current definition of &lt;code&gt;Stream&lt;/code&gt; is closer to a &lt;code&gt;StreamingIterator&amp;lt;Item=Future&amp;lt;Item=T&amp;gt;&amp;gt;&lt;/code&gt;, as the &lt;code&gt;poll_next&lt;/code&gt; requires a pin mut ref to the stream. This borrowing is required for many real streams. (I expect &lt;code&gt;Stream&lt;/code&gt; to be abused for &lt;code&gt;StreamingIterator&lt;/code&gt; if it works for such and we don't have &lt;code&gt;StreamingIterator&lt;/code&gt; yet.)&lt;/p&gt;

&lt;p&gt;This could be made to work fairly simply: make &lt;code&gt;for&lt;/code&gt; work with &lt;code&gt;StreamingIterator&lt;/code&gt; with a fallback for &lt;code&gt;Iterator&lt;/code&gt; behavior, and let streams be used by the above composition of &lt;code&gt;StreamingIterator&lt;/code&gt; and &lt;code&gt;Future&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But this still lacks the "&lt;code&gt;await?&lt;/code&gt;" behavior that many real futures will want (as most async is so because of IO). And even if we add &lt;code&gt;?&lt;/code&gt; to patterns as well, this still means we have two ways of doing the same await operation: expr position (for chaining, which was a focus of the bikeshedding thread) and pat position.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 5: Conclusions
&lt;/h1&gt;

&lt;p&gt;I think that &lt;code&gt;await for&lt;/code&gt; is the best of the currently proposed syntaxes, at least while awaiting on futures includes the keyword &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In any case, this is a difficult choice with many tradeoffs, and one that's even harder to make without knowing what the final &lt;code&gt;await&lt;/code&gt; syntax is going to be. But it's one that needs to be at least considered when stabilizing &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;


</description>
      <category>rust</category>
      <category>languagedesign</category>
      <category>async</category>
    </item>
    <item>
      <title>Great Rust CI</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Sat, 20 Jan 2018 03:39:40 +0000</pubDate>
      <link>https://dev.to/cad97/great-rust-ci-1fk6</link>
      <guid>https://dev.to/cad97/great-rust-ci-1fk6</guid>
      <description>&lt;p&gt;Great CI means coding with confidence. And the CI-compatible tooling situation for Rust is great, so you should take advantage of it.&lt;/p&gt;

&lt;p&gt;If you don't know the full details of all of the available tools, though, it can be difficult to set up the perfect CI. So here, I'll walk you through the setup that I'm using.&lt;/p&gt;




&lt;h2&gt;
  
  
  Install local tools.
&lt;/h2&gt;

&lt;p&gt;Here's what I use every day:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/rust-lang-nursery/rust-clippy" rel="noopener noreferrer"&gt;Clippy&lt;/a&gt;: code linting for more opinionated things than what rustc gives you.&lt;/p&gt;

&lt;p&gt;For now, clippy will only work with the latest nightly. Install and update nightly rust with rustup, then run &lt;code&gt;cargo +nightly install clippy --force&lt;/code&gt; to force a clippy install built against your current nightly. Use it with &lt;code&gt;cargo +nightly clippy&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/rust-lang-nursery/rustfmt" rel="noopener noreferrer"&gt;Rustfmt&lt;/a&gt;: automatic code formatting.&lt;/p&gt;

&lt;p&gt;For &lt;em&gt;many&lt;/em&gt; (though not all, sadly) nightlies, rustfmt can be managed using rustup, just like you can for rls. If the nightly that you're on contains rustfmt, you can do &lt;code&gt;rustup component add rustfmt-preview&lt;/code&gt;. If your nightly doesn't contain rustfmt-preview, you can install it from crates.io: &lt;code&gt;cargo +nightly install rustfmt-nightly --force&lt;/code&gt;. Having both the rustup managed and cargo managed versions can lead to conflicts, so use one or the other. Use it with &lt;code&gt;cargo +nightly fmt&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/nabijaczleweli/cargo-update" rel="noopener noreferrer"&gt;Cargo-Update&lt;/a&gt;: check for and update cargo-install-ed binaries.&lt;/p&gt;

&lt;p&gt;Not as much help for clippy/rustfmt, which need to be force-reinstalled for every new nightly (because they link against it), but invaluable for seamlessly updating other tools (including itself). (Requires CMake)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optional: &lt;a href="https://github.com/killercup/cargo-edit" rel="noopener noreferrer"&gt;Cargo-Edit&lt;/a&gt;: modify the build manifest (&lt;code&gt;Cargo.toml&lt;/code&gt;) from the command line with simple commands, rather than editing the file by hand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optional: IDE support. I use IntelliJ IDEA with the &lt;a href="https://intellij-rust.github.io/" rel="noopener noreferrer"&gt;IntelliJ Rust&lt;/a&gt; plugin. There's also &lt;a href="https://marketplace.visualstudio.com/items?itemName=rust-lang.rust" rel="noopener noreferrer"&gt;RLS for VSCode&lt;/a&gt;, or you could use &lt;a href="https://github.com/rust-lang/rust.vim" rel="noopener noreferrer"&gt;Vim&lt;/a&gt; or &lt;a href="https://github.com/rust-lang/rust-mode" rel="noopener noreferrer"&gt;Emacs&lt;/a&gt; if you're into that kind of thing (no judging!).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Create your project!
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo new great-ci
     Created library `great-ci` project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's good practice to set up &lt;code&gt;.git/info/exclude&lt;/code&gt; to tell git to ignore your IDE files. For me, that means the contents of the git exclude are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.idea/
*.iml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for the purpose of this example, let's make a tiny "Hello World" style library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;//! Example library for great CI integration!&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// Greetings to some target&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Copy,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Hash)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Greeting&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Greeting&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Construct a Greeter to greet a target&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Greeting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Display&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Greeting&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Formatter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;write!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Greetings, {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;#[test]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;it_works&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;#[test]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;greet_author&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CAD97"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeter&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Greetings, CAD97!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a LICENSE and README, then it's time to commit and &lt;a href="https://github.com/CAD97/great-ci/tree/91a0947f638fb7beda5356e7dc520296fcffae93" rel="noopener noreferrer"&gt;get the code online&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git add .
$ git commit -m "Initial commit"
$ git remote add CAD97 git@github.com:CAD97/great-ci.git
$ git push -u CAD97 master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up CI
&lt;/h2&gt;

&lt;p&gt;The part that we care about! I use &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;Travis CI&lt;/a&gt;, &lt;a href="https://github.com/roblabla/cargo-travis" rel="noopener noreferrer"&gt;Cargo-Travis&lt;/a&gt;, &lt;a href="https://codecov.io/" rel="noopener noreferrer"&gt;Codecov&lt;/a&gt;, and &lt;a href="https://bors.tech/" rel="noopener noreferrer"&gt;Bors&lt;/a&gt; for my CI stack.&lt;/p&gt;

&lt;p&gt;So let's switch to a feature branch and set up a basic &lt;code&gt;bors.toml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"continuous-integration/travis-ci/push"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and &lt;code&gt;.travis.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rust&lt;/span&gt;

&lt;span class="na"&gt;rust&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;beta&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nightly&lt;/span&gt;

&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;cargo build --verbose &amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="s"&gt;cargo test  --verbose &amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="s"&gt;cargo doc   --verbose&lt;/span&gt;

&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt; &lt;span class="c1"&gt;# bors r+&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;trying&lt;/span&gt;  &lt;span class="c1"&gt;# bors try&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;don't forget to enable Travis and Bors for the repository (I did), and then &lt;a href="https://github.com/CAD97/great-ci/pull/2" rel="noopener noreferrer"&gt;send a PR&lt;/a&gt;. If all goes well, your CI is green and you can merge with &lt;code&gt;bors r+&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing rustfmt and clippy
&lt;/h2&gt;

&lt;p&gt;When you're working with a project you expect to get large, it can help to enforce standard formatting, and clippy does wonders for preventing simple mistakes and nudging people away from &lt;a href="https://rust-lang-nursery.github.io/rust-clippy/current/index.html#wrong_self_convention" rel="noopener noreferrer"&gt;questionable API decisions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Because rustfmt and clippy are somewhat unstable, requiring certain small ranges of nightly compilers and sometimes breaking, and changing default formatting or adding lints may break your build, we depend on specific versions of the tools, and you can update the versions manually.&lt;/p&gt;

&lt;p&gt;We use a &lt;a href="https://docs.travis-ci.com/user/customizing-the-build/#Explicitly-Including-Jobs" rel="noopener noreferrer"&gt;matrix include&lt;/a&gt; on Travis to add the check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo&lt;/span&gt;
&lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;rust&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nightly-2018-01-12&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# use env so updating versions causes cache invalidation&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLIPPY_VERSION=0.0.179&lt;/span&gt;
      &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rustup component add rustfmt-preview&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo install clippy --version $CLIPPY_VERSION || echo "clippy already installed"&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo fmt -- --write-mode=diff&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo clippy -- -D clippy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we install clippy using &lt;code&gt;cargo install&lt;/code&gt;, or succeed if it's already installed. We install rustfmt using rustup, because in Travis's Rust setup, rustfmt is already tracked by rustup, so the &lt;code&gt;cargo-fmt&lt;/code&gt; executable exists, and an install without &lt;code&gt;--force&lt;/code&gt; will fail. And if we don't pick a nightly toolchain that actually contains &lt;code&gt;cargo-fmt&lt;/code&gt;, using it will fail. Here we have &lt;code&gt;rust: nightly-2018-01-12 CLIPPY_VERSION=0.0.179&lt;/code&gt; because this is the latest toolchain as-of-writing where rustfmt-preview is in, and the latest version of clippy which builds on that nightly.&lt;/p&gt;

&lt;p&gt;Installing tools like rustfmt and clippy takes time, and CI is made great when it's &lt;em&gt;fast&lt;/em&gt;, so we enable &lt;a href="https://docs.travis-ci.com/user/caching/#Rust-Cargo-cache" rel="noopener noreferrer"&gt;Travis's Rust Cargo cache&lt;/a&gt; to cache cargo's symbols. This speeds up the build because cargo doesn't have to recompile dependencies, whether these be build dependencies or tools.&lt;/p&gt;

&lt;p&gt;The cache is keyed by the language version (here &lt;code&gt;rust: nightly-2018-01-18&lt;/code&gt;) and the env (here &lt;code&gt;CLIPPY_VERSION=0.0.180&lt;/code&gt;), and shared between build jobs with the same rust version and env. By putting clippy's version in the env, we separate the tool build's cache from the other caches, and ensure that a version update causes a rebuild.&lt;/p&gt;

&lt;p&gt;You may be tempted to stick these environment variables in the CI configuration, so that you can update them without an extra commit to the repository. This is ill-advisable, for two main reasons. Primarily, version bumping these tools has a high likelihood of changing requirements for your build, and the breakage will show up unannounced. This change should be marked in your repository. Secondarily, the use of env here also serves to separate the cache for these tools from the other caches. If the specified rust version is the most up-to-date nightly, this cache and the nightly cache would clobber each other. And you don't want to force installation of these tools on CI builds that don't require it, because we want those &lt;em&gt;zippy&lt;/em&gt; CI greens.&lt;/p&gt;

&lt;p&gt;So make these changes, &lt;a href="https://github.com/CAD97/great-ci/pull/3" rel="noopener noreferrer"&gt;submit a PR&lt;/a&gt;, and we're go for the last step!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using cargo-travis
&lt;/h2&gt;

&lt;p&gt;Cargo-travis enables you to easily use &lt;a href="https://github.com/SimonKagstrom/kcov" rel="noopener noreferrer"&gt;kcov&lt;/a&gt; and upload coverage information to codecov or coveralls. Additionally, added by myself recently, it allows you to upload documentation for your crate to GitHub pages and maintain an understandable git history and directory structure allowing you to document multiple branches (&lt;code&gt;master&lt;/code&gt;/&lt;code&gt;beta&lt;/code&gt;/&lt;code&gt;release&lt;/code&gt; branches to imitate Rust's &lt;code&gt;nightly&lt;/code&gt;/&lt;code&gt;beta&lt;/code&gt;/&lt;code&gt;stable&lt;/code&gt; trains) if you so wish.&lt;/p&gt;

&lt;p&gt;Because these tasks can take a while, and are more for informing decisions rather than to hard gate PRs, I stick these into a allowed-failure matrix line for my builds. This means that Travis passes as soon as the four above jobs pass (&lt;code&gt;rust: [stable, beta, nightly]&lt;/code&gt;, rustfmt&amp;amp;clippy), and allows the cargo-travis job to continue running in the background.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;.travis.yml&lt;/code&gt; additions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# required for allow_failures&lt;/span&gt;
&lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fast_finish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;allow_failures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NAME='cargo-travis'&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NAME='cargo-travis'&lt;/span&gt;
      &lt;span class="na"&gt;sudo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt; &lt;span class="c1"&gt;# travis-ci/travis-ci#9061&lt;/span&gt;
      &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo install cargo-update || echo "cargo-update already installed"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo install cargo-travis || echo "cargo-travis already installed"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo install-update -a&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;cargo build    --verbose &amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="s"&gt;cargo coverage --verbose &amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="s"&gt;bash &amp;lt;(curl -s https://codecov.io/bash) -s target/kcov&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;cargo doc --verbose &amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="s"&gt;cargo doc-upload&lt;/span&gt;
      &lt;span class="na"&gt;addons&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# required for kcov&lt;/span&gt;
        &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libcurl4-openssl-dev&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libelf-dev&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libdw-dev&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;binutils-dev&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cmake&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to use Coveralls, just use &lt;code&gt;cargo coveralls&lt;/code&gt; instead of &lt;code&gt;cargo coverage&lt;/code&gt;. If you don't want to use Codecov, just remove the line for the Codecov bash script.&lt;/p&gt;

&lt;p&gt;This isn't enough for the &lt;code&gt;doc-upload&lt;/code&gt; task, however (though this &lt;em&gt;will not&lt;/em&gt; make your CI go red, as we allow this job to fail). In order to upload documentation, the &lt;code&gt;doc-upload&lt;/code&gt; script needs permission to push to your GitHub repository. The easiest way, which we will use here, is a &lt;a href="https://github.com/blog/1509-personal-api-tokens" rel="noopener noreferrer"&gt;GitHub token&lt;/a&gt;, but you can read more about the options at the &lt;a href="https://github.com/roblabla/cargo-travis#doc-upload" rel="noopener noreferrer"&gt;cargo-travis README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to generate a GitHub token, navigate to &lt;a href="https://github.com/settings/tokens" rel="noopener noreferrer"&gt;your tokens settings page&lt;/a&gt;. While you're there, review your currently issued tokens, and revoke those that you're no longer using. Generate a new token, give it a descriptive name (this can be edited later) (I suggest &lt;code&gt;repo-name-doc-upload&lt;/code&gt;) and the &lt;code&gt;public_repo&lt;/code&gt; scope (this can be edited later). Make sure to copy the token once it's generated, as you will never be able to see it again (though you can regenerate it)! This token gives anyone with the token access to act as you when read/writing to any public repository you have the permission to read/write to, so keep it safe. Add it to the &lt;code&gt;GH_TOKEN&lt;/code&gt; environment variable on Travis and &lt;em&gt;make sure that "Display value in build log" is set to off&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1b0yr05zo1uxn3e59lc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1b0yr05zo1uxn3e59lc.png" alt="Environment Variables" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you &lt;a href="https://github.com/CAD97/great-ci/pull/4" rel="noopener noreferrer"&gt;send your PR&lt;/a&gt;, the new job will kick off.&lt;/p&gt;

&lt;p&gt;A few things to note about this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI will pass before coverage is done. This is intentional, as we want to see quick CI feedback for tests passing/failing, and coverage doesn't need to slow down that feedback loop for PRs (or the time it takes to &lt;code&gt;bors r+&lt;/code&gt; and merge). We still want to see those stats, though, and Codecov/Coveralls will still do its analysis and leave a comment once the coverage information is uploaded.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cargo-travis&lt;/code&gt; will take a good long time the first time around; you have to build a large number of tools, including kcov itself. Hopefully, however, all of this will be cached, so subsequent builds will be much faster.&lt;/li&gt;
&lt;li&gt;Documentation will be built when CI builds the master branch only. You can specify which branches to build by passing (optionally multiple) &lt;code&gt;--branch NAME&lt;/code&gt; arguments to &lt;code&gt;cargo doc-upload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;doc-upload&lt;/code&gt; &lt;em&gt;does not&lt;/em&gt; build documentation for you, so you need to call &lt;code&gt;cargo doc&lt;/code&gt; yourself. This is so that you can, if your library offers feature flags or other conditional compilation, build up a directory in &lt;code&gt;target/doc&lt;/code&gt; (rustdoc's output directory) which &lt;code&gt;doc-upload&lt;/code&gt; will then use when uploading to GitHub pages.&lt;/li&gt;
&lt;li&gt;Documentation ends up living at &lt;code&gt;https://&amp;lt;user&amp;gt;.github.io/&amp;lt;repo&amp;gt;/&amp;lt;branch&amp;gt;/&amp;lt;crate&amp;gt;/&lt;/code&gt;, which is &lt;a href="https://cad97.github.io/great-ci/master/great_ci/" rel="noopener noreferrer"&gt;https://cad97.github.io/great-ci/master/great_ci/&lt;/a&gt; for this example.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codecov.io/gh/CAD97/great-ci" rel="noopener noreferrer"&gt;Coverage is 100%&lt;/a&gt; 🎉&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further extensions
&lt;/h2&gt;

&lt;p&gt;If you want to (or need to) test on a Windows platform, &lt;a href="https://www.appveyor.com/" rel="noopener noreferrer"&gt;AppVeyor&lt;/a&gt; is often used. This CI can be used in parallel to this Travis setup with no problems. Make sure to tell Bors to wait for the AppVeyor build, however!&lt;/p&gt;

&lt;p&gt;Don't forget that you can suppress rustfmt and clippy warnings if you don't want them to apply to certain blocks of code. If it's an issue in the source library, submit an issue, or if it's just a disagreement, check the configuration and see if you can change it there.&lt;/p&gt;

&lt;p&gt;For the security-minded, the &lt;code&gt;public_repo&lt;/code&gt; scope of the GitHub token may be too broad. This is a solved problem; the solution is repo-specific deploy keys. If you provide a deploy key for your repository and load it into Travis (and don't provide a token), &lt;code&gt;doc-upload&lt;/code&gt; will use it.&lt;/p&gt;

&lt;p&gt;You've got the CI set up, brag about it in your README using badges and by embedding coverage charts! &lt;a href="https://shields.io/" rel="noopener noreferrer"&gt;Shields|IO&lt;/a&gt; provides consistently-styled badges for practically every service, and &lt;a href="https://codecov.io/gh/CAD97/great-ci/branch/master/graphs" rel="noopener noreferrer"&gt;Codecov graphs&lt;/a&gt; are 🔥🔥🔥.&lt;/p&gt;

&lt;p&gt;The base page of your GitHub pages (&lt;code&gt;&amp;lt;user&amp;gt;.github.io/&amp;lt;repo&amp;gt;/&lt;/code&gt;) is going to 404, as no &lt;code&gt;index.html&lt;/code&gt; exists at the root of your &lt;code&gt;gh-pages&lt;/code&gt; branch. The same for the branch root (&lt;code&gt;&amp;lt;user&amp;gt;.gihub.io/&amp;lt;repo&amp;gt;/&amp;lt;branch&amp;gt;&lt;/code&gt;). &lt;code&gt;doc-upload&lt;/code&gt; deliberately doesn't mess with your root directory or the &lt;code&gt;index.html&lt;/code&gt; at the branch root so that you can include a HTML redirect at these spots or a more informative index if you want. For a HTML redirect, use the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"refresh"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"0; url=&amp;lt;crate&amp;gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;crate&amp;gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Redirect&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://redd.it/7rnyg8" rel="noopener noreferrer"&gt;Discuss this on Reddit&lt;/a&gt; and tell me if I left something out or something is outdated!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CAD97/great-ci" rel="noopener noreferrer"&gt;See the public repository on GitHub!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cargo</category>
      <category>travis</category>
      <category>ci</category>
    </item>
    <item>
      <title>Refutable Let and Rust in 2018</title>
      <dc:creator>Crystal Durham</dc:creator>
      <pubDate>Thu, 11 Jan 2018 03:54:02 +0000</pubDate>
      <link>https://dev.to/cad97/refutable-let-and-rust-in-2018-4l3k</link>
      <guid>https://dev.to/cad97/refutable-let-and-rust-in-2018-4l3k</guid>
      <description>&lt;p&gt;This examines the postponed &lt;a href="https://github.com/rust-lang/rfcs/pull/1303" rel="noopener noreferrer"&gt;RFC #1303 "Add a &lt;code&gt;let...else&lt;/code&gt; expression"&lt;/a&gt;, addressing the RFC issue &lt;a href="https://github.com/rust-lang/rfcs/issues/373" rel="noopener noreferrer"&gt;#373 "Explicit refutable &lt;code&gt;let&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This probably will end up formatted like an RFC, and I'd be willing to adapt it to a new RFC since the old one was postponed nearly two years ago now.&lt;/p&gt;

&lt;h2&gt;
  
  
  A motivating example
&lt;/h2&gt;

&lt;p&gt;Consider a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make B"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two key problems here. The first is locality of error handling. The error for line 1 is returned on line 12 of this tiny example. The second is rightward drift. The actual meat of the function (here just &lt;code&gt;Ok(c)&lt;/code&gt;) is indented three levels deep. This RFC introduces a "refutable let binding" in order to address both of these issues.&lt;/p&gt;

&lt;p&gt;First, let me address the obvious refactor to this minimal example. The current function signatures look something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;make_a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;     &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;make_b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;make_c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The obvious "best" answer would be for these to return a &lt;code&gt;Result&lt;/code&gt; with a descriptive error message that you could then propogate with &lt;code&gt;?&lt;/code&gt;. In a real case, though, maybe &lt;code&gt;Option&lt;/code&gt; really is the right semantic type to return, and maybe it's vendor code you can't change, etc. etc..&lt;/p&gt;

&lt;p&gt;Secondly: You could &lt;code&gt;Option::ok_or_else?&lt;/code&gt;. This is how I would write this today. To be fully honest, I'd maybe still write it that way, because &lt;code&gt;ok_or_else&lt;/code&gt; is the exact behavior that I want and is very clear. But assume for the sake of argument that this is a more complicated example, such as destructuring a complicated ADT enum. I use &lt;code&gt;Option&lt;/code&gt; here for simplicity.&lt;/p&gt;

&lt;p&gt;The third option is to destructure using &lt;code&gt;match&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;make_a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;make_b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make B"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;make_c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or by "stuttering" an &lt;code&gt;if let&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make B"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://play.rust-lang.org/?gist=c0f017dc5a6d6e71b7c2feaae00c9ac0" rel="noopener noreferrer"&gt;playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the same example using a refutable let:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make B"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to make C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is actually implementable using &lt;code&gt;macro_rules&lt;/code&gt; macros, though not without some difficulty. &lt;a href="https://play.rust-lang.org/?gist=1a50e5a509b310d3981db2e7b12fa453" rel="noopener noreferrer"&gt;playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;The point of a refutable let is that you have some destructuring to do, and you want to handle the case where you cannot destructure by diverging from the function.&lt;/p&gt;

&lt;p&gt;The simple desugar of &lt;code&gt;let...else&lt;/code&gt; is the following transformation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;PAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXPR&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;BLOCK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;EXPR&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PAT&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;BLOCK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;BLOCK: !&lt;/code&gt; is &lt;a href="https://github.com/rust-lang/rust/issues/23416" rel="noopener noreferrer"&gt;type ascription&lt;/a&gt;. The ascribed &lt;code&gt;!&lt;/code&gt; type makes it such that &lt;code&gt;BLOCK&lt;/code&gt; needs to diverge (this effectively means &lt;code&gt;return&lt;/code&gt;, &lt;code&gt;break&lt;/code&gt; or &lt;code&gt;continue&lt;/code&gt;). &lt;code&gt;(bindings)&lt;/code&gt; here is a tuple of all assigned bindings in the pattern, so that they can be moved out of the pattern and into the containing scope.&lt;/p&gt;

&lt;p&gt;You can hopefully see that this pattern reduces the required stuttering in using a &lt;code&gt;match&lt;/code&gt; or a &lt;code&gt;let = if let&lt;/code&gt; for this pattern of early-return to handle errors locally. More key, however, is that this &lt;em&gt;enforces the diverge&lt;/em&gt;. If you write a &lt;code&gt;match&lt;/code&gt; or &lt;code&gt;let = if let&lt;/code&gt; or &lt;code&gt;unwrap_or_else&lt;/code&gt; or anything other than a &lt;code&gt;?&lt;/code&gt;, then the error handling branch could instead be a default value branch. Requiring the diverge at a language level increases the guarantees that a reader has when reading the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems and alternate syntaxes
&lt;/h2&gt;

&lt;p&gt;Consider parsing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;quux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Option 1:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nf"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;quux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Option 2:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;quux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second &lt;em&gt;is&lt;/em&gt; actually a vailid parse option if &lt;code&gt;baz()&lt;/code&gt; is of type &lt;code&gt;()&lt;/code&gt;. &lt;code&gt;if COND { () }&lt;/code&gt; is valid in expr position and has type &lt;code&gt;()&lt;/code&gt;. &lt;a href="https://play.rust-lang.org/?gist=b7f691eec516d6f1bc893bebc184d3ca" rel="noopener noreferrer"&gt;playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, this ambiguity means that &lt;code&gt;if PAT = EXPR else&lt;/code&gt; is not a possible unambiguous syntax; there is a reason &lt;code&gt;else&lt;/code&gt; isn't in the follow set for &lt;code&gt;expr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Other proposed syntaxes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;PAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXPR&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;BLOCK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suffers from the same ambiguity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;PAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXPR&lt;/span&gt; &lt;span class="n"&gt;BLOCK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not ambiguous, but suffers from overloading &lt;code&gt;if let&lt;/code&gt;, which doesn't put bindings into the scope that contains it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;PAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXPR&lt;/span&gt; &lt;span class="n"&gt;BLOCK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unambiguous, but requires a new keyword. Keyword possibilities include &lt;code&gt;unless&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recently
&lt;/h2&gt;

&lt;p&gt;Two RFCs recently popped up that relate to this are &lt;a href="https://github.com/rust-lang/rfcs/pull/2221" rel="noopener noreferrer"&gt;#2221 Guard Clause Flow Typing&lt;/a&gt; and &lt;a href="https://github.com/rust-lang/rfcs/pull/2260" rel="noopener noreferrer"&gt;#2260 if- and while- let chains&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The former is looking to get the same functionality from flow typing, and the author seems to not consider &lt;code&gt;let...else&lt;/code&gt; as being a valid "guard". I'll not say more, lest I assert something that isn't true.&lt;/p&gt;

&lt;p&gt;The latter looks to allow chaining &lt;code&gt;if let&lt;/code&gt; to reduce nesting. Though this doesn't seem direclty related, it was mentioned often that having a refutable let would much reduce the necessity of being able to chain &lt;code&gt;if let&lt;/code&gt; together at one block level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking forward to #Rust2018
&lt;/h2&gt;

&lt;p&gt;Unless I've missed some glorious obvious-in-retrospect syntax, &lt;code&gt;if !let PAT = EXPR BLOCK&lt;/code&gt; seems to be the only no-new-keyword-viable solution to the refutable let. Probably, this will end up being the syntax to use, and while maybe alien now, it might become as second nature as &lt;code&gt;if let&lt;/code&gt; is now.&lt;/p&gt;

&lt;p&gt;I can introduce a new RFC proposing using this syntax again, and detailing the problems with the other syntaxes. Maybe there the design can be fully, properly 🚲 :shed: (you pick the emoji :slight_smile:).&lt;/p&gt;

&lt;p&gt;For the rest of Rust in 2018, I agree with much of the other #Rust2018 posts. Rust would probably be best served by a tick/tock cycle, where this year is spent on paying down stabilization debt. Many great features are just around the corner and just need that final push on design/implementation work.&lt;/p&gt;

&lt;p&gt;This is not to say nothing new should happen; WebAssembly work should continue, the RFC machine should continue moving (though we shouldn't tell people to go submit ideas as rapidly as happened before the impl period cutoff). Stabilizing key tools, landing the impl period features, and (re)clarifying stability. Some way to endorse crates as high quality, ready-for-production libraries. Async/await/generators.&lt;/p&gt;

&lt;p&gt;These are all &lt;em&gt;great&lt;/em&gt; things which have been started. Let's move them towards finished together!&lt;/p&gt;

&lt;p&gt;Oh, and my never-gonna-happen breakage whishlist: make all of the &lt;code&gt;Iterator&lt;/code&gt; fn return &lt;code&gt;impl Iterator&lt;/code&gt; instead of concrete types. &lt;code&gt;impl Trait&lt;/code&gt; all of the things.&lt;/p&gt;

&lt;p&gt;UPDATE to above: u/QuietMisdreavus &lt;a href="https://www.reddit.com/r/rust/comments/7plf8z/examining_rfc_1303_and_rust2018/dsj5lnc/" rel="noopener noreferrer"&gt;pointed out the flaw with this&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is actually a loss of information in many cases. Several of the &lt;code&gt;Iterator&lt;/code&gt; wrappers also conditionally implement &lt;code&gt;DoubleEndedIterator&lt;/code&gt;, &lt;code&gt;ExactSizeIterator&lt;/code&gt;, &lt;code&gt;FusedIterator&lt;/code&gt;, etc, based on their contained type. As far as i know, there's no way to represent that in &lt;code&gt;impl Trait&lt;/code&gt; syntax.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having realized the error of my ways, this is no longer a choice I would make.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>rust2018</category>
    </item>
  </channel>
</rss>
