<?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: Dave</title>
    <description>The latest articles on DEV Community by Dave (@xphoniex).</description>
    <link>https://dev.to/xphoniex</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%2F132198%2Fcfa1b8d2-a7fd-47dd-bf67-0bc0e2c739da.jpeg</url>
      <title>DEV Community: Dave</title>
      <link>https://dev.to/xphoniex</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xphoniex"/>
    <language>en</language>
    <item>
      <title>How to call C code from Rust</title>
      <dc:creator>Dave</dc:creator>
      <pubDate>Thu, 28 Oct 2021 14:05:47 +0000</pubDate>
      <link>https://dev.to/xphoniex/how-to-call-c-code-from-rust-56do</link>
      <guid>https://dev.to/xphoniex/how-to-call-c-code-from-rust-56do</guid>
      <description>&lt;p&gt;Calling C code from Rust falls under FFI (Foreign Function Interface) and is unsafe by nature, as it's crossing Rust boundary and all the checks that comes with it.&lt;/p&gt;

&lt;p&gt;The syntax itself is pretty simple, so create a project and:&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="c"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&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;print_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&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="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;"[rust] start"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&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 are defining an external function which uses C ABI convention - which has got to do with the way stack and registers are arranged, when making a call to another function.&lt;/p&gt;

&lt;p&gt;And for our C library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/num.c&lt;/span&gt;
&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;print_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[  c ] num is %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&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 if we &lt;code&gt;cargo run&lt;/code&gt; here, we'd get &lt;code&gt;main.rs:8: undefined reference to print_num&lt;/code&gt;, meaning compiler is not finding our C function so we need to link the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;# in root of project &lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;cc &lt;span class="nt"&gt;-c&lt;/span&gt; src/num.c
&lt;span class="nv"&gt;$ &lt;/span&gt;cc &lt;span class="nt"&gt;-shared&lt;/span&gt; num.o &lt;span class="nt"&gt;-o&lt;/span&gt; libnum.so
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First &lt;code&gt;cc&lt;/code&gt; would generate &lt;code&gt;lib.o&lt;/code&gt; but &lt;code&gt;rustc&lt;/code&gt; needs a shared obejct, which is generated from that and starts its name with &lt;code&gt;lib&lt;/code&gt;. Now we can link it to our Rust code (omit the &lt;code&gt;lib&lt;/code&gt; at start):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rustc &lt;span class="nt"&gt;-l&lt;/span&gt; num &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; src/main.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which looks for &lt;code&gt;(lib)num.so&lt;/code&gt; in current &lt;code&gt;.&lt;/code&gt; path. This should compile and give you the &lt;code&gt;main&lt;/code&gt; binary, which can't be executed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./main
./main: error &lt;span class="k"&gt;while &lt;/span&gt;loading shared libraries: libnum.so: cannot open shared object file: No such file or directory

&lt;span class="nv"&gt;$ &lt;/span&gt;ldd main
    …
    libnum.so &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because you've used a dynamic library, and &lt;code&gt;ldd&lt;/code&gt; can't find it, you can't run your binary. You can either install &lt;code&gt;libnum.so&lt;/code&gt; in appropriate path or use a static library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ar rcs libnum.a num.o
&lt;span class="nv"&gt;$ &lt;/span&gt;rustc &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;static&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;num &lt;span class="nt"&gt;-L&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; src/main.rs  
&lt;span class="nv"&gt;$ &lt;/span&gt;./main
&lt;span class="o"&gt;[&lt;/span&gt;rust] start
&lt;span class="o"&gt;[&lt;/span&gt;  c &lt;span class="o"&gt;]&lt;/span&gt; num is 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect! Let's simplify our workflow, create &lt;code&gt;build.rs&lt;/code&gt; in root of project:&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;main&lt;/span&gt;&lt;span class="p"&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:rustc-link-search=."&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:rustc-link-lib=static=num"&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 now we can use &lt;code&gt;cargo run&lt;/code&gt; and &lt;code&gt;cargo build&lt;/code&gt; the usual way. We can also declare the name of library where it's being used so instead of &lt;code&gt;println!("cargo:rustc-link-lib=static=num");&lt;/code&gt; in &lt;code&gt;build.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="c"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="nd"&gt;#[link(name&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"num"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;kind&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"static"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&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;print_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&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;which links &lt;code&gt;libnum.a&lt;/code&gt; and if we remove the &lt;code&gt;kind&lt;/code&gt; part defaults to dynamic versin &lt;code&gt;libnum.so&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally if you're not interested in handling the compilation of library files yourself, there's &lt;code&gt;cc&lt;/code&gt; crate which takes care of that for you:&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="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;Cargo.toml&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="nn"&gt;[build-dependencies]&lt;/span&gt;
&lt;span class="py"&gt;cc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your &lt;code&gt;build.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="c"&gt;// build.rs&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Build&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="nf"&gt;.file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/num.c"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"anything"&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 that's all!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>c</category>
      <category>ffi</category>
    </item>
    <item>
      <title>Adding our own custom statement to Rust language</title>
      <dc:creator>Dave</dc:creator>
      <pubDate>Fri, 30 Jul 2021 14:16:50 +0000</pubDate>
      <link>https://dev.to/xphoniex/adding-our-own-custom-statement-to-rust-language-30lc</link>
      <guid>https://dev.to/xphoniex/adding-our-own-custom-statement-to-rust-language-30lc</guid>
      <description>&lt;p&gt;I wanted to learn more about Rust internals and decided why not add my own custom statement and see how it goes.&lt;/p&gt;

&lt;p&gt;Without knowing much about either the code base or compilers in general, I was able to add my statement. Buckle up, this gonna be interesting!&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;Goal is to add the &lt;code&gt;unless cond { block }&lt;/code&gt; statement, which only executes the block when &lt;code&gt;cond&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; met:&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;num_is_odd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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="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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&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;1&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;unless&lt;/span&gt; &lt;span class="nf"&gt;num_is_odd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;print!&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="n"&gt;num&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;// expected output:&lt;/span&gt;
&lt;span class="c"&gt;// 2 4 6 8 ⏎&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;You need to clone the &lt;code&gt;rust-lang/rust&lt;/code&gt; repository and setup everything it needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/rust-lang/rust.git
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;rust
&lt;span class="nv"&gt;$ &lt;/span&gt;./x.py build &lt;span class="nt"&gt;-i&lt;/span&gt; library/std &lt;span class="c"&gt;# this builds the compiler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should take about 30 minutes, so get comfortable!&lt;/p&gt;

&lt;h2&gt;
  
  
  Start investigating
&lt;/h2&gt;

&lt;p&gt;Once I had everything setup, meaning I could compile my own compiler, I started looking for keyword &lt;code&gt;Stmt&lt;/code&gt; in the project.&lt;/p&gt;

&lt;p&gt;The interesting file containing &lt;code&gt;Stmt&lt;/code&gt; is at &lt;code&gt;compiler/rustc_ast/src/ast.rs&lt;/code&gt; which is the module responsible for building the &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;abstract syntax tree (AST)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After parsing the source code files, Rust creates the AST because it's easier to work with at further steps.&lt;/p&gt;

&lt;p&gt;The file has an interesting &lt;code&gt;enum&lt;/code&gt; containing expressions:&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;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ExprKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="err"&gt;.&lt;/span&gt;
      &lt;span class="err"&gt;.&lt;/span&gt;
      &lt;span class="c"&gt;/// A binary operation (e.g., `a + b`, `a * b`).&lt;/span&gt;
      &lt;span class="nf"&gt;Binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BinOp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&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;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="c"&gt;/// A unary operation (e.g., `!x`, `*x`).&lt;/span&gt;
      &lt;span class="nf"&gt;Unary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnOp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&lt;/span&gt;&lt;span class="o"&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="err"&gt;.&lt;/span&gt;
      &lt;span class="c"&gt;/// An `if` block, with an optional `else` block.&lt;/span&gt;
      &lt;span class="c"&gt;///&lt;/span&gt;
      &lt;span class="c"&gt;/// `if expr { block } else { expr }`&lt;/span&gt;
      &lt;span class="nf"&gt;If&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&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;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Block&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;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&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="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating &lt;code&gt;Unless&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;unless&lt;/code&gt; has the same logic as an &lt;code&gt;if&lt;/code&gt; statement so we're going to model after that. Right under &lt;code&gt;If&lt;/code&gt; we're going to place:&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="c"&gt;/// An `unless` block, with an optional `else` block.&lt;/span&gt;
      &lt;span class="c"&gt;///&lt;/span&gt;
      &lt;span class="c"&gt;/// `unless expr { block } else { expr }`&lt;/span&gt;
      &lt;span class="nf"&gt;Unless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&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;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Block&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;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&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 can do without the optional expression but we chose to keep it. Save the file and try to compile, don't worry it will error out and won't take that much time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./x.py build &lt;span class="nt"&gt;-i&lt;/span&gt; library/std

error[E0004]: non-exhaustive patterns: &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
    &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_ast/src/ast.rs:1192:15
     |
1192 |           match self.kind &lt;span class="o"&gt;{&lt;/span&gt;
     |                 ^^^^^^^^^ pattern &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
...
1265 | / pub enum ExprKind &lt;span class="o"&gt;{&lt;/span&gt;
1266 | |     /// A &lt;span class="sb"&gt;`&lt;/span&gt;box x&lt;span class="sb"&gt;`&lt;/span&gt; expression.
1267 | |     Box&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
1268 | |     /// An array &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;a, b, c, d]&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
...    |
1313 | |     Unless&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;, P&amp;lt;Block&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
     | |     &lt;span class="nt"&gt;------&lt;/span&gt; not covered
...    |
1411 | |     Err,
1412 | | &lt;span class="o"&gt;}&lt;/span&gt;
     | |_- &lt;span class="sb"&gt;`&lt;/span&gt;ast::ExprKind&lt;span class="sb"&gt;`&lt;/span&gt; defined here
     |
     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt;: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
     &lt;span class="o"&gt;=&lt;/span&gt; note: the matched value is of &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;ast::ExprKind&lt;span class="sb"&gt;`&lt;/span&gt;

error[E0004]: non-exhaustive patterns: &lt;span class="sb"&gt;`&lt;/span&gt;&amp;amp;mut Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
    &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_ast/src/mut_visit.rs:1204:11
     |
1204 |       match kind &lt;span class="o"&gt;{&lt;/span&gt;
     |             ^^^^ pattern &lt;span class="sb"&gt;`&lt;/span&gt;&amp;amp;mut Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
     |
    ::: compiler/rustc_ast/src/ast.rs:1265:1
     |
1265 | / pub enum ExprKind &lt;span class="o"&gt;{&lt;/span&gt;
1266 | |     /// A &lt;span class="sb"&gt;`&lt;/span&gt;box x&lt;span class="sb"&gt;`&lt;/span&gt; expression.
1267 | |     Box&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
1268 | |     /// An array &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;a, b, c, d]&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
...    |
1313 | |     Unless&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;, P&amp;lt;Block&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
     | |     &lt;span class="nt"&gt;------&lt;/span&gt; not covered
...    |
1411 | |     Err,
1412 | | &lt;span class="o"&gt;}&lt;/span&gt;
     | |_- &lt;span class="sb"&gt;`&lt;/span&gt;ast::ExprKind&lt;span class="sb"&gt;`&lt;/span&gt; defined here
     |
     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt;: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
     &lt;span class="o"&gt;=&lt;/span&gt; note: the matched value is of &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&amp;amp;mut ast::ExprKind&lt;span class="sb"&gt;`&lt;/span&gt;

error[E0004]: non-exhaustive patterns: &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
    &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_ast/src/visit.rs:738:11
     |
738  |       match expression.kind &lt;span class="o"&gt;{&lt;/span&gt;
     |             ^^^^^^^^^^^^^^^ pattern &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
     |
    ::: compiler/rustc_ast/src/ast.rs:1265:1
     |
1265 | / pub enum ExprKind &lt;span class="o"&gt;{&lt;/span&gt;
1266 | |     /// A &lt;span class="sb"&gt;`&lt;/span&gt;box x&lt;span class="sb"&gt;`&lt;/span&gt; expression.
1267 | |     Box&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
1268 | |     /// An array &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;a, b, c, d]&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
...    |
1313 | |     Unless&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;, P&amp;lt;Block&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
     | |     &lt;span class="nt"&gt;------&lt;/span&gt; not covered
...    |
1411 | |     Err,
1412 | | &lt;span class="o"&gt;}&lt;/span&gt;
     | |_- &lt;span class="sb"&gt;`&lt;/span&gt;ast::ExprKind&lt;span class="sb"&gt;`&lt;/span&gt; defined here
     |
     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt;: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
     &lt;span class="o"&gt;=&lt;/span&gt; note: the matched value is of &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;ast::ExprKind&lt;span class="sb"&gt;`&lt;/span&gt;

error: aborting due to 3 previous errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we added a new &lt;code&gt;Enum&lt;/code&gt;, we need to fill in our type in places matching against that, those 3 files mentioned in errors:&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;compiler/rustc_ast/src/ast.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;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;precedence&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="n"&gt;ExprPrecedence&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="py"&gt;.kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="err"&gt;.&lt;/span&gt;
              &lt;span class="py"&gt;.
              ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;If&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;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;ExprPrecedence&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;If&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Unless&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;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;ExprPrecedence&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;If&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="err"&gt;.&lt;/span&gt;
              &lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;compiler/rustc_ast/src/visit.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;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;walk_expr&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;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Visitor&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;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&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;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expression&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="n"&gt;Expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;walk_list!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;visit_attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="py"&gt;.attrs&lt;/span&gt;&lt;span class="nf"&gt;.iter&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;expression&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
        &lt;span class="py"&gt;.
        ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;If&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;head_expression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;if_block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;optional_else&lt;/span&gt;&lt;span class="p"&gt;)&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;visitor&lt;/span&gt;&lt;span class="nf"&gt;.visit_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head_expression&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="nf"&gt;.visit_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;if_block&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nd"&gt;walk_list!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;visit_expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optional_else&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Unless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;head_expression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;unless_block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;optional_unless&lt;/span&gt;&lt;span class="p"&gt;)&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;visitor&lt;/span&gt;&lt;span class="nf"&gt;.visit_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head_expression&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="nf"&gt;.visit_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unless_block&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nd"&gt;walk_list!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;visit_expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optional_unless&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;compiler/rustc_ast/src/mut_visit.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;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;noop_visit_expr&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;MutVisitor&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;Expr&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&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;vis&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;T&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;match&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
        &lt;span class="py"&gt;.
        ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;If&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;)&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;vis&lt;/span&gt;&lt;span class="nf"&gt;.visit_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;vis&lt;/span&gt;&lt;span class="nf"&gt;.visit_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;visit_opt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;vis&lt;/span&gt;&lt;span class="nf"&gt;.visit_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Unless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;)&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;vis&lt;/span&gt;&lt;span class="nf"&gt;.visit_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;vis&lt;/span&gt;&lt;span class="nf"&gt;.visit_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;visit_opt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;vis&lt;/span&gt;&lt;span class="nf"&gt;.visit_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initially I'd negated the &lt;code&gt;head_expression&lt;/code&gt; and &lt;code&gt;cond&lt;/code&gt;, but I'd get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;error[E0600]: cannot apply unary operator &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; to &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&amp;amp;mut P&amp;lt;ast::Expr&amp;gt;&lt;span class="sb"&gt;`&lt;/span&gt;
    &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_ast/src/mut_visit.rs:1250:28
     |
1250 |             vis.visit_expr&lt;span class="o"&gt;(!&lt;/span&gt;cond&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     |                            ^^^^^ cannot apply unary operator &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
     |
     &lt;span class="o"&gt;=&lt;/span&gt; note: an implementation of &lt;span class="sb"&gt;`&lt;/span&gt;std::ops::Not&lt;span class="sb"&gt;`&lt;/span&gt; might be missing &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&amp;amp;mut P&amp;lt;ast::Expr&amp;gt;&lt;span class="sb"&gt;`&lt;/span&gt;

error[E0600]: cannot apply unary operator &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; to &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&amp;amp;P&amp;lt;ast::Expr&amp;gt;&lt;span class="sb"&gt;`&lt;/span&gt;
   &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_ast/src/visit.rs:792:32
    |
792 |             visitor.visit_expr&lt;span class="o"&gt;(!&lt;/span&gt;head_expression&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    |                                ^^^^^^^^^^^^^^^^ cannot apply unary operator &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
    |
    &lt;span class="o"&gt;=&lt;/span&gt; note: an implementation of &lt;span class="sb"&gt;`&lt;/span&gt;std::ops::Not&lt;span class="sb"&gt;`&lt;/span&gt; might be missing &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&amp;amp;P&amp;lt;ast::Expr&amp;gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which means, we have to use &lt;code&gt;std::ops::Not&lt;/code&gt; to achieve this. For now, we proceed without it. All good, let's build the compiler now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./x.py build &lt;span class="nt"&gt;-i&lt;/span&gt; library/std
&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;
error[E0004]: non-exhaustive patterns: &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
    &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_ast_pretty/src/pprust/state.rs:1871:15
     |
1871 |         match expr.kind &lt;span class="o"&gt;{&lt;/span&gt;
     |               ^^^^^^^^^ pattern &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
     |
    ::: /.../rust-lang/rust/compiler/rustc_ast/src/ast.rs:1314:5
     |
1314 |     Unless&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;, P&amp;lt;Block&amp;gt;, Option&amp;lt;P&amp;lt;Expr&amp;gt;&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
     |     &lt;span class="nt"&gt;------&lt;/span&gt; not covered
     |
     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt;: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
     &lt;span class="o"&gt;=&lt;/span&gt; note: the matched value is of &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;ExprKind&lt;span class="sb"&gt;`&lt;/span&gt;

error: aborting due to previous error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We missed that, so in &lt;code&gt;rustc_ast_pretty/src/pprust/state.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;fn&lt;/span&gt; &lt;span class="nf"&gt;print_expr_outer_attr_style&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;expr&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;ast&lt;/span&gt;&lt;span class="p"&gt;::&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;is_inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
        &lt;span class="py"&gt;.
        match&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;.&lt;/span&gt;
            &lt;span class="py"&gt;.
            ast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;If&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;blk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;elseopt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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="nf"&gt;.print_if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elseopt&lt;/span&gt;&lt;span class="nf"&gt;.as_deref&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Unless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;blk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;elseopt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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="nf"&gt;.print_if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elseopt&lt;/span&gt;&lt;span class="nf"&gt;.as_deref&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="err"&gt;.&lt;/span&gt;
            &lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./x.py build &lt;span class="nt"&gt;-i&lt;/span&gt; library/std
&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;
error[E0425]: cannot find value &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;module &lt;span class="sb"&gt;`&lt;/span&gt;kw&lt;span class="sb"&gt;`&lt;/span&gt;
    &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_parse/src/parser/expr.rs:1119:40
     |
1119 |         &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else if &lt;/span&gt;self.eat_keyword&lt;span class="o"&gt;(&lt;/span&gt;kw::Unless&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     |                                        ^^^^^^ not found &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;kw&lt;span class="sb"&gt;`&lt;/span&gt;
     |
&lt;span class="nb"&gt;help&lt;/span&gt;: consider importing one of these items
     |
1    | use crate::parser::ExprKind::Unless&lt;span class="p"&gt;;&lt;/span&gt;
     |
1    | use rustc_ast::ExprKind::Unless&lt;span class="p"&gt;;&lt;/span&gt;
     |

   Compiling rustc_middle v0.0.0 &lt;span class="o"&gt;(&lt;/span&gt;/.../rust-lang/rust/compiler/rustc_middle&lt;span class="o"&gt;)&lt;/span&gt;
error[E0004]: non-exhaustive patterns: &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
    &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; compiler/rustc_ast_lowering/src/expr.rs:29:30
     |
29   |             &lt;span class="nb"&gt;let &lt;/span&gt;kind &lt;span class="o"&gt;=&lt;/span&gt; match e.kind &lt;span class="o"&gt;{&lt;/span&gt;
     |                              ^^^^^^ pattern &lt;span class="sb"&gt;`&lt;/span&gt;Unless&lt;span class="o"&gt;(&lt;/span&gt;_, _, _&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; not covered
     |
    ::: /.../rust-lang/rust/compiler/rustc_ast/src/ast.rs:1314:5
     |
1314 |     Unless&lt;span class="o"&gt;(&lt;/span&gt;P&amp;lt;Expr&amp;gt;, P&amp;lt;Block&amp;gt;, Option&amp;lt;P&amp;lt;Expr&amp;gt;&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;,
     |     &lt;span class="nt"&gt;------&lt;/span&gt; not covered
     |
     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt;: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
     &lt;span class="o"&gt;=&lt;/span&gt; note: the matched value is of &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;rustc_ast::ExprKind&lt;span class="sb"&gt;`&lt;/span&gt;

error: aborting due to previous error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;kw::Unless&lt;/code&gt; doesn't exist, if we follow &lt;code&gt;kw&lt;/code&gt; definition, we reach &lt;code&gt;rustc_span/src/symbol.rs&lt;/code&gt; and there we can add our keyword:&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="n"&gt;If&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="n"&gt;Unless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;             &lt;span class="s"&gt;"unless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Impl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;               &lt;span class="s"&gt;"impl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;rustc_parse/src/parser/expr.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;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_bottom_expr&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PResult&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;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&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="err"&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="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.eat_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;If&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="nf"&gt;.parse_if_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&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="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.eat_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Unless&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="nf"&gt;.parse_if_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
        &lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in &lt;code&gt;compiler/rustc_ast_lowering/src/expr.rs#L115&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="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Unless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;else_opt&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;match&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;scrutinee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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="nf"&gt;.lower_expr_if_let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="py"&gt;.span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scrutinee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;else_opt&lt;/span&gt;&lt;span class="nf"&gt;.as_deref&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Paren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;paren&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;match&lt;/span&gt; &lt;span class="n"&gt;paren&lt;/span&gt;&lt;span class="nf"&gt;.peel_parens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;scrutinee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="c"&gt;// A user has written `if (let Some(x) = foo) {`, we want to avoid&lt;/span&gt;
                            &lt;span class="c"&gt;// confusing them with mentions of nightly features.&lt;/span&gt;
                            &lt;span class="c"&gt;// If this logic is changed, you will also likely need to touch&lt;/span&gt;
                            &lt;span class="c"&gt;// `unused::UnusedParens::check_expr`.&lt;/span&gt;
                            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.if_let_expr_with_parens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&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;paren&lt;/span&gt;&lt;span class="nf"&gt;.peel_parens&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.lower_expr_if_let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="py"&gt;.span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;scrutinee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;else_opt&lt;/span&gt;&lt;span class="nf"&gt;.as_deref&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="mi"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.lower_expr_if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;else_opt&lt;/span&gt;&lt;span class="nf"&gt;.as_deref&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.lower_expr_if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;else_opt&lt;/span&gt;&lt;span class="nf"&gt;.as_deref&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;
  
  
  When do I stop copying?
&lt;/h2&gt;

&lt;p&gt;So far, we only copied whatever &lt;code&gt;If&lt;/code&gt; had for our &lt;code&gt;Unless&lt;/code&gt; type. We have everything we want now to compile the compiler, but wait!&lt;/p&gt;

&lt;p&gt;Before you start another compile and spend a lot of time, you can quickly check the status with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./x.py check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a faster command that is &lt;em&gt;only&lt;/em&gt; going to check whether your code can compile. Don't worry if it errors at &lt;code&gt;src/tools/clippy/clippy_utils/src/sugg.rs&lt;/code&gt;, you're good to go if you reach that far!&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing &lt;code&gt;Unless&lt;/code&gt; logic
&lt;/h2&gt;

&lt;p&gt;Right now, we have &lt;code&gt;unless&lt;/code&gt; as a proxy for &lt;code&gt;if&lt;/code&gt; but that's not what we want. We want our block to be run only when the condition is not met. We already tried with &lt;code&gt;!&lt;/code&gt; above but it told us to use &lt;code&gt;std::ops::Not&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I tried that too, but that's not exactly the type we're looking for. Thank you, compiler!&lt;/p&gt;

&lt;p&gt;Instead we need to modify our parser, because by the time code reaches &lt;code&gt;ast&lt;/code&gt; module, expressions are set and we only have &lt;code&gt;Visit&lt;/code&gt; logic.&lt;/p&gt;

&lt;p&gt;So in &lt;code&gt;rustc_parse/src/parser/expr.rs&lt;/code&gt; change:&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="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.eat_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Unless&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="nf"&gt;.parse_unless_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&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 then:&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="c"&gt;/// Parses an `unless` expression (`unless` token already eaten).&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_unless_expr&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;attrs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AttrVec&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;PResult&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;P&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expr&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;lo&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;.prev_token.span&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;cond&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.parse_cond_expr&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="c"&gt;// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then&lt;/span&gt;
        &lt;span class="c"&gt;// verify that the last statement is either an implicit return (no `;`) or an explicit&lt;/span&gt;
        &lt;span class="c"&gt;// return. This won't catch blocks with an explicit `return`, but that would be caught by&lt;/span&gt;
        &lt;span class="c"&gt;// the dead code lint.&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;thn&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;self&lt;/span&gt;&lt;span class="nf"&gt;.eat_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Else&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;cond&lt;/span&gt;&lt;span class="nf"&gt;.returns&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="nf"&gt;.error_missing_if_cond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="py"&gt;.span&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;attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.parse_outer_attributes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.take_for_recovery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c"&gt;// For recovery.&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;not_block&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;.token&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nn"&gt;token&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;OpenDelim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;token&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Brace&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;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.parse_block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map_err&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;err&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;not_block&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="nf"&gt;.span_label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"this `if` expression has a condition, but no block"&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="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="py"&gt;.kind&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="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&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;right&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="nf"&gt;.help&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"maybe you forgot the right operand of the condition?"&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="n"&gt;err&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;self&lt;/span&gt;&lt;span class="nf"&gt;.error_on_if_block_attrs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&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="n"&gt;block&lt;/span&gt;&lt;span class="py"&gt;.span&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;attrs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;block&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;els&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;self&lt;/span&gt;&lt;span class="nf"&gt;.eat_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Else&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="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.parse_else_expr&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="nb"&gt;None&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;neg_cond&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.mk_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="nf"&gt;.to&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;.prev_token.span&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.mk_unary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;UnOp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Not&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;AttrVec&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="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="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.mk_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="nf"&gt;.to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neg_cond&lt;/span&gt;&lt;span class="py"&gt;.span&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;ExprKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;If&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neg_cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;els&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;attrs&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;Our parser pretty much looks like &lt;code&gt;If&lt;/code&gt;, except we negate the condition using &lt;code&gt;Unary&lt;/code&gt; type, store that in &lt;code&gt;neg_cond&lt;/code&gt; and then create a normal &lt;code&gt;If&lt;/code&gt; block using our new condition.&lt;/p&gt;

&lt;p&gt;Not only is this not a bad practice, but actually encouraged as it narrows down the building blocks in later stages and improvements on one of them would trickle. In our case a new compiler optimization for &lt;code&gt;If&lt;/code&gt; would translate to a better &lt;code&gt;Unless&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiling our goal
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RUST_SRC_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/path-to-source/rust-lang/rust
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RUSTC_DEV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$RUST_SRC_PATH&lt;/span&gt;/build/x86_64-unknown-linux-gnu/stage1/bin/rustc
&lt;span class="nv"&gt;$ $RUSTC_DEV&lt;/span&gt; &lt;span class="nt"&gt;-vV&lt;/span&gt; &lt;span class="c"&gt;# notice the dollar sign&lt;/span&gt;
rustc 1.56.0-dev &lt;span class="c"&gt;# notice -dev here which tells us it's compiled from source&lt;/span&gt;
binary: rustc
commit-hash: unknown
commit-date: unknown
host: x86_64-unknown-linux-gnu
release: 1.56.0-dev
LLVM version: 12.0.1

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;unless.rs
fn num_is_odd&lt;span class="o"&gt;(&lt;/span&gt;n: u32&lt;span class="o"&gt;)&lt;/span&gt; -&amp;gt; bool &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;n % 2 &lt;span class="o"&gt;==&lt;/span&gt; 1
&lt;span class="o"&gt;}&lt;/span&gt;

fn main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;num &lt;span class="k"&gt;in &lt;/span&gt;1..10 &lt;span class="o"&gt;{&lt;/span&gt;
        unless num_is_odd&lt;span class="o"&gt;(&lt;/span&gt;num&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            print!&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"{} "&lt;/span&gt;, num&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="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$ $RUSTC_DEV&lt;/span&gt; unless.rs
&lt;span class="nv"&gt;$ &lt;/span&gt;./unless
2 4 6 8 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Github
&lt;/h2&gt;

&lt;p&gt;You can see the &lt;a href="https://github.com/xphoniex/rust/commit/78c41a46c80394161d4ce8e638312e4866fe0cd5"&gt;commit here&lt;/a&gt; and if you want to try out the whole thing, checkout &lt;a href="https://github.com/xphoniex/rust/tree/add-unless-statement"&gt;&lt;code&gt;add-unless-statement&lt;/code&gt; branch&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>rust</category>
      <category>compiler</category>
      <category>rustdev</category>
    </item>
    <item>
      <title>II. Implementing ICMP in Rust</title>
      <dc:creator>Dave</dc:creator>
      <pubDate>Sun, 18 Jul 2021 15:00:44 +0000</pubDate>
      <link>https://dev.to/xphoniex/ii-implementing-icmp-in-rust-3bk5</link>
      <guid>https://dev.to/xphoniex/ii-implementing-icmp-in-rust-3bk5</guid>
      <description>&lt;p&gt;&lt;em&gt;Make sure to checkout previous part where we talk about IP and ICMP layouts if you haven't already: &lt;a href="https://dev.to/xphoniex/i-implementing-icmp-in-rust-296o"&gt;I. Implementing ICMP in Rust&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. (Cont'd) Implementation in Rust
&lt;/h2&gt;

&lt;p&gt;First thing we need to do is to create a TUN/TAP device that allows us to receive/send raw frames directly. It's a kernel-feature which enables us to have software-defined interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn main() {
    let mut nic = tun_tap::Iface::without_packet_info("tun0", tun_tap::Mode::Tun).unwrap();
    let mut buf = [0u8; 1500];
    loop {
        let nbytes = nic.recv(&amp;amp;mut buf[..]).unwrap();

        match etherparse::Ipv4HeaderSlice::from_slice(&amp;amp;buf[..nbytes]) {
            Ok(iph) =&amp;gt; {
                let src = iph.source_addr();
                let dst = iph.destination_addr();
                let proto = iph.protocol();

                if proto != 1 {
                    continue;
                }

                let data_buf = &amp;amp;buf[iph.slice().len()..nbytes];

                if let Some(mut c) = Connection::start(
                    iph,
                    data_buf,
                ).unwrap() {
                    println!("connection c started!");
                    c.respond(&amp;amp;mut nic).unwrap();
                    println!("responded to {} packet from {} ", proto, src);
                }
            }
            Err(e) =&amp;gt; {
                eprintln!("ignoring weird packet {:?}", e);
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our &lt;code&gt;main&lt;/code&gt;, we create our device and a &lt;code&gt;buf&lt;/code&gt; and keep reading from it in a loop. Whenever we find an &lt;code&gt;IPv4&lt;/code&gt; header, &lt;code&gt;etherparse&lt;/code&gt; already takes care of the parsing for us and gives us the &lt;code&gt;iph&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;For example, if you've read the previous installment you should know the &lt;code&gt;proto == 1&lt;/code&gt; for ICMP echo and echo reply packets, thus we skip everything else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                if proto != 1 {
                    continue;
                }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally we read the actual &lt;code&gt;data&lt;/code&gt;, which is everything except header bytes and create a connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                let data_buf = &amp;amp;buf[iph.slice().len()..nbytes];

                if let Some(mut c) = Connection::start(
                    iph,
                    data_buf,
                ).unwrap() {
                    println!("connection c started!");
                    c.respond(&amp;amp;mut nic).unwrap();
                    println!("responded to {} packet from {} ", proto, src);
                }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we're not dealing with a stateful protocol like TCP, we can get away with not using &lt;code&gt;Connection&lt;/code&gt; but for sake of conforming to John's TCP implementation, I use one as well.&lt;/p&gt;

&lt;p&gt;Still you need &lt;code&gt;Connection&lt;/code&gt; to distinguish multiple streams and detect out of order sequence numbers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub struct Connection {
    ip: etherparse::Ipv4Header,
    icmp_id: u16,
    seq_no: u16,
}

impl Connection {
    pub fn start(iph: etherparse::Ipv4HeaderSlice, data: &amp;amp;[u8]) -&amp;gt; std::io::Result&amp;lt;Option&amp;lt;Self&amp;gt;&amp;gt; {
        let mut c = Connection {
            ip: etherparse::Ipv4Header::new(
                0,
                64,
                etherparse::IpTrafficClass::Icmp,
                [
                    iph.destination()[0],
                    iph.destination()[1],
                    iph.destination()[2],
                    iph.destination()[3],
                ],
                [
                    iph.source()[0],
                    iph.source()[1],
                    iph.source()[2],
                    iph.source()[3],
                ],
            ),
            icmp_id: u16::from_be_bytes(data[4..6].try_into().unwrap()),
            seq_no: u16::from_be_bytes(data[6..8].try_into().unwrap()),
        };

        Ok(Some(c))
    }

    pub fn respond(&amp;amp;mut self, nic: &amp;amp;mut tun_tap::Iface,) -&amp;gt; std::io::Result&amp;lt;usize&amp;gt; {
        let mut buf = [0u8; 1500];

        self.ip.set_payload_len(84-20 as usize);

        use std::io::Write;
        let mut unwritten = &amp;amp;mut buf[..];
        self.ip.write(&amp;amp;mut unwritten);

        let mut icmp_reply = [0u8; 64];
        // type
        icmp_reply[0] = ICMP_ECHO_REPLY;
        // code, always 0
        icmp_reply[1] = 0; 

        // checksum = 2 &amp;amp; 3, empty for now
        icmp_reply[2] = 0x00; 
        icmp_reply[3] = 0x00;

        // id = 4 &amp;amp; 5
        icmp_reply[4] = ((self.icmp_id &amp;gt;&amp;gt; 8) &amp;amp; 0xff) as u8; 
        icmp_reply[5] = (self.icmp_id &amp;amp; 0xff) as u8;

        // seq_no = 6 &amp;amp; 7
        icmp_reply[6] = ((self.seq_no &amp;gt;&amp;gt; 8) &amp;amp; 0xff) as u8; 
        icmp_reply[7] = (self.seq_no &amp;amp; 0xff) as u8;

        unwritten.write(&amp;amp;icmp_reply);

        let unwritten = unwritten.len();
        nic.send(&amp;amp;buf[..buf.len() - unwritten])?;

        Ok(0)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create our &lt;code&gt;Connection&lt;/code&gt; type and implement two methods: &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;respond&lt;/code&gt;. All &lt;code&gt;start&lt;/code&gt; does is create an IP header with the source and destination swapped.&lt;/p&gt;

&lt;p&gt;Then in &lt;code&gt;respond&lt;/code&gt;, we start writing the actual ICMP packet. We start by setting IP's size to 84, which if you remember from last part was the &lt;em&gt;Total Length&lt;/em&gt; of our IP packet. 20 bytes is the IP header so we deduce that and prepare a 64 bytes buffer to hold our ICMP.&lt;/p&gt;

&lt;p&gt;All we do here is change the ICMP type to &lt;code&gt;0&lt;/code&gt; which is &lt;em&gt;echo reply&lt;/em&gt;, leave checksum as &lt;code&gt;0&lt;/code&gt;, and copy in the &lt;code&gt;identifier&lt;/code&gt; and &lt;code&gt;sequence number&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Remember ICMP layout from previous part?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;08          Type             0th byte       = Echo message
00          Code             1st byte                    
492b        Checksum         2-3rd byte
5514        Identifier       4-5th byte     = id 21780 (in raw capture)
0001        Sequence Number  6-7th byte     = seq 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Testing the implementation
&lt;/h2&gt;

&lt;p&gt;We're ready to run our program.&lt;/p&gt;

&lt;p&gt;Once it creates the device, we can &lt;code&gt;ping&lt;/code&gt; it with any IP address associated with it and get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ping 192.168.0.3

PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=1626615676072 ms
wrong data byte #16 should be 0x10 but was 0x0
#16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#48 0 0 0 0 0 0 0 0
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=1626615677081 ms
wrong data byte #16 should be 0x10 but was 0x0
#16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#48 0 0 0 0 0 0 0 0
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=1626615678105 ms
wrong data byte #16 should be 0x10 but was 0x0
#16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#48 0 0 0 0 0 0 0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out it's expecting our byte #16 to be &lt;code&gt;0x10&lt;/code&gt;, our #17 to be &lt;code&gt;0x11&lt;/code&gt; and so on. So we add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        for i in 16..64-8 {
            icmp_reply[i+8] = (0x10 + (i - 16)) as u8;
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to our &lt;code&gt;respond&lt;/code&gt; method and try &lt;code&gt;ping&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ping 192.168.0.3

PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=1626615769165 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=1626615770169 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=1626615771193 ms
64 bytes from 192.168.0.3: icmp_seq=4 ttl=64 time=1626615772217 ms
64 bytes from 192.168.0.3: icmp_seq=5 ttl=64 time=1626615773241 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get a working &lt;code&gt;ping&lt;/code&gt; back and forth, only all the &lt;code&gt;times&lt;/code&gt; are &lt;strong&gt;all wrong&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After a lot of head scratches, and double and triple checking the wiki page of IP, ICMP, etc, I finally found the solution on RFC-792 page:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The data received in the echo message must be returned in the echo reply message.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So instead of blindly adding &lt;code&gt;0x10&lt;/code&gt;, &lt;code&gt;0x11&lt;/code&gt; to my packet, I copy the original values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;icmp_reply[8..64].clone_from_slice(&amp;amp;self.data[8..64]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and try once again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ping 192.168.0.3

PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.162 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.214 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.174 ms
64 bytes from 192.168.0.3: icmp_seq=4 ttl=64 time=0.226 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Everything seems to be working, except I don't have the correct checksum. Or any checksum for that mattter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's not showing up in &lt;code&gt;ping&lt;/code&gt; but if you use Wireshark:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fg4di8r7tjhki15zkmsuq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fg4di8r7tjhki15zkmsuq.png" alt="checksum-invalid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following RFCs and Wikis only made me more confused when trying to write the checksum function. I had better luck writing one in Python and translating it to Rust after getting it right:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn calculate_checksum(data: &amp;amp;mut [u8]) {
    let mut f = 0;
    let mut chk: u32 = 0;
    while f + 2 &amp;lt;= data.len() {
        chk += u16::from_le_bytes(data[f..f+2].try_into().unwrap()) as u32;

        f += 2;
    }

    while chk &amp;gt; 0xffff {
        chk = (chk &amp;amp; 0xffff) + (chk &amp;gt;&amp;gt; 2*8);
    }

    let mut chk = chk as u16;

    chk = !chk &amp;amp; 0xffff;

    // endianness
    //chk = chk &amp;gt;&amp;gt; 8 | ((chk &amp;amp; 0xff) &amp;lt;&amp;lt; 8);

    data[3] = (chk &amp;gt;&amp;gt; 8) as u8;
    data[2] = (chk &amp;amp; 0xff) as u8;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.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%2Fxszkel9ss8l91tt970t1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxszkel9ss8l91tt970t1.png" alt="checksum-correct"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And everything seems to be working, finally.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Github
&lt;/h2&gt;

&lt;p&gt;The code is available on my Github &lt;a href="https://github.com/xphoniex/icmp-rust" rel="noopener noreferrer"&gt;xphoniex/icmp-rust&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>icmp</category>
      <category>rust</category>
      <category>networkprogramming</category>
    </item>
    <item>
      <title>I. Implementing ICMP in Rust</title>
      <dc:creator>Dave</dc:creator>
      <pubDate>Sun, 18 Jul 2021 14:38:01 +0000</pubDate>
      <link>https://dev.to/xphoniex/i-implementing-icmp-in-rust-296o</link>
      <guid>https://dev.to/xphoniex/i-implementing-icmp-in-rust-296o</guid>
      <description>&lt;p&gt;This post is inspired by &lt;a href="https://twitter.com/jonhoo" rel="noopener noreferrer"&gt;Jon Gjengset&lt;/a&gt; series titled &lt;a href="https://www.youtube.com/watch?v=bzja9fQWzdA" rel="noopener noreferrer"&gt;"Implementing TCP in Rust"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This should be an interesting read for anyone who wants to get a better understanding of networking protocols down to bits and doesn't mind diving into RFCs.&lt;/p&gt;

&lt;p&gt;So what is ICMP anyway? It's the protocol that makes &lt;code&gt;ping&lt;/code&gt; and &lt;code&gt;traceroute&lt;/code&gt; possible. If you're a gamer or ever joined an online call, then you know how important those ping/latency numbers are.&lt;/p&gt;

&lt;p&gt;Unlike TCP/UDP, which are Layer 4 protocols in OSI Model, ICMP actually belongs to Layer 3 which is the same level as IP, itself the &lt;strong&gt;main&lt;/strong&gt; protocol of the Internet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Few5c1p4s7frl9ecfp90m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Few5c1p4s7frl9ecfp90m.png" alt="osi-model"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. IP Packet
&lt;/h2&gt;

&lt;p&gt;First, I'll show you what an IPv4 (&lt;a href="https://datatracker.ietf.org/doc/html/rfc791#section-3.1" rel="noopener noreferrer"&gt;RFC-791&lt;/a&gt;) header looks like, remember all your connections on the internet start with one of these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  Example Internet Datagram Header
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To capture a raw IP frame, ping &lt;code&gt;localhost&lt;/code&gt; in another terminal and listen with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tcpdump -i lo -p icmp -X
15:23:33.885666 IP localhost &amp;gt; localhost: ICMP echo request, id 21780, seq 1, length 64
    0x0000:  4500 0054 9210 4000 4001 aa96 7f00 0001  E..T..@.@.......
    0x0010:  7f00 0001 0800 492b 5514 0001 2d08 f460  ......I+U...-..`
    0x0020:  0000 0000 6c83 0d00 0000 0000 1011 1213  ....l...........
    0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
    0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&amp;amp;'()*+,-./0123
    0x0050:  3435 3637                                4567
15:23:33.885695 IP localhost &amp;gt; localhost: ICMP echo reply, id 21780, seq 1, length 64
    0x0000:  4500 0054 9211 0000 4001 ea95 7f00 0001  E..T....@.......
    0x0010:  7f00 0001 0000 512b 5514 0001 2d08 f460  ......Q+U...-..`
    0x0020:  0000 0000 6c83 0d00 0000 0000 1011 1213  ....l...........
    0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
    0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&amp;amp;'()*+,-./0123
    0x0050:  3435 3637                                4567

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

&lt;/div&gt;



&lt;p&gt;Let's start with the first IP and decode the header — the first 20 bytes of &lt;code&gt;4500 0054 9210 4000 4001 aa96 7f00 0001 7f00 0001 ...&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;▼
4           Version                 = IPv4 version
5           IHL                     = 20 bytes
00          ToS
0054        Total Length            = 84 bytes
9210        Identification
4           Flags
000         Fragment Offset
40          Time to Live            = 64 TTL
01          Protocol                = ICMP
aa96        Header Checksum
7f00 0001   Source IP Address       = 127.0.0.1
7f00 0001   Destination IP Address  = 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. ICMP Packet
&lt;/h2&gt;

&lt;p&gt;From &lt;a href="https://datatracker.ietf.org/doc/html/rfc792" rel="noopener noreferrer"&gt;RFC-792&lt;/a&gt; we can see the layout of &lt;em&gt;Echo or Echo reply message&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Identifier          |        Sequence Number        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Data ...
+-+-+-+-+-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And by replacing &lt;code&gt;data&lt;/code&gt; bytes, the remaining bytes after the header, we get our ICMP header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;08          Type                    = Echo message
00          Code                     
492b        Checksum
5514        Identifier              = id 21780 (in raw capture)
0001        Sequence Number         = seq 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you compare this ICMP packet with the one from second IP frame, two fields have changed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Type&lt;/code&gt; which has become &lt;code&gt;00&lt;/code&gt; or Echo &lt;strong&gt;reply&lt;/strong&gt; message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Checksum&lt;/code&gt;, naturally because content has changed&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  3. Implementation in Rust
&lt;/h2&gt;

&lt;p&gt;Now that we know what an ICMP packet looks like, we are ready to implement it in Rust. &lt;/p&gt;

&lt;p&gt;Unlike TCP/UDP, we have no concept of ports here and only use IPs to find our path. (Now you understand why ping has no port?).&lt;/p&gt;

&lt;p&gt;Furthermore, astute reader may have noticed that the only thing that changes in the ICMP echo reply is the &lt;code&gt;Type&lt;/code&gt; which goes from &lt;code&gt;08&lt;/code&gt; to &lt;code&gt;00&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We've got all we need. Check out:&lt;/strong&gt; &lt;a href="https://dev.to/xphoniex/ii-implementing-icmp-in-rust-3bk5"&gt;II. Implementing ICMP in Rust&lt;/a&gt;&lt;/p&gt;

</description>
      <category>icmp</category>
      <category>rust</category>
      <category>networkprogramming</category>
    </item>
    <item>
      <title>How to create a Kubernetes cluster on Alpine Linux</title>
      <dc:creator>Dave</dc:creator>
      <pubDate>Tue, 19 May 2020 16:16:26 +0000</pubDate>
      <link>https://dev.to/xphoniex/how-to-create-a-kubernetes-cluster-on-alpine-linux-kcg</link>
      <guid>https://dev.to/xphoniex/how-to-create-a-kubernetes-cluster-on-alpine-linux-kcg</guid>
      <description>&lt;p&gt;&lt;em&gt;this post will help you understand kubeadm, kubelet flags, and nuances of alpine&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Creating a production-ready K8s cluster is almost a breeze nowadays on most cloud platforms so I was curious to see how hard it'd be to create a cluster from scratch on my own set of VMs... turns out not very hard.&lt;/p&gt;

&lt;p&gt;To accomplish this, you can either do it &lt;a href="https://github.com/kelseyhightower/kubernetes-the-hard-way"&gt;the hard way&lt;/a&gt; or use some automation. You're presented with two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kubernetes-sigs/kubespray"&gt;kubespray&lt;/a&gt; which uses Ansible under the hood&lt;/li&gt;
&lt;li&gt;kubeadm which is the official way to do it, part of k/k, and supported by amazing k8s team of VMWare&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As kubeadm's binary already comes with kubernetes package on Alpine, I decided to go with that option. &lt;/p&gt;

&lt;p&gt;I already had KVM installed on my machine and had an Alpine Linux 3.9 VM ready to go, so you need to pause here and provision your VMs if you haven't already before you proceed.&lt;/p&gt;

&lt;p&gt;Once you have your VM, you need to add community and testing repositories so you can get the needed binaries for Kubernetes and Docker packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing/" &amp;gt;&amp;gt; /etc/apk/repositories
# echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community/" &amp;gt;&amp;gt; /etc/apk/repositories
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;then install required packages with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# apk add kubernetes@testing
# apk add docker@community
# apk add cni-plugins@testing
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;at this point when I tried to start my docker service, I'd get an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# service docker start
supervise-daemon: --pidfile must be specified
failed to start Docker Daemon
ERROR: docker failed to start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is apparently a bug on part of &lt;code&gt;supervise-daemon&lt;/code&gt; and I created a merge request for this issue to &lt;a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/7681"&gt;alpine/aports&lt;/a&gt; but apparently this issue has been solved in newer versions of Alpine. In case you still run into this, you need to edit your &lt;code&gt;/etc/init.d/docker&lt;/code&gt; file, add &lt;code&gt;pidfile="/run/docker/docker.pid"&lt;/code&gt; and inside &lt;code&gt;start_pre&lt;/code&gt; block add &lt;code&gt;mkdir -p /run/docker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you can duplicate your VM in KVM, and name the new one &lt;code&gt;worker-1&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# hostname worker-1
# echo "worker-1" &amp;gt; /etc/hostname
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;make sure to do the same steps for master node but with the name &lt;code&gt;master-1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You're ready to create your control-plane on master node, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# kubeadm init --apiserver-advertise-address=[ Master Node's IP Here ] --kubernetes-version=1.17.5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Kubeadm runs in phases, and it was crashing when reaching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running another terminal (using SSH) and restarting the kubelet service fixed this issue. Turns out, Kubeadm starts the kubelet service first and then writes the config files it needs to start properly. On other OSes such as Ubuntu, Systemd &lt;em&gt;-the OS init system-&lt;/em&gt; takes care of restarting the crashing service until the config files are there and kubelet can be run.&lt;/p&gt;

&lt;p&gt;Alpine on the other hand, uses OpenRC as its init system which doesn't restart on crash loops. For that Gentoo community has introduced &lt;code&gt;supervise-daemon&lt;/code&gt; which is experimental at the moment. To make this possible on Alpine, we fixed this issue directly on kubeadm with this &lt;a href="https://github.com/kubernetes/kubernetes/pull/90892"&gt;PR&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once &lt;code&gt;kubeadm&lt;/code&gt; runs it course, it gives you two notes, one is the location of your kube config file. This is the file that &lt;code&gt;kubectl&lt;/code&gt; uses to authenticate to API server on every call. You need to copy this file on any machines that needs to interact with cluster using &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another one is a join statement like below, which is how you'll add your worker nodes to the cluster. First add your CNI on master node and then join from worker node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# on master node
master-1 # kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

# on worker node
worker-1 # kubeadm join 192.168.122.139:6443 --token hcexp0.qiaxub64z17up9rn --discovery-token-ca-cert-hash sha256:05653259a076769faa952024249faa9c9457b4abf265914ba58f002f08834006
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note:&lt;br&gt;
Your join command should succeed now but when I initially tried this command, my kubelet service would again fail to start because config files were missing and, surprisingly, restarting kubelet service didn't help this time. (Shocking, I know!)&lt;/p&gt;

&lt;p&gt;After some investigation I realized another mismatch between Systemd and OpenRC, &lt;code&gt;--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf&lt;/code&gt; was missing from &lt;code&gt;/etc/conf.d/kubelet&lt;/code&gt; and adding it fixed this but didn't specify CNI and my pods would get Docker IPs. You guessed it right, another kubelet argument missing. (See the full changes that were necessary &lt;a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/7678/diffs"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;At this point you can deploy your workloads, and if you come from Ubuntu world one subtle difference is that you need to make sure you apps are compatible with musl as opposed to glibc. For example if you're deploying Go static binaries, make sure you're compiling with &lt;code&gt;CGO_ENABLED=0&lt;/code&gt; to create a statically-linked binary or if you're deploying node apps, make sure your &lt;code&gt;npm install&lt;/code&gt; is being run inside an Alpine container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's it!&lt;/strong&gt; Feel free to reach out to me if you need help with your k8s clusters. &lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>alpine</category>
      <category>kubeadm</category>
    </item>
  </channel>
</rss>
