<?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: Kevin K.</title>
    <description>The latest articles on DEV Community by Kevin K. (@kbknapp).</description>
    <link>https://dev.to/kbknapp</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%2F550918%2Fa64f7673-4fc8-4748-a0c0-79574625ba80.jpeg</url>
      <title>DEV Community: Kevin K.</title>
      <link>https://dev.to/kbknapp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kbknapp"/>
    <language>en</language>
    <item>
      <title>Configuration Tetris</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Sat, 03 Feb 2024 15:28:50 +0000</pubDate>
      <link>https://dev.to/kbknapp/configuration-tetris-npk</link>
      <guid>https://dev.to/kbknapp/configuration-tetris-npk</guid>
      <description>&lt;p&gt;Recently &lt;a href="https://www.makeworld.space/2024/02/no_prefill_config.html"&gt;this post titled, "Don't prefill Your config files"&lt;/a&gt; was making its round of the various news aggregators I follow. This topic closely tracks the last few articles I wrote about building command line applications and passing around an &lt;a href="https://kbknapp.dev/cli-structure-01/#context-structs"&gt;"Application Context."&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I still plan on writing an article about loading configuration specifically for applications written in Rust, but at least for now I wanted to jot down some thoughts and best practices in a language agnostic manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Play Field
&lt;/h2&gt;

&lt;p&gt;At it's most basic form the runtime context will contain only application defaults, i.e. the application isn't configurable at all.&lt;/p&gt;

&lt;p&gt;There are a multitude of places an application could pull it's configuration from, not all applications support all methods. But if we look at the most common options, we'd see something like this for an application with six (6) configurable options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfyzj1946ebt5nzeavit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfyzj1946ebt5nzeavit.png" alt="Image description" width="733" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
In the image above the "filled in" (hash checked) boxes are "values" provided.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A runtime context for a configurable option will &lt;em&gt;always&lt;/em&gt; have a value, even if it's just an application default and that default is "no value" as expressed in whatever language happens to be used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;p&gt;Notice the order of the Y axis is important. Higher rows will override values in lower rows.&lt;/p&gt;

&lt;p&gt;The lower the row the more "implicit" the value is considered. Likewise, the higher the row the more "explicit" the value is considered because it is increasingly likely to have been set by the user directly and for this particular run of the program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Falling Blocks
&lt;/h2&gt;

&lt;p&gt;If we were to "fill in" various cells indicating that the user or system administrator changed some default to a new value we may end up with something that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fke48xv3ighan3cjybhaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fke48xv3ighan3cjybhaj.png" alt="Image description" width="553" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how the final "Runtime Context" contains the "value" of the highest (most explicit) value.&lt;/p&gt;

&lt;p&gt;That's really all there is to it. More explicit values should override implicit values.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Using a Trait in Derive CLIs</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Wed, 27 Dec 2023 19:31:24 +0000</pubDate>
      <link>https://dev.to/kbknapp/cli-structure-in-rust-05-1d11</link>
      <guid>https://dev.to/kbknapp/cli-structure-in-rust-05-1d11</guid>
      <description>&lt;p&gt;In Part 5 we update our trait to work with Derive based CLIs and discuss the tradeoffs in doing so.&lt;/p&gt;

&lt;h2&gt;
  
  
  Previously On...
&lt;/h2&gt;

&lt;p&gt;First a quick re-cap on how we used a trait in the Build method so we can compare.&lt;/p&gt;

&lt;h3&gt;
  
  
  Builder Trait Revisited
&lt;/h3&gt;

&lt;p&gt;In the Builder method we defined a trait that enforced updating a context struct, performing some action with only that context struct, and then calling the next subcommand, if any.&lt;/p&gt;

&lt;p&gt;A reminder about what our trait looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_args&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;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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="n"&gt;next_cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_args&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="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;None&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 then implemented this trait on Zero Sized Type dummy structs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;Bustup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// impl here...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We had a helper method implemented on the trait object itself that would do the walking and enforcing of &lt;code&gt;update_ctx&lt;/code&gt;-&amp;gt;&lt;code&gt;run&lt;/code&gt;-&amp;gt;&lt;code&gt;next_cmd&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;walk_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&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;.next_cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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="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;Finally, we kicked off this process in &lt;code&gt;main&lt;/code&gt; by creating a Trait Object out of top level dummy struct. Because we used ZSTs, creating a &lt;code&gt;Box&amp;lt;dyn Cmd&amp;gt;&lt;/code&gt; did not actually need to heap allocate anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&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;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&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;args&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;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Back to present day
&lt;/h2&gt;

&lt;p&gt;Now that we're using a Derive based method we have a few issues if we were to try and port that trait directly as is to our current code.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLI Value Structs
&lt;/h3&gt;

&lt;p&gt;We are no longer using dummy structs and no longer passing around a &lt;code&gt;clap::ArgMatches&lt;/code&gt; as the CLI values.&lt;/p&gt;

&lt;p&gt;If we tried to use ZST structs and instead of &lt;code&gt;clap::ArgMatches&lt;/code&gt; pass in our CLI structs we run into not being able to define the type of our CLI struct since they're all distinct types.&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;trait&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;--- What goes here?&lt;/span&gt;
        &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we &lt;em&gt;actually want&lt;/em&gt; to go from our CLI struct to the context struct in that method, it seems perfectly reasonable to &lt;em&gt;just use our CLI struct&lt;/em&gt; instead of a ZST dummy struct.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Source of Truth in &lt;code&gt;run&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Deciding against a ZST dummy struct also has the consequence of now we have access to our CLI struct &lt;em&gt;and&lt;/em&gt; the context struct during &lt;code&gt;run&lt;/code&gt; which can break our "single source of truth rule."&lt;/p&gt;

&lt;p&gt;There is no good answer this issue, and just like in Builder method we "just live with" the possibility of "stringly-typed" bugs or other oddities of the &lt;code&gt;ArgMatches&lt;/code&gt; API; this is something we can live with.&lt;/p&gt;

&lt;p&gt;For starters, we take self by shared reference (&lt;code&gt;&amp;amp;self&lt;/code&gt;) which keeps us from being able to easily mutate anything and encourages us to use the &lt;code&gt;Ctx&lt;/code&gt; struct if we needd to mutate a field such as for normalization or validation.&lt;/p&gt;

&lt;p&gt;Additionally, I've just lived with allowing the CLI struct to be the source of truth for any values that meet &lt;em&gt;all&lt;/em&gt; of the following rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No normalization is required for this CLI value (e.g. no need to deconflict or check multiple CLI value fields to determine what the user "really wanted")&lt;/li&gt;
&lt;li&gt;This CLI value has no complex environment variable equivalents (&lt;code&gt;clap&lt;/code&gt; can handle basic environment variables which is the reason for for "complex" qualifier)&lt;/li&gt;
&lt;li&gt;The CLI value has no configuration file equivalents&lt;/li&gt;
&lt;li&gt;THe CLI argument is not global or shared between other commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If all of these rules hold, I allow myself to use the CLI struct's values, otherwise use the Context struct.&lt;/p&gt;

&lt;p&gt;In practice this rarely an issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;Box&amp;lt;dyn Cmd&amp;gt;&lt;/code&gt; will now allocate...a lot
&lt;/h3&gt;

&lt;p&gt;Because we got rid of ZST dummy structs and instead decided to use the CLI value structs, that means creating a &lt;code&gt;Box&amp;lt;dyn Cmd&amp;gt;&lt;/code&gt; out of them will allocate. These structs can also end up being quite large depending on the number of CLI arguments your program contains.&lt;/p&gt;

&lt;p&gt;Luckily, all is not lost. It turns out we can just as easily use a &lt;code&gt;&amp;amp;dyn Cmd&lt;/code&gt; as well since our CLI struct is created at program startup and kept around until after the end of the final &lt;code&gt;run&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;This has the slight downside that you must keep the CLI struct around in memory, but I have yet to find a program where that is a problem as even though I said these structs can be quite large, it's still typically in well below a page size (4k) even for enormous CLIs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
See [Appendix A][appendix_a] for a variation on this trait that I've used in the past where I wanted to be able to drop the CLI structs but allow the program to continue to run.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Switching from &lt;code&gt;Box&amp;lt;dyn Cmd&amp;gt;&lt;/code&gt; to a &lt;code&gt;&amp;amp;dyn Cmd&lt;/code&gt; is trivial in our case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;//                          👇 new&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next_cmd&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;None&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 impl signature for &lt;code&gt;Cmd&lt;/code&gt; changes slightly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&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 finally our &lt;code&gt;main&lt;/code&gt; function changes ever so slightly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.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="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&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;ctx&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;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Alright, so we've adjusted our trait objects and our trait, but what about our &lt;code&gt;Ctx&lt;/code&gt;? Since we are allowing ourselves to use the CLI structs as a partial context only for fields that are trivial, that leaves us with only the more complex, or global values that we need to move into our &lt;code&gt;Ctx&lt;/code&gt;. For &lt;code&gt;bustup&lt;/code&gt; that happens to only be the &lt;code&gt;toolchain&lt;/code&gt; field used globally by all &lt;code&gt;bustup target ...&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/context.rs&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;target_toolchain&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="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Our First Hard Decision
&lt;/h3&gt;

&lt;p&gt;What about &lt;code&gt;bustup update&lt;/code&gt;? It takes a &lt;code&gt;[toolchain]&lt;/code&gt; argument, but it meets all the rules for us to just use the CLI struct instead of the context, right? Should we have just named that context field a more general &lt;code&gt;toolchain&lt;/code&gt; and shared it?&lt;/p&gt;

&lt;p&gt;My answer is, no.&lt;/p&gt;

&lt;p&gt;Although those two arguments share a name, they may in the future not share anything else. I prefer to qualify fields with their path, &lt;em&gt;or&lt;/em&gt; use child contexts.&lt;/p&gt;

&lt;h4&gt;
  
  
  Child Contexts
&lt;/h4&gt;

&lt;p&gt;Just a quick aside, our toy example &lt;code&gt;bustup&lt;/code&gt; isn't complex enough to really demo this, but in a real CLI it's not a bad idea to instead of qualifying all &lt;code&gt;Ctx&lt;/code&gt; fields with their path, instead to use actual sub-contexts. For example something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ctx_target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TargetCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ctx_update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UpdateCtx&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PRO TIP&lt;/strong&gt;&lt;br&gt;
You an also use things like &lt;a href="https://docs.rs/once_cell/latest/once_cell/unsync/struct.Lazy.html"&gt;&lt;code&gt;Lazy&lt;/code&gt;&lt;/a&gt; initialized fields because due to how CLI command work, you typically only walk down a single command path, e.g. &lt;code&gt;bustup update&lt;/code&gt; won't ever require anything out of &lt;code&gt;bustup target ...&lt;/code&gt;. Of course, there are some minor exceptions depending on what you're doing and how things are structured, but in general this is the case.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Enums and Subcommands
&lt;/h2&gt;

&lt;p&gt;Because of how &lt;code&gt;clap&lt;/code&gt;'s Derive methods parse the subcommands we get back an enum representing one possible subcommand.&lt;/p&gt;

&lt;p&gt;And then when we want to implement &lt;code&gt;Cmd::next_cmd&lt;/code&gt; we have to do this tedious dance to match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;

&lt;span class="cd"&gt;/// not rustup&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Parser)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Bustup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[command(subcommand)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BustupCmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Subcommand)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;BustupCmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupUpdate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;target&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTarget&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Bustup&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;next_cmd&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;BustupCmd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;BustupCmd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this works, it's tedious to update all the various levels we could have subcommands and also must be updated any time we add or remove a subcommand!&lt;/p&gt;

&lt;p&gt;If you don't mind taking on another dependency it turns out we can just implement &lt;code&gt;Cmd&lt;/code&gt; directly on our enum in a low drama way!&lt;/p&gt;

&lt;p&gt;We'll use the &lt;a href="https://crates.io/crates/enum_delegate"&gt;&lt;code&gt;enum_delegate&lt;/code&gt;&lt;/a&gt; crate to reduce some boiler plate for us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo add enum_delegate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we change our code slightly to register our trait, and utilize it on our &lt;code&gt;BustupCmd&lt;/code&gt; enum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;

&lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
&lt;span class="nd"&gt;#[enum_delegate::register]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* .. unchanged */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
&lt;span class="nd"&gt;#[enum_delegate::implement(Cmd)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Subcommand)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;BustupCmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupUpdate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;target&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTarget&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;What does that buy us? Well &lt;em&gt;all&lt;/em&gt; of the variants of &lt;code&gt;BustupCmd&lt;/code&gt; implement &lt;code&gt;Cmd&lt;/code&gt; so we actually just want to delegate directly to them.&lt;/p&gt;

&lt;p&gt;Why that matters is when we call &lt;code&gt;&amp;lt;Bustup as Cmd&amp;gt;::next_cmd&lt;/code&gt; what we really want is to call the that method on our &lt;em&gt;inner&lt;/em&gt; value of whatever variant &lt;code&gt;BustupCmd&lt;/code&gt; happens to currently have.&lt;/p&gt;

&lt;p&gt;Well now that we have some boiler plate free method do that delegation, we just have to return the enum value itself!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Bustup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next_cmd&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cmd&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;Yes, this will call &lt;code&gt;Cmd::update_ctx&lt;/code&gt; and &lt;code&gt;Cmd::run&lt;/code&gt; on the enum itself as well, but since we have default implementation that do nothing it doesn't actually matter.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;only&lt;/em&gt; thing we have to do is write those three lines for each CLI struct that contains subcommands. No more changes even when we add and remove subcommands!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
This IMO is a big improvement over the builder method&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Rest of the Owl
&lt;/h2&gt;

&lt;p&gt;Back to code-dump time! We have all the bits we need to implement our remaining commands and see how it all fits together.&lt;/p&gt;

&lt;p&gt;Starting with &lt;code&gt;bustup update&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/update.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// All else unchanged...&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupUpdate&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"updating toolchain {}{}"&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;.toolchain&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;self&lt;/span&gt;&lt;span class="py"&gt;.force&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;" (forced)"&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="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// All else unchanged...&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTarget&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target_toolchain&lt;/span&gt; &lt;span class="o"&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="py"&gt;.toolchain&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next_cmd&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cmd&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/add.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// All else unchanged...&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTargetAdd&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Adding the {} target to the {} toolchain"&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;.target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target_toolchain&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/list.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// All else unchanged...&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTargetList&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Listing {} targets for the {} toolchain"&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;self&lt;/span&gt;&lt;span class="py"&gt;.installed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"installed"&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="s"&gt;"all"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target_toolchain&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/remove.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// All else unchanged...&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTargetRemove&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Removing the {} target from the {} toolchain"&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;.target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target_toolchain&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it!&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/kbknapp/bustup"&gt;full code&lt;/a&gt; can be found in the repository under the &lt;code&gt;derive&lt;/code&gt; branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;By structuring our code in such a way we can have clean delineations between "setup" and "action" code allowing us to split up code to run at the appropriate point of program execution logically.&lt;/p&gt;

&lt;p&gt;It also helps us to enforce a little bit of rigor in appropriately using our context structs and keeping the "run" code single purpose.&lt;/p&gt;

&lt;p&gt;There will be times when you want to manually "run" one of the commands from within code, and with this type of setup it should be mostly trivial as you only need to ensure the context struct is appropriately populated and then call &lt;code&gt;Cmd::run&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
It's possible to use an associated type for an "output" of the &lt;code&gt;Cmd::run&lt;/code&gt; method if you prefer, for these manual run scenarios. However I've found that it's easier to maintain by just setting a context field if &lt;code&gt;run&lt;/code&gt; methods need to pass data between them which is actually quite rare.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Appendix A: Short Lived CLI Structs
&lt;/h2&gt;

&lt;p&gt;If for some reason we do not want our CLI structs to remain in memory for the duration of the program such as either they take up significant memory or perhaps there is sensitive information that must be cleaned up, we can alter our &lt;code&gt;Cmd&lt;/code&gt; trait slightly to allow dropping.&lt;/p&gt;

&lt;p&gt;In this variation I think of the &lt;code&gt;Cmd&lt;/code&gt; trait as an initializer, and thus I either rename &lt;code&gt;run&lt;/code&gt; -&amp;gt; &lt;code&gt;runner&lt;/code&gt; or remove it altogether.&lt;/p&gt;

&lt;p&gt;Addressing these options in reverse order...&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing &lt;code&gt;run&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In these scenarios your "real" &lt;code&gt;main&lt;/code&gt;/&lt;code&gt;run&lt;/code&gt; will just take the final &lt;code&gt;Ctx&lt;/code&gt; as it's only argument. This option can get tricky though if you have multiple terminal methods that are distinct, e.g. &lt;code&gt;git clone&lt;/code&gt; versus &lt;code&gt;git push&lt;/code&gt;. Passing a &lt;code&gt;Ctx&lt;/code&gt; to some final &lt;code&gt;run&lt;/code&gt; method would probably need to match on some field to figure out what functionality it really needs to execute. Hence this method I typically only use in single purpose daemons where there is esseentially always a single well defined "running" state.&lt;/p&gt;

&lt;p&gt;The code would look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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;next_cmd&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&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;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&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;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
    &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
    &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* .. */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Renaming &lt;code&gt;run&lt;/code&gt; to &lt;code&gt;runner&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In this variation &lt;code&gt;run&lt;/code&gt; is more of an object initializer that returns something that can be &lt;code&gt;run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means I typically make another trait to represent the terminal &lt;code&gt;Run&lt;/code&gt; action that should be performed.&lt;/p&gt;

&lt;p&gt;Depending on the use case you can also just &lt;em&gt;not implement&lt;/em&gt; &lt;code&gt;runner&lt;/code&gt; in any of the commaneds except the terminal one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Runnable&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// 👇 renamed                                👇 new&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Runable&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="nb"&gt;None&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;next_cmd&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;walk_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&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;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Runnable&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;self&lt;/span&gt;&lt;span class="nf"&gt;.update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// 👇 new (return if we have something to run)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;)&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;.runnere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&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;.next_cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&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;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;args&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;runner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&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;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
    &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
    &lt;span class="n"&gt;runner&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;



</description>
      <category>rust</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Derive Based CLIs</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Wed, 27 Dec 2023 19:31:12 +0000</pubDate>
      <link>https://dev.to/kbknapp/cli-structure-in-rust-04-344i</link>
      <guid>https://dev.to/kbknapp/cli-structure-in-rust-04-344i</guid>
      <description>&lt;p&gt;In Part 4 of this series we go back to the beginning and look at Derive based CLIs, and how we can structure our program with the tradeoffs that a Derive based CLI brings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Previously On...
&lt;/h2&gt;

&lt;p&gt;Up until this point we'd been using &lt;code&gt;clap&lt;/code&gt;'s Builder approach to making a CLI and then defining a trait to help with some of the strict enforcement of how we want commands to run.&lt;/p&gt;

&lt;p&gt;Builder CLIs are great in that they're the most flexible and fastest to compile, however they're more verbose to create and use at runtime by a significant margin.&lt;/p&gt;

&lt;p&gt;This can make them more painful to maintain and use throughout a program and can even introduce subtle bugs when converting from the &lt;code&gt;clap::ArgMatches&lt;/code&gt; to your &lt;code&gt;Ctx&lt;/code&gt; structs.&lt;/p&gt;

&lt;p&gt;Now we go back to the beginning and start anew using &lt;code&gt;clap&lt;/code&gt;'s Derive mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going Back in Time
&lt;/h2&gt;

&lt;p&gt;First, let's check out the main (empty) branch of our repository and create a new &lt;code&gt;derive&lt;/code&gt; branch; we'll then add the dependencies we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git switch main
$ git swwitch -c derive
$ cargo add anyhow
$ cargo add clap -F derive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice we have to activate &lt;code&gt;clap&lt;/code&gt;'s &lt;code&gt;derive&lt;/code&gt; feature to enable the derive macros. This is because they pull in additional dependencies such as &lt;code&gt;syn&lt;/code&gt; and &lt;code&gt;quote&lt;/code&gt; and will increase the compile time to some extent.&lt;/p&gt;

&lt;p&gt;Like before, here's a quick code dump to get us started:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
Just like in our Builder example, we're enot attempting to show all the cool things you can do with &lt;code&gt;clap&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Run the program!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now the actual CLI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
I like to break up the commands into individual files, however for a small toy example like this that doesn't normally make sense and adds more noise than necessary. As such I will not be showing files that just contain module definintions or re-exports. Likewise, you're also free to keep everything in a single file if you're following along and wish to do so.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;cmds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Subcommand&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cmds&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="cd"&gt;/// not rustup&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Parser)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Bustup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[command(subcommand)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BustupCmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Subcommand)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;BustupCmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupUpdate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;target&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTarget&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/update.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// update toolchains&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Args)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupUpdate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// toolchain to update&lt;/span&gt;
    &lt;span class="nd"&gt;#[arg(default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;toolchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="cd"&gt;/// forcibly update toolchain&lt;/span&gt;
    &lt;span class="nd"&gt;#[arg(short,&lt;/span&gt; &lt;span class="nd"&gt;long)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;force&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target.rs&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Subcommand&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cd"&gt;/// manage targets&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Args)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTarget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// toolchain to update&lt;/span&gt;
    &lt;span class="nd"&gt;#[arg(short,&lt;/span&gt; &lt;span class="nd"&gt;long,&lt;/span&gt; &lt;span class="nd"&gt;default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;toolchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nd"&gt;#[command(subcommand)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BustupTargetCmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Subcommand)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;BustupTargetCmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;add&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTargetAdd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;list&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTargetList&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTargetRemove&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/add.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// list targets&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Args)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTargetAdd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// target to add&lt;/span&gt;
    &lt;span class="nd"&gt;#[arg(default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/list.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// list targets&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Args)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTargetList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// only list installed targets&lt;/span&gt;
    &lt;span class="nd"&gt;#[arg(short,&lt;/span&gt; &lt;span class="nd"&gt;long)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;installed&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/remove.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// remove a target&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Args)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTargetRemove&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// target to remove&lt;/span&gt;
    &lt;span class="nd"&gt;#[arg(default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the CLI build properly by passing the &lt;code&gt;--help&lt;/code&gt; flag to the various commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run -q -- --help
Not rustup

Usage: bustup [COMMAND]

Commands:
  update  update toolchains
  target  manage targets
  help    Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

$ cargo run -q -- update --help
update toolchains

Usage: bustup update [OPTIONS] [toolchain]

Arguments:
  [toolchain]  toolchain to update

Options:
  -f, --force    Forcibly update
  -h, --help     Print help

$ cargo run -q -- target --help
manage targets

Usage: bustup target [OPTIONS] [COMMAND]

Commands:
  add     add a target
  list    list targets
  remove  remove a target
  help    Print this message or the help of the given subcommand(s)

Options:
  -t, --toolchain &amp;lt;toolchain&amp;gt;  toolchain to use [default: default]
  -h, --help                   Print help

$ cargo run -q -- target list --help
list targets

Usage: bustup target list [OPTIONS]

Options:
  -i, --installed              Only list installed targets
  -t, --toolchain &amp;lt;toolchain&amp;gt;  toolchain to use [default: default]
  -h, --help                   Print help
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if we try to run it, we get a panic due to our &lt;code&gt;todo!()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run
thread 'main' panicked at src/main.rs:6:5:
not yet implemented: implement Bustup!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's commit this as our starting point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git commit -am "starting point"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the Program
&lt;/h2&gt;

&lt;p&gt;So we have the basic CLI structure, and unlike the Builder method we already kind of have the structure we want at least file system/module wise.&lt;/p&gt;

&lt;p&gt;It's also so much easier to just &lt;code&gt;match&lt;/code&gt; our way into the code path we want since we have well defined enums that &lt;em&gt;already appear&lt;/em&gt; to have their own self-contained context.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;&lt;br&gt;
Don't be fooled into believing the CLI structs are context structs!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Naive Matching and no &lt;code&gt;Ctx&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The naive method is to match on a particular subcommand, and dispatch to some &lt;code&gt;run&lt;/code&gt;-like function that takes the CLI struct by reference as context. This is a common approach, but there are downsides. Let's implement this method for a single command &lt;code&gt;bustup update&lt;/code&gt; just so we can contrast it later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/update.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;BustupUpdate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&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="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;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;"updating toolchain...{}"&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;.toolchain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our &lt;code&gt;main.rs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.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="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&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;args&lt;/span&gt;&lt;span class="py"&gt;.cmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;BustupCmd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&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;update&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"implement other subcommands"&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 can see that it works by running the update command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run -- update
updating toolchain...default

$ cargo run -- update footoolchain
updating toolchain...footoolchain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is already way less verbose than the Builder method, and we no longer have to worry about "stringly-typed" bugs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
See the Appendix A to this post about how &lt;code&gt;clap&lt;/code&gt; actually allows removing a few more layers of indirection that we're using in this example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For extremely simple CLIs this can work. However, even simple CLIs can suffer by forgoing proper context structs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A second talk about &lt;code&gt;Ctx&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;It's so tempting to just use our CLI struct as the passed in context like we did above. And for a simple CLI, it'd probably be fine. But we're pretending to build a large and complex CLI.&lt;/p&gt;

&lt;p&gt;The CLI structs we defined are &lt;em&gt;only&lt;/em&gt; convenient CLI structs. &lt;strong&gt;They are not context!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just like how we mentioned previously a &lt;code&gt;--color&lt;/code&gt; and &lt;code&gt;--no-color&lt;/code&gt; flag, in a CLI struct that may look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Parser)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Args&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[arg(long,&lt;/span&gt; &lt;span class="nd"&gt;default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"auto"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;value_enum)]&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ColorChoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nd"&gt;#[arg(long)]&lt;/span&gt;
    &lt;span class="n"&gt;no_color&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="nd"&gt;#[derive(ValueEnum)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ColorChoice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Always&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Never&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;Not only will &lt;em&gt;all&lt;/em&gt; code that wants to determine if it should color something deconflict both &lt;code&gt;Args::color&lt;/code&gt; and &lt;code&gt;Args::no_color&lt;/code&gt;, but remember there are also environment variables and configuration files to handle!&lt;/p&gt;

&lt;p&gt;Since we already went over a run-of-the-mill context struct being threaded through the program we will omit that exercise in the Derive based method because there is zero different between it and the Builder version.&lt;/p&gt;

&lt;p&gt;This get interesting though when we use a context struct and try to use a trait to define some structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Time
&lt;/h2&gt;

&lt;p&gt;In the next post we'll see how to modify our trait that we used in the Builder method for our current Derive method and discuss some more tradeoffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appenix A: Removing More Layers
&lt;/h2&gt;

&lt;p&gt;If we trim our example down to just the absolute essentials for a single &lt;code&gt;bustup target add&lt;/code&gt; command, it would currently look like this (moving everything into a single file for clarity):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// not rustup
#[derive(Parser)]
pub struct Bustup {
    #[command(subcommand)]
    pub cmd: BustupCmd,
}

#[derive(Clone, Subcommand)]
pub enum BustupCmd {
    Target(target::BustupTarget),
}

/// manage targets
#[derive(Clone, Args)]
pub struct BustupTarget {
    /// toolchain to update
    #[arg(short, long, default_value = "default")]
    pub toolchain: String,

    #[command(subcommand)]
    pub cmd: BustupTargetCmd,
}

#[derive(Clone, Subcommand)]
pub enum BustupTargetCmd {
    Add(add::BustupTargetAdd),
}

/// list targets
#[derive(Clone, Args)]
pub struct BustupTargetAdd {
    /// target to add
    #[arg(default_value = "default")]
    pub target: String,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;bustup&lt;/code&gt; itself has no arguments or state, we can actually implement &lt;code&gt;clap::Parser&lt;/code&gt; directly on an enum, and then use struct-variants for our enum which condenses it down even further. This would make the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// not rustup
#[derive(Parser)]
pub enum Bustup {
    #[command(subcommand)]
    Target {
        /// toolchain to update
        #[arg(short, long, default_value = "default")]
        pub toolchain: String,

        /// manage targets
        #[command(subcommand)]
        pub cmd: BustupTargetCmd,
    },
}

#[derive(Subcommand)]
pub enum BustupTargetCmd {
    /// add a target
    Add {
        /// target to add
        #[arg(default_value = "default")]
        pub target: String,
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the latter is far less verbose, I find that it gets cluttered when the CLI is of any reasonable size. But this is purely subjective, and other find the condensed version easier to grok.&lt;/p&gt;

&lt;p&gt;Even if your top level command (i.e. &lt;code&gt;bustup&lt;/code&gt; itself in our example) has actual arguments or state, you're still able to use enum struct-variants to remove a layer of indirection if you wish.&lt;/p&gt;

&lt;p&gt;If you're interested in this style of de-duplication I'd also suggest looking at the &lt;code&gt;clap&lt;/code&gt; documentation for &lt;a href="https://docs.rs/clap/latest/clap/_derive/index.html#flattening-hand-implemented-args-into-a-derived-application"&gt;&lt;code&gt;flatten&lt;/code&gt;&lt;/a&gt; and more generally using the &lt;a href="https://docs.rs/clap/latest/clap/trait.Args.html"&gt;&lt;code&gt;Args&lt;/code&gt;&lt;/a&gt; trait to define structs of common arguments for multiple command structs.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Using a Trait in Builder CLIs</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Wed, 27 Dec 2023 19:30:48 +0000</pubDate>
      <link>https://dev.to/kbknapp/cli-structure-in-rust-03-2182</link>
      <guid>https://dev.to/kbknapp/cli-structure-in-rust-03-2182</guid>
      <description>&lt;p&gt;In Part 3 of this series we define a trait to help control the chaos and enforce some structure on our CLI programs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Previously On...
&lt;/h2&gt;

&lt;p&gt;In Part 2 we saw how using context structs was a better idea, but the method in which we niavely applied it has the potential to lead to pain the larger our CLI program grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traits have entered the chat
&lt;/h2&gt;

&lt;p&gt;We can solve this by using a trait to define the context updating, running, and traversing down the subcommand call stack. I call this &lt;code&gt;Cmd&lt;/code&gt; and it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Cmd&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;next_cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// .. all else unchanged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a lot going on here, so let's break it down.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Cmd::update_ctx&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;First we have a method that is responsible for taking a CLI values struct (in our case &lt;code&gt;clap::ArgMattches&lt;/code&gt;) and normalizing any values into &lt;code&gt;Ctx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By default this does nothing because there may be no context to update.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Cmd::run&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This can be thought of as the entry-point to whatever functionality the command itself does.&lt;/p&gt;

&lt;p&gt;Notice that it only takes a &lt;code&gt;Ctx&lt;/code&gt; as context.&lt;/p&gt;

&lt;p&gt;This is important because it means you can fully test your commands by building a mock &lt;code&gt;Ctx&lt;/code&gt; and don't have to worry about mocking CLIs, etc. It &lt;em&gt;also&lt;/em&gt; means you can use the same backing code for a CLI, a TUI, or a GUI because the code only need a &lt;code&gt;Ctx&lt;/code&gt; to run. It doesn't know anything about CLI values or environments, or config files.&lt;/p&gt;

&lt;p&gt;By default this method also does nothing allowing for intermediate subcommands that have no distinct action.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Cmd::next_cmd&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, we have a method for retrieving the next subcommand to run, if any.&lt;/p&gt;

&lt;p&gt;Like all other methods, it also does nothing by default returning that there are no further subcomands to run.&lt;/p&gt;

&lt;p&gt;The interesting bit about this method is the return when there &lt;em&gt;is&lt;/em&gt; another subcommad to run. It returns a boxed trait object of something else that also implements &lt;code&gt;Cmd&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traversing the call-stack with &lt;code&gt;Cmd&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;So we've added the definition of &lt;code&gt;Cmd&lt;/code&gt;, but there is another bit of magic required to really reap the ergonomic benefits.&lt;/p&gt;

&lt;p&gt;We implement a function on the trait object itself for doing the subcommand traversal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;

&lt;span class="c1"&gt;//  ... all else unchanged&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;walk_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&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;.next_cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This updates the context, runs the action, and if there is another subcommand to call it calls &lt;code&gt;walk_exec&lt;/code&gt; on it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;&lt;br&gt;
Some may smell a whiff of recursion and be wary of any such tactics, however by design subcommands cannot, so any such loop would be an inherent error where a stack overflow would be desirable. Additionally, I have never seen subcommands nested so heavily that an overflown stack would be possible. Even on very poorly designed subcommand-based CLIs the nesting does not go above 5-6 levels which is a far cry away from the &lt;em&gt;hundreds&lt;/em&gt; that would be required to overflow the stack even on platforms like Windows which use small 1MB stacks by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PRO TIP&lt;/strong&gt;&lt;br&gt;
You can add another method on the trait object that allows for simply updating the context all the way down the call-stack without actually executing any of the code. This is super useful in testing where you don't actually want to run the code for real, but you'd like the context to be accurately updated. I usually call this &lt;code&gt;walk_update_ctx&lt;/code&gt; and simply omit the &lt;code&gt;selef.run(..)&lt;/code&gt; call while recursively calling &lt;code&gt;walk_update_ctx&lt;/code&gt; instead of &lt;code&gt;walk_exec&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Our new &lt;code&gt;main&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Ok, so we have all the glue, now we just need to fill in the implementations. Let's start with &lt;code&gt;main&lt;/code&gt; because it contains some interesting notes, here's the entire file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.get_matches&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&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;cmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="nf"&gt;.walk_exec&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;args&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;ctx&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;Notice we create a boxed trait object and then call &lt;code&gt;walk_exec&lt;/code&gt; on it to kick off the entire show.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Box&lt;/code&gt; has a specialization for Zero-Sized Types (ZSTs) that doesn't actually allocate. &lt;code&gt;cmd&lt;/code&gt; however is a pointer to a vtable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice we reference &lt;code&gt;cli::Bustup&lt;/code&gt; so let's take a look at that next.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLI Structs
&lt;/h2&gt;

&lt;p&gt;When using this pattern with &lt;code&gt;clap&lt;/code&gt;'s builder based CLIs I like to create empty Zero Sized structs which I can actually implement the &lt;code&gt;Cmd&lt;/code&gt; trait on.&lt;/p&gt;

&lt;p&gt;This forces me to keep no state except in &lt;code&gt;Ctx&lt;/code&gt;, and allows the neat no-allocation for &lt;code&gt;Box&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I also prefer to strictly name these structs after their path in the CLI hierarchy. For example &lt;code&gt;Bustup&lt;/code&gt; is the top level command, and &lt;code&gt;bustup target add&lt;/code&gt; would end up being named &lt;code&gt;BustupTargetAdd&lt;/code&gt;. This is handy to always know exactly what command you're operating on in code.&lt;/p&gt;

&lt;p&gt;For the top-level command I typically place it in the &lt;code&gt;cli&lt;/code&gt; module, but that isn't strictly necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Bustup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Bustup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;next_cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="nf"&gt;.subcommand&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="s"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nn"&gt;Box&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="nn"&gt;cmds&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupUpdate&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="n"&gt;m&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="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nn"&gt;Box&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="nn"&gt;cmds&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;target&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTarget&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice I don't need to do anything for &lt;code&gt;run&lt;/code&gt; or &lt;code&gt;update_ctx&lt;/code&gt; in our toy example, but adding code to execute at those hooks would be trivial.&lt;/p&gt;

&lt;p&gt;One annoyance of the builder-pattern based CLIs is that we have manually handle dispatching to another subcommand at each level, but this is a minor complaint that could easily be handled by a macro if we so desired.&lt;/p&gt;

&lt;p&gt;Looking over at our &lt;code&gt;update.rs&lt;/code&gt; file next we see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/update.rs&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupUpdate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupUpdate&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.toolchain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.cloned&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.force&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="nf"&gt;.get_flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"force"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;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;"Updating {} toolchain...{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.toolchain&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.force&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;" (forced)"&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="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="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;
  
  
  Intermediate Subcommands
&lt;/h2&gt;

&lt;p&gt;In our toy example &lt;code&gt;bustup target ...&lt;/code&gt; is an interesting example because it's an intermediate layer subcommand that has no functionality of it's own (although it could), and it defines a "global argument" (an argument that is present in all of it's child subcommands).&lt;/p&gt;

&lt;p&gt;So even though we don't have a distinct action to take, we do need to update the context with our global CLI option. We also dispatch to our child subcommands exactly how the top level &lt;code&gt;Bustup&lt;/code&gt; command does.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target.rs&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTarget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTarget&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.toolchain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.cloned&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;next_cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;matches&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="nf"&gt;.subcommand&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="s"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nn"&gt;Box&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="nn"&gt;add&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTargetAdd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;m&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="s"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nn"&gt;Box&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="nn"&gt;list&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTargetList&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;m&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="s"&gt;"remove"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nn"&gt;Box&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="nn"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BustupTargetRemove&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Rest of the Owl
&lt;/h2&gt;

&lt;p&gt;Everything should fairly self-evident at this point, so we'll breeze through the next few files only calling out interesting aspects.&lt;/p&gt;

&lt;p&gt;Just like &lt;code&gt;BustupUpdate&lt;/code&gt; the following are all leaf subcommands and thus do not need to implement &lt;code&gt;Cmd::next_cmd&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/add.rs&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTargetAdd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTargetAdd&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.cloned&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;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;"Adding the {} target to the {} toolchain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.toolchain&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/list.rs&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTargetList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTargetList&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.installed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="nf"&gt;.get_flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"installed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;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;"Listing {} targets for the {} toolchain"&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;ctx&lt;/span&gt;&lt;span class="py"&gt;.installed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"installed"&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="s"&gt;"all"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.toolchain&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target/remove.rs&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BustupTargetRemove&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;BustupTargetRemove&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;update_ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.cloned&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;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;"Removing the {} target from the {} toolchain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.target&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.toolchain&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  One Final Change
&lt;/h2&gt;

&lt;p&gt;If you look at the repository's final code, you'll notice that one other thing I typically change, although it's not at all mandatory is to move the CLI construction into the respective modules instead of being fully contained at &lt;code&gt;src/cli.rs&lt;/code&gt;. I find this lets me better encapsulate shared arguments and keep smaller subsets of the code in my head at any given time. To do this I usually place a &lt;code&gt;fn build() -&amp;gt; clap::Command&lt;/code&gt; function in each module that contains a subcommand. For example, the &lt;code&gt;cli.rs&lt;/code&gt; would then look this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;build&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;Command&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;Command&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="s"&gt;"bustup"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not rustup"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;cmds&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;cmds&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;target&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for example &lt;code&gt;src/cli/cmds/target.rs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/target.rs&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;build&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;Command&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;Command&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="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"manage targets"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nn"&gt;Arg&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="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&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;"toolchain to use"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.default_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;add&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;list&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&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 so on and so forth.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/kbknapp/bustup"&gt;full code&lt;/a&gt; can be found in the repository under the &lt;code&gt;builder&lt;/code&gt; branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary for Builder based CLIs
&lt;/h2&gt;

&lt;p&gt;The Builder Pattern is an older and more verbose way to define CLIs in &lt;code&gt;clap&lt;/code&gt;. When used with this method for structuring your CLIs it has the benefit of being easy to enforce single-source-of-truth &lt;code&gt;run&lt;/code&gt; functions and &lt;code&gt;clap&lt;/code&gt; does a lot of the heavy lifting when it comes to providing our &lt;code&gt;ArgMatches&lt;/code&gt; structs that we can use to update the &lt;code&gt;Ctx&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Time!
&lt;/h2&gt;

&lt;p&gt;That's it for Builder Pattern based CLIs!&lt;/p&gt;

&lt;p&gt;In the next post we'll start back over using &lt;code&gt;clap&lt;/code&gt;'s Derive based approach and see how that changes our trait definitions and concerns.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Builder Based CLIs</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Wed, 27 Dec 2023 19:30:23 +0000</pubDate>
      <link>https://dev.to/kbknapp/cli-structure-in-rust-02-4dco</link>
      <guid>https://dev.to/kbknapp/cli-structure-in-rust-02-4dco</guid>
      <description>&lt;p&gt;In Part 2 we dive into some actual code to see what it would look like to use these patterns for CLIs that utilize the &lt;code&gt;clap&lt;/code&gt; Builder method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Previously On...
&lt;/h2&gt;

&lt;p&gt;Reminder I said, the commands and arguments of our &lt;code&gt;bustup&lt;/code&gt; will only print messages to the terminal (without color...perhaps I'll fully explore &lt;code&gt;Ctx&lt;/code&gt; initialization and well defined output coloring in another post).&lt;/p&gt;

&lt;p&gt;Also another reminder, we don't care about the tool itself here, so forgive the brevity and code dump.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's gooooo
&lt;/h2&gt;

&lt;p&gt;First, some setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo new bustup
$ cd bustup
$ git add .
$ git commit -m "Initial Commit"
$ git switch -c builder
$ cargo add clap anyhow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now the code:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
This post is not attempting to show all the cool things you can do with &lt;code&gt;clap&lt;/code&gt;, or even trying to use any of the developer niceties. That would get in the way of what we're trying to demo, so the code is naturally a little terse to keep the post &lt;del&gt;shorter&lt;/del&gt; bearable.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.get_matches&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Run the program!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now the actual CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;build&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;Command&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;Command&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="s"&gt;"bustup"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not rustup"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nn"&gt;Command&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="s"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"update toolchains"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nn"&gt;Arg&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="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&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;"toolchain to update"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.default_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nn"&gt;Arg&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="s"&gt;"force"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'f'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"force"&lt;/span&gt;&lt;span class="p"&gt;)&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;"Forcibly update"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SetTrue&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="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nn"&gt;Command&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="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"manage targets"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nn"&gt;Arg&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="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&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;"toolchain to use"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.default_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="nf"&gt;.global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nn"&gt;Command&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="s"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"add a target"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nn"&gt;Arg&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="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;)&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;"The target to add"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="nf"&gt;.action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Set&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="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nn"&gt;Command&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="s"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"list targets"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nn"&gt;Arg&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="s"&gt;"installed"&lt;/span&gt;&lt;span class="p"&gt;)&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;"Only list installed targets"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nf"&gt;.long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"installed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nf"&gt;.short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nf"&gt;.action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SetTrue&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="nf"&gt;.subcommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nn"&gt;Command&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="s"&gt;"remove"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"remove a target"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nn"&gt;Arg&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="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;)&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;"The target to remove"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="nf"&gt;.action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ArgAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                &lt;span class="nf"&gt;.default_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"default"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the CLI build properly by passing the &lt;code&gt;--help&lt;/code&gt; flag to the various commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run -q -- --help
Not rustup

Usage: bustup [COMMAND]

Commands:
  update  update toolchains
  target  manage targets
  help    Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

$ cargo run -q -- update --help
update toolchains

Usage: bustup update [OPTIONS] [toolchain]

Arguments:
  [toolchain]  toolchain to update

Options:
  -f, --force    Forcibly update
  -h, --help     Print help

$ cargo run -q -- target --help
manage targets

Usage: bustup target [OPTIONS] [COMMAND]

Commands:
  add     add a target
  list    list targets
  remove  remove a target
  help    Print this message or the help of the given subcommand(s)

Options:
  -t, --toolchain &amp;lt;toolchain&amp;gt;  toolchain to use [default: default]
  -h, --help                   Print help

$ cargo run -q -- target list --help
list targets

Usage: bustup target list [OPTIONS]

Options:
  -i, --installed              Only list installed targets
  -t, --toolchain &amp;lt;toolchain&amp;gt;  toolchain to use [default: default]
  -h, --help                   Print help
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if we try to run it, we get a panic due to our &lt;code&gt;todo!()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run
thread 'main' panicked at src/main.rs:6:5:
not yet implemented: Run the program!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's commit this as our starting point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git commit -am "starting point"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the Program
&lt;/h3&gt;

&lt;p&gt;So we have the basic CLI structure, now how should we structure our program?&lt;/p&gt;

&lt;h4&gt;
  
  
  Naive Matching and no &lt;code&gt;Ctx&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The naive method is to match on a particular subcommand, and dispatch to some &lt;code&gt;run&lt;/code&gt;-like function that takes a &lt;code&gt;clap::ArgMatches&lt;/code&gt; as a context. This is a common approach, but there are downsides. Let's implement this method for a single command &lt;code&gt;bustup update&lt;/code&gt; just so we can contrast it later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
I'm going to omit code examples that only contain things like declaring module structure for brevity. The full code is located in the repository if interested.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/update.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&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;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;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;"updating toolchain...{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"toolchain"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, our &lt;code&gt;main.rs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cmds&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.get_matches&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;args&lt;/span&gt;&lt;span class="nf"&gt;.subcommand&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="s"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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="nn"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&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="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"implement other subcommands"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that it works by running the update command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run -- update
updating toolchain...default

$ cargo run -- update footoolchain
updating toolchain...footoolchain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a perfectly valid approach! For a small number of subcommands, or CLIs with single-layer subcommands this approach is usually fine. However, it can start to go sideways quickly when using multiple layers of configuration or nested subcommand layers, especially when context/run-actions need to happen at each individual layer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding &lt;code&gt;Ctx&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;It's so tempting to just use &lt;code&gt;clap::ArgMatches&lt;/code&gt; as the passed in context like we did above. And for a simple CLI, it'd probably be fine. But we're pretending to build a large and complex CLI.&lt;/p&gt;

&lt;p&gt;Based on everything we learned when talking about &lt;code&gt;Ctx&lt;/code&gt; above, we're already convinced we should be using a Context Struct. And we know initializing and updating one can be a complex process.&lt;/p&gt;

&lt;p&gt;But we're starting small and we won't be adding configuration files or environment variables to complicate things in this post. So let's just create our &lt;code&gt;Ctx&lt;/code&gt; and pass that to &lt;code&gt;update::run&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//                             👇 new&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cmds&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.get_matches&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;args&lt;/span&gt;&lt;span class="nf"&gt;.subcommand&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="s"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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="c1"&gt;// 👇 new&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nn"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;run&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;ctx&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="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"implement other subcommands"&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="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/context.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArgMatches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;toolchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&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;ArgMatches&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;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;toolchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"toolchain"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cli/cmds/update.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 👇 new&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;context&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//         👇 new&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//                                 👇 new&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;"updating toolchain...{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.toolchain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This also works!&lt;/p&gt;

&lt;p&gt;But for more complex CLIs, this will get tedious and error prone as well for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the above code we're creating the &lt;code&gt;Ctx&lt;/code&gt; from scratch which wouldn't be an option with nested subcommands that each need to &lt;em&gt;update&lt;/em&gt; a context&lt;/li&gt;
&lt;li&gt;As we nest subcommands the code to update the context and call the next subcommand is going to become pure boilerplate noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Time
&lt;/h2&gt;

&lt;p&gt;In the next post we'll see how to use traits to perform some magic and enforce structure on what could otherwise become unbridled chaos.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>patterns</category>
    </item>
    <item>
      <title>CLI Contexts</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Wed, 27 Dec 2023 19:29:44 +0000</pubDate>
      <link>https://dev.to/kbknapp/cli-structure-in-rust-01-41hl</link>
      <guid>https://dev.to/kbknapp/cli-structure-in-rust-01-41hl</guid>
      <description>&lt;p&gt;How should one structure their CLI programs? I've seen this question a few times, and over the years I've come up with some patterns that I really like. This post explores the variations of these patterns and trade-offs between them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I recently &lt;a href="https://github.com/clap-rs/clap/discussions/5258"&gt;came across this question&lt;/a&gt; (and &lt;a href="https://github.com/clap-rs/clap/discussions/5258#discussioncomment-7866256"&gt;associated answer&lt;/a&gt;) on the &lt;code&gt;clap&lt;/code&gt; repository. The answer given is a good one. But I wanted to expand with my own findings and practices, which spurred the motivation for this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type of CLI
&lt;/h2&gt;

&lt;p&gt;First things first. We need to know which type of CLI you're building. For these purposes there are two broad categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subcommand based&lt;/li&gt;
&lt;li&gt;Single Command Argument based&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example of "subcommand based" would be &lt;code&gt;cargo&lt;/code&gt;; each function is represented by a distinct "command" that is a child (or grand-child, or great-grand-child, etc.) of the top level command &lt;code&gt;cargo&lt;/code&gt;. i.e:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo build
$ cargo clean
$ cargo new
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas an example of a single command based CLI would be &lt;code&gt;ripgrep&lt;/code&gt;, where the tool has a single command, in this case &lt;code&gt;rg&lt;/code&gt; that is controlled solely by arguments.&lt;/p&gt;

&lt;p&gt;Most often, although not always, subcommand based CLIs each command is a distinct function, and at some level they could have perhaps been distinct tools. For example &lt;code&gt;cargo build&lt;/code&gt; builds the Rust program, whereas &lt;code&gt;cargo clean&lt;/code&gt; cleans all build artifacts. These could probably have been implemented as &lt;code&gt;cargo-build&lt;/code&gt; and &lt;code&gt;cargo-clean&lt;/code&gt; respectively. But because those two commands are closely related in purpose (handling Rust projects) it makes far more sense to combine them into a single &lt;code&gt;cargo&lt;/code&gt; command which has the added benefit of being able to easily share code, cohesion in things like error messages and arguments, and not cluttering the file system with &lt;code&gt;cargo-*&lt;/code&gt; commands, etc.&lt;/p&gt;

&lt;p&gt;Similarly, single command based CLIs often, but not always, have a single function. In Ripgrep's case, that is searching through files. This function can be altered in ways via arguments, but ultimately it's still just searching through files.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;br&gt;
Ripgrep is actually a good example of the "but not always" saying. Technically, Ripgrep can also manage and assist the user with "type definitions" that allow searching exclusively through specific file types. This function is controlled through the &lt;code&gt;--type-*&lt;/code&gt; arguments, which when used add, remove, or list various "type definitions" and thus don't actually do the "sole functionality" of searching through files. These could have been made subcommands, such as &lt;code&gt;rg type [OPTIONS]&lt;/code&gt; however, this set of functionality is minor enough (and the &lt;em&gt;only&lt;/em&gt; other functionality beyond searching files) that making it a subcommand could have detracted away from the primary purpose of searching needlessly. Subcommands can, and do, complicate matters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok, so now we know what kind of CLI we're building, we can start to decide on what pattern to use.&lt;/p&gt;

&lt;p&gt;This post will focus almost exclusively on subcommand based, because it's the most interesting and complicated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;br&gt;
I plan to write a "BONUS POST" that discusses a single-command based pattern for completeness sake if that's the route you're taking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The CLI - bad rustup...bustup
&lt;/h2&gt;

&lt;p&gt;So we're making a subcommand based CLI. The example we'll use is a toy example to keep this already long post manageable since the actual tool itself isn't important here. This tool will mimic a tiny tiny subset of &lt;code&gt;rustup&lt;/code&gt; &lt;em&gt;extremely poorly&lt;/em&gt;...i.e. we're just going to print some messages.&lt;/p&gt;

&lt;p&gt;We'll call this &lt;code&gt;bustup&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;br&gt;
Why  &lt;code&gt;rustup&lt;/code&gt;? Because it implements a pattern that will be useful to explore, and that's using several nested layers deep of subcommands. For example &lt;code&gt;cargo&lt;/code&gt; (and other tools like &lt;code&gt;git&lt;/code&gt;) typically only go one layer deep (i.e. &lt;code&gt;git clone&lt;/code&gt;, &lt;code&gt;cargo update&lt;/code&gt;, etc.) whereas &lt;code&gt;rustup&lt;/code&gt; can go several more layers deep, such as &lt;code&gt;rustup toolchain add ...&lt;/code&gt;. This will be important as the pattern we'll use has additional considerations when nesting more than a layer or two deep.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Parsing Library
&lt;/h3&gt;

&lt;p&gt;We also need to decide on a parsing library. I'm biased towards &lt;a href="https://crates.io/crates/clap"&gt;&lt;code&gt;clap&lt;/code&gt;&lt;/a&gt; so that's what we'll be using. However, this pattern should more or less be applicable to any command line argument parsing library.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;clap&lt;/code&gt; like several other parsing libraries supports two different modes of building a CLI. The so-called "Builder Pattern" and the "derive based" method.&lt;/p&gt;

&lt;p&gt;We'll cover both methods because the pattern used is different in interesting ways for each.&lt;/p&gt;

&lt;p&gt;But this also means we'll have to re-implement &lt;code&gt;bustup&lt;/code&gt; twice using the different methods. Another reason to keep &lt;code&gt;bustup&lt;/code&gt; minimally simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;bustup&lt;/code&gt; Command Structure
&lt;/h2&gt;

&lt;p&gt;Here's what we'll implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bustup update [toolchain] [--force]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bustup target add [--toolchain=&amp;lt;TOOLCHAIN&amp;gt;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bustup target remove [--toolchain=&amp;lt;TOOLCHAIN&amp;gt;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bustup target list [--toolchain=&amp;lt;TOOLCHAIN&amp;gt;] [--installed]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context Structs
&lt;/h2&gt;

&lt;p&gt;Something all (or at the very least &lt;em&gt;most&lt;/em&gt;) CLI applications deal with the idea of a "runtime context."&lt;/p&gt;

&lt;p&gt;When doing an actual action in code, there is normally some defined "context" informing the runtime code on what actions to take and how to take them. For example our &lt;code&gt;bustup update&lt;/code&gt; will need some contextual knowledge about which &lt;code&gt;toolchain&lt;/code&gt; the user wishes to update.&lt;/p&gt;

&lt;p&gt;There are many different ways to store and pass around runtime context. The most common ways are via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The CLI value structs themselves&lt;/li&gt;
&lt;li&gt;Context Structs&lt;/li&gt;
&lt;li&gt;Globals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will omit globals, as it's typically an anti-pattern and frowned upon especially in Rust as these context objects are typically mutable and having global mutable state precludes many multi-threading possibilities and negates many of Rust's safety features.&lt;/p&gt;

&lt;p&gt;That leaves us with the CLI value structs, and context structs.&lt;/p&gt;

&lt;p&gt;As the heading may suggest, Context Structs are what this post will focus on. But before doing so I will mention below in the appropriate sections about CLI value structs; as the types of value structs and how they're used is different depending on the mode of &lt;code&gt;clap&lt;/code&gt; one is using.&lt;/p&gt;

&lt;p&gt;For now, suffice it to say that Context Structs are nearly always a better approach, even though they may seem redundant in some circumstances.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meeting &lt;code&gt;Ctx&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A Context Struct (usually abbreviated &lt;code&gt;Ctx&lt;/code&gt;) is just a local struct containing &lt;em&gt;normalized&lt;/em&gt; values from all configuration sources (whereas CLI value structs typically only get their values from the CLI or perhaps from the environment depending on argument parsing library features).&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;bustup update&lt;/code&gt; example, using the &lt;code&gt;toolchain&lt;/code&gt; as the context we may have a struct similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;toolchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;br&gt;
It's common to prefer borrowing of values in some context structs, especially if the value is only temporary. For instance:&lt;/p&gt;


&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;toolchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But for brevity and simplicity I'm leaving out any such concerns in order to focus on the topic of this post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An important distinction about context structs is that they contain the &lt;em&gt;normalized configuration values&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Source of Truth
&lt;/h3&gt;

&lt;p&gt;The primary benefit of using Context Structs is to provide &lt;em&gt;A Single Source of Truth&lt;/em&gt; to runtime code.&lt;/p&gt;

&lt;p&gt;Although our toy &lt;code&gt;bustup&lt;/code&gt; doesn't use overriding flags, if we pretend it does for the sake of argument real quick let's see what could happen.&lt;/p&gt;

&lt;p&gt;Imagine something like our &lt;code&gt;bustup update&lt;/code&gt; taking a &lt;code&gt;--confirm&lt;/code&gt; flag that says to ask the user for confirmation before downloading and installing any updates, and also a &lt;code&gt;--no-confirm&lt;/code&gt; flag that says &lt;em&gt;not&lt;/em&gt; to ask the use first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;br&gt;
Naively it may seem silly to provide both &lt;code&gt;--confirm&lt;/code&gt; and &lt;code&gt;--no-confirm&lt;/code&gt;, especially if one of those values is the default behavior of the program (for instance if either flag is provided it acts &lt;em&gt;as if&lt;/em&gt; &lt;code&gt;--confirm&lt;/code&gt; was used). However, it's actually a super useful pattern to provide because it allows users to set up custom aliases. For example a user normally does not want to be asked for confirmation, so they set up &lt;code&gt;alias bustup-up='bustup update --no-confirm'&lt;/code&gt;. Now one day, they are on a metered network connection and decide they'd like to confirm before downloading a massive update, so run:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bustup-up --confirm

... this expands to ...

$ bustup update --no-confirm --confirm
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;As it stands, we'd probably start by only passing in the CLI values directly to the &lt;code&gt;run_update&lt;/code&gt; function. This would mean it's the function's responsibility for knowing about and deconflicting both &lt;code&gt;--confirm&lt;/code&gt; and &lt;code&gt;--no-confirm&lt;/code&gt; which is something it should not have to care about. Additionally, if we had other subcommands with similar flags, they &lt;em&gt;too&lt;/em&gt; would have to know about and handle these cases.&lt;/p&gt;

&lt;p&gt;This typically leads to people passing in &lt;em&gt;duplicate&lt;/em&gt; context. e.g. they'd pass in the CLI values raw and a boolean flag of some kind:&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;run_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cli_values&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;Args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confirm&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="cm"&gt;/* .. */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To properly write &lt;code&gt;run_update&lt;/code&gt; now one needs to know the difference between the two locations which contain values for whether or not we should prompt the user for confirmation.&lt;/p&gt;

&lt;p&gt;And that's not all!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Technically&lt;/em&gt;, the CLI values are only a single layer in a delicious cake that is program configuration and on their own make for bad context....&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing &lt;code&gt;Ctx&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Although it's out of scope for this post to fully explore this topic; for completeness sake let's take an ultra-brief look at what it's like to initialize a &lt;code&gt;Ctx&lt;/code&gt; struct.&lt;/p&gt;

&lt;p&gt;Let's pretend we had a program that &lt;em&gt;could&lt;/em&gt; use pretty colors for terminal output. So we have a Context Struct that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If `true` pain the terminal&lt;/span&gt;
    &lt;span class="n"&gt;color&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's further assume our program supports system-wide, user-level, and project-level configuration files, as well as CLI flags and environment variables for controlling settings.&lt;/p&gt;

&lt;p&gt;For something as simple as turning color on or off, the ways to control such a setting could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A default value of &lt;code&gt;Auto&lt;/code&gt;  meaning to check if STDOUT is a TTY or not&lt;/li&gt;
&lt;li&gt;A system-wide config file setting&lt;/li&gt;
&lt;li&gt;A user-level config file setting&lt;/li&gt;
&lt;li&gt;A project level config file setting&lt;/li&gt;
&lt;li&gt;A set of environment variables

&lt;ul&gt;
&lt;li&gt;E.g. could be any of &lt;code&gt;TERM&lt;/code&gt;, &lt;code&gt;NO_COLOR&lt;/code&gt;, or perhaps &lt;code&gt;PROGRAM_COLOR&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A set of CLI flags

&lt;ul&gt;
&lt;li&gt;E.g. &lt;code&gt;--color=...&lt;/code&gt; or &lt;code&gt;--no-color&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This seems like madness! Yet its exactly how a well behaved CLI program should function!&lt;/p&gt;

&lt;p&gt;So a full initialization sequence probably looks something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At program startup do something like &lt;code&gt;Ctx::default()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Load system-wide configuration files, if any (e.g. &lt;code&gt;/etc/...&lt;/code&gt;) perhaps in a
&lt;code&gt;Config&amp;lt;System&amp;gt;&lt;/code&gt; struct

&lt;ul&gt;
&lt;li&gt;Normalize values if needed&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;Ctx&lt;/code&gt; with something like a &lt;code&gt;Config::update_ctx(&amp;amp;mut ctx)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Load user-level configuration files, if any (e.g. &lt;code&gt;~/.config/...&lt;/code&gt;) perhaps
in a &lt;code&gt;Config&amp;lt;User&amp;gt;&lt;/code&gt; struct&lt;/li&gt;
&lt;li&gt;Normalize values if needed&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;Ctx&lt;/code&gt; with something like a &lt;code&gt;Config::update_ctx(&amp;amp;mut ctx)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Load environment variable values, if any

&lt;ul&gt;
&lt;li&gt;This step may be done, or partially done by your CLI parsing library, however things like &lt;code&gt;TERM&lt;/code&gt; or &lt;code&gt;NO_COLOR&lt;/code&gt; which are only loosely related to your &lt;code&gt;--color&lt;/code&gt; and &lt;code&gt;--no-color&lt;/code&gt; flags will probably be handled manually via something like a &lt;code&gt;Ctx::update_from_env&lt;/code&gt; method&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Parse CLI values&lt;/li&gt;
&lt;li&gt;Normalize values if needed&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;Ctx&lt;/code&gt; with something like a &lt;code&gt;Config::update_ctx(&amp;amp;mut ctx)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You now have a fully initialized &lt;code&gt;Ctx&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benefit being any actual functionality in your program no longer needs to worry about &lt;em&gt;all of that&lt;/em&gt; and can just get passed an instance of &lt;code&gt;&amp;amp;Ctx&lt;/code&gt; as an argument check a quick &lt;code&gt;ctx.color&lt;/code&gt; field and trust whatever is written there!&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Time!
&lt;/h2&gt;

&lt;p&gt;In the next post we'll actually dive in using the &lt;code&gt;clap&lt;/code&gt; Builder based method to see what using this pattern looks like in practice.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Generically Bloated</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Mon, 06 Feb 2023 00:17:55 +0000</pubDate>
      <link>https://dev.to/kbknapp/generically-bloated-21mj</link>
      <guid>https://dev.to/kbknapp/generically-bloated-21mj</guid>
      <description>&lt;p&gt;Rust generics are great, but they can bloat the final code, and have negative effects on compile times. This post discusses a "trick" to help fight those effects.&lt;/p&gt;

&lt;p&gt;There exists a decently common pattern to combat these issues given a few preconditions are met. This pattern is used heavily in the standard library and popular crates. &lt;/p&gt;

&lt;p&gt;However, when talking to a colleague recently they were unaware of this pattern (to be fair I wasn't fully aware of this pattern either until just a few years ago). This conversation made me wonder if there are others who also haven't yet seen this method which can have pretty big downstream affects!&lt;/p&gt;

&lt;h1&gt;
  
  
  Prelude
&lt;/h1&gt;

&lt;p&gt;This post only addresses code bloat from generic functions, not generic structs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Basics
&lt;/h1&gt;

&lt;p&gt;Let's start by just showing a basic set of generics in Rust, and why some problems pop up.&lt;/p&gt;

&lt;p&gt;When you use generic parameters in Rust, the compiler will actually generate a copy of your code for each concrete type it finds. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;genric&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// code...&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="nf"&gt;generic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// T = i32&lt;/span&gt;
  &lt;span class="nf"&gt;generic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// T = &amp;amp;'static str&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns into something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;genric_i32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&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="c1"&gt;// code...&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;genric_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// code...&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="nf"&gt;generic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;generic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"foo"&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;While this produces extremely efficient code at runtime, there are a few potential downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;generic&amp;lt;T&amp;gt;()&lt;/code&gt; is of substantial size (in compiled binary form), that code is also duplicated leading to potential "bloat"&lt;/li&gt;
&lt;li&gt;(Although I haven't gone spelunking into the compiler code to know for sure; I believe that) all the generated (roughly duplicate) code must also be compiled and optimized separately! This is a lot more code for &lt;code&gt;rustc&lt;/code&gt; and LLVM to churn through&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;generic&amp;lt;T&amp;gt;()&lt;/code&gt; cannot be fully compiled until the compiler knows all the concrete types that will be used&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Library Authors Beware
&lt;/h1&gt;

&lt;p&gt;These concerns are most applicable to library authors, but can affect binary authors as well when their binary is split into a binary-consuming-an-internal-library.&lt;/p&gt;

&lt;p&gt;Where this shows up is downstream consumers filing issues related to code bloat (it turned out many concrete types were used for &lt;code&gt;T&lt;/code&gt;), or slow compile times due to your library (your library heavily relies on generics that cannot be compiled "earlier" or the compiler is churning through all that extra code).&lt;/p&gt;

&lt;h1&gt;
  
  
  Preconditions
&lt;/h1&gt;

&lt;p&gt;I mentioned earlier that the pattern we're about to discuss isn't a silver bullet and cannot be used in all circumstances. There is an important precondition that need to be met:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;br&gt;
The generic code must have a "preferred type" which usually means the generic&lt;br&gt;
parameter is bounded and that bound represents some kind of type conversion&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This should become more clear as we go along.&lt;/p&gt;

&lt;h1&gt;
  
  
  Immediate Dispatch to the Rescue
&lt;/h1&gt;

&lt;p&gt;The solution is to immediately dispatch to a known type. In hindsight this may seem somewhat obvious, however if it doesn't that's OK! We're about to see this in action!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
This example will be extremely contrived in order to demonstrate the effects&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  In Action
&lt;/h2&gt;

&lt;p&gt;First, lets define a trait that will be used as a generic bound.&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;trait&lt;/span&gt; &lt;span class="n"&gt;Speak&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;speak&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="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we define a generic function that can be used with any type that implements the &lt;code&gt;Speak&lt;/code&gt; trait.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;generic_speak&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;Speak&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;param&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;T&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;"It says: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="nf"&gt;.speak&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could be thought of as our library boundary. Perhaps the library also has some concrete types it uses internally, but that is not a requirement.&lt;/p&gt;

&lt;p&gt;It does not matter if the concrete types are internal, external, or a mix.&lt;/p&gt;

&lt;p&gt;Lets define two concrete types that implement said trait as example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Speak&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Cat&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;speak&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="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"meow"&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Speak&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Dog&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;speak&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="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"woof"&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we use that generic function with both a &lt;code&gt;Cat&lt;/code&gt; and a &lt;code&gt;Dog&lt;/code&gt; struct:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
We're creating a binary because it's easier to demonstrate :)&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;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;let&lt;/span&gt; &lt;span class="n"&gt;whiskers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Cat&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;spot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;generic_speak&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;whiskers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;generic_speak&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;spot&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;If we run it, we get what you probably expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run --quiet
It says: meow
It says: woof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Counting Functions
&lt;/h2&gt;

&lt;p&gt;Lets first back up and prove the claims I made at the beginning, that our generic function actually generates two concrete functions. To see that we can either &lt;a href="https://crates.io/crates/cargo-llvm-lines" rel="noopener noreferrer"&gt;&lt;code&gt;cargo-llvm-lines&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://crates.io/crates/cargo-bloat" rel="noopener noreferrer"&gt;&lt;code&gt;cargo-bloat&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
I use both pretty extensively, so lets compare the output of both just for fun!&lt;/p&gt;
&lt;h3&gt;
  
  
  aside: &lt;code&gt;cargo-llvm-lines&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;First, we'll use &lt;code&gt;cargo-llvm-lines&lt;/code&gt; to see the amount of LLVM IR generated:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
Both tools can generate &lt;em&gt;a lot&lt;/em&gt; of output, so we could be &lt;code&gt;grep&lt;/code&gt;ing it down to&lt;br&gt;
size but I'll make some readability edits instead.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo llvm-lines
Lines               Copies            Function name
-----               ------            -------------
[ .. snip .. ]
    80 (4.9%, 50.3%)   2 (4.9%, 17.1%)  generic_speak
     5 (0.3%, 98.3%)   1 (2.4%, 82.9%)  &amp;lt;Cat as Speak&amp;gt;::speak
     5 (0.3%, 98.6%)   1 (2.4%, 85.4%)  &amp;lt;Dog as Speak&amp;gt;::speak
[ .. snip .. ]

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

&lt;/div&gt;



&lt;p&gt;Notice we do, in fact, have two copies of &lt;code&gt;generic_speak&lt;/code&gt; (as can be seen by the &lt;code&gt;Copies&lt;/code&gt; column) and one implementation function each for the concrete types (e.g. &lt;code&gt;&amp;lt;Cat as Speak&amp;gt;::speak&lt;/code&gt; which is the code from where we did &lt;code&gt;impl&lt;br&gt;
Speak for Cat&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;cargo-bloat&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Contrasting the above with &lt;code&gt;cargo-bloat&lt;/code&gt; which shows the binary size of each function:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;cargo-bloat&lt;/code&gt; by default only shows the largest 99 functions, but our example&lt;br&gt;
is to tiny we tell it show us the largest 999 functions so we can be sure our&lt;br&gt;
functions show up in the output.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo bloat -n 999
Analyzing target/debug/blog_demo

File  .text     Size     Crate Name
[ .. snip .. ]
0.0%   0.1%     193B blog_demo generic_speak
0.0%   0.1%     193B blog_demo generic_speak
0.0%   0.0%      44B blog_demo &amp;lt;Dog as Speak&amp;gt;::speak
0.0%   0.0%      44B blog_demo &amp;lt;Cat as Speak&amp;gt;::speak
[ .. snip .. ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like &lt;code&gt;carog-llvm-lines&lt;/code&gt; we can see that we do, in fact, have two copies of &lt;code&gt;generic_speak&lt;/code&gt; and one implementation function each for the concrete types (e.g. &lt;code&gt;&amp;lt;Cat as Speak&amp;gt;::speak&lt;/code&gt; which is the code from where we did &lt;code&gt;impl Speak for Cat&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
For the rest of the post I'm going to omit the actual trait implementations&lt;br&gt;
(&lt;code&gt;&amp;lt;Dog as Speak&amp;gt;::speak&lt;/code&gt;) for brevity, because those don't change, we still&lt;br&gt;
implement those traits with actual code!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With &lt;code&gt;cargo-bloat&lt;/code&gt; we see that in the final binary both copies of &lt;code&gt;generic_speak&lt;/code&gt; are 193 bytes (for a total of 386 bytes).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
As the name implies I tend to prefer &lt;code&gt;cargo-bloat&lt;/code&gt; when working on bloat&lt;br&gt;
issues, because it looks at the final compiled binary size as opposed to just&lt;br&gt;
the LLVM IR with &lt;code&gt;cargo-llvm-lines&lt;/code&gt;. Although I prefer &lt;code&gt;cargo-llvm-lines&lt;/code&gt;&lt;br&gt;
when working on compile times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Generic Bloat
&lt;/h2&gt;

&lt;p&gt;Although contrived, one thing I like about this example is by pure line count, the &lt;code&gt;generic_speak&lt;/code&gt; function looks like almost no code! But this brings up another great source of bloat (&lt;em&gt;especially&lt;/em&gt; when combined with the issue&lt;br&gt;
described in this post!): macros!&lt;/p&gt;
&lt;h3&gt;
  
  
  aside: macros
&lt;/h3&gt;

&lt;p&gt;Using an LSP expand function in my editor (although similar could be done with something like &lt;a href="https://crates.io/crates/cargo-expand" rel="noopener noreferrer"&gt;&lt;code&gt;cargo-expand&lt;/code&gt;&lt;/a&gt;) we see &lt;code&gt;generic_speak&lt;/code&gt; actually expands to something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
You can't run this directly as it uses private rust internals, but it gives a&lt;br&gt;
good view into the kind things macros expand to&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;generic_speak&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;Speak&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;param&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;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="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Arguments&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new_v1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"It says: "&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ArgumentV1&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="nf"&gt;.speak&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Display&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trying Immediate Dispatch
&lt;/h2&gt;

&lt;p&gt;If we take a step back we see that &lt;code&gt;Speak::speak&lt;/code&gt; just produces a &lt;code&gt;String&lt;/code&gt; and all the code inside &lt;code&gt;generic_speak&lt;/code&gt; really only needs that &lt;code&gt;String&lt;/code&gt; to operate.&lt;/p&gt;

&lt;p&gt;The trick is that we We can add a private internal function that accepts the actual type we &lt;em&gt;actually&lt;/em&gt; needed/wanted (i.e. &lt;code&gt;String&lt;/code&gt; in this case) instead of just sticking with the generic parameter.&lt;/p&gt;

&lt;p&gt;Now &lt;code&gt;generic_speak&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;generic_speak&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;Speak&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;param&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;T&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;generic_speak_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It says: {param}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;generic_speak_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="nf"&gt;.speak&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
The function could be external as well, it doesn't need to be defined within&lt;br&gt;
the outer function scope. Although if it's not used anywhere else it makes&lt;br&gt;
sense to define it within internal scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we re-run &lt;code&gt;cargo-bloat&lt;/code&gt; we now see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo bloat -n 999
Analyzing target/debug/blog_demo

File  .text     Size     Crate Name
[ .. snip .. ]
0.0%   0.1%     160B blog_demo generic_speak::generic_speak_string
0.0%   0.0%      37B blog_demo generic_speak
0.0%   0.0%      37B blog_demo generic_speak
[ .. snip .. ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We still have two concrete implementations of &lt;code&gt;generic_speak&lt;/code&gt; since we still have a generic function, however notice the actual code inside has gone down from 193 bytes to just 37 bytes (essentially enough to dispatch the other function). Now, all our "real code" lives in non-generic (and thus not&lt;br&gt;
duplicated) &lt;code&gt;generic_speak_string&lt;/code&gt; internal function (160 bytes).&lt;/p&gt;

&lt;p&gt;Doing the quick math of our duplicate generic functions + the new internal function we get a total 234 bytes versus the original total of 386 bytes!&lt;/p&gt;

&lt;p&gt;This is just a contrived example, but imagine a real library with multiple generics and actually substantial sized functions!&lt;/p&gt;

&lt;p&gt;Additionally, that inner function (&lt;code&gt;generic_speak_string&lt;/code&gt;) is able to be fully compiled right away since all it's types are fully known.&lt;/p&gt;
&lt;h2&gt;
  
  
  A Note on Inlining and Release Builds
&lt;/h2&gt;

&lt;p&gt;You may have noticed if you compiled the examples in release mode, the functions don't appear at all!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo bloat -n 999 --release | grep speak
$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because the code is pretty trivial and Rust/LLVM are able to inline all the code and optimize this away. However, in a real world library that's not always possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
When using this trick, you may need in some cases tell Rust/LLVM &lt;em&gt;not&lt;/em&gt; to&lt;br&gt;
inline your private wrapped function by using &lt;code&gt;#[inline(never)]&lt;/code&gt; if it turns&lt;br&gt;
out the function is just getting inlined into all the generic functions&lt;br&gt;
again. But that should only be done when you're sure that's the case, and the&lt;br&gt;
additional code bloat is worse than the performance lost by not-inlining.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why not just use a &lt;code&gt;String&lt;/code&gt; as the parameter instead of the generic?
&lt;/h2&gt;

&lt;p&gt;Because this was a contrived example. &lt;/p&gt;

&lt;p&gt;Also there are times you'll do something almost exactly like this purely for ergonomics. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Accepts anything that can be converted to &amp;amp;str cheaply&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;takes_stringish&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;AsRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;str&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;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* code */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sure, we could just take &lt;code&gt;&amp;amp;str&lt;/code&gt; as the parameter, but some types may be cheaply yet not &lt;em&gt;ergonomically&lt;/em&gt; converted to a &lt;code&gt;&amp;amp;str&lt;/code&gt;. Using the generic parameter can give our library a nice ergonomic boost.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Even More Contrived Example
&lt;/h3&gt;

&lt;p&gt;At the risk of making this post too long, to show another example of one where it's less ergonomic to ask the user for exactly what we want.&lt;/p&gt;

&lt;p&gt;Cases often comes up around type generics, e.g. we'd prefer to ask for a &lt;code&gt;impl Iterator&amp;lt;Item = AsRef&amp;lt;str&amp;gt;&amp;gt;&lt;/code&gt; when we're working with roughly a &lt;code&gt;Vec&amp;lt;&amp;amp;str&amp;gt;&lt;/code&gt; internally. Forcing the user to do the conversion isn't very ergonomic.&lt;/p&gt;

&lt;p&gt;Let's do exactly this with our previous code, but instead of &lt;code&gt;AsRef&amp;lt;str&amp;gt;&lt;/code&gt; we'll use our &lt;code&gt;Speak&lt;/code&gt; as the bound.&lt;/p&gt;

&lt;p&gt;If we change our &lt;code&gt;generic_speak&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;generic_speak&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;Speak&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;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Iterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;param&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;"It says: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="nf"&gt;.speak&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HashSet&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;whiskers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;spots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashSet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;spots&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;generic_speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;whiskers&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="nf"&gt;generic_speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spots&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&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;Notice we're taking two totally different collection types, a &lt;code&gt;Vec&amp;lt;Cat&amp;gt;&lt;/code&gt; and &lt;code&gt;HashSet&amp;lt;Dog&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Re-running our example gives what we'd expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run --quiet
It says: meow
It says: meow
It says: woof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;cargo-bloat&lt;/code&gt; now shows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo bloat -n 999
Analyzing target/debug/blog_demo

[ .. snip .. ]
0.0%   0.2%     440B  blog_demo generic_speak
0.0%   0.1%     415B  blog_demo generic_speak
[ .. snip .. ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A total of 855 bytes.&lt;/p&gt;

&lt;p&gt;Since you already know the drill, we can do the inner function dispatch thing (with a caveat listed below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;generic_speak&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;Speak&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;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Iterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;generic_speak_strings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;params&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;"It says: {item}"&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="nf"&gt;generic_speak_strings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To which &lt;code&gt;cargo-bloat&lt;/code&gt; reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo bloat -n 999
nalyzing target/debug/blog_demo

[ .. snip .. ]
0.0%   0.1%     405B  blog_demo generic_speak::generic_speak_strings
0.0%   0.0%      80B  blog_demo generic_speak
0.0%   0.0%      69B  blog_demo generic_speak
0.0%   0.0%      65B  blog_demo generic_speak::{{closure}}
0.0%   0.0%      65B  blog_demo generic_speak::{{closure}}
[ .. snip .. ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though we have these closures, it's still a total of 684 bytes instead of the original total of 855 bytes. Again, in this contrived example it's not that dramatic, but in the real world it is often quite dramatic as the original &lt;code&gt;generic_speak&lt;/code&gt; or later &lt;code&gt;generic_speak_strings&lt;/code&gt; could have quite a lot of code!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
The Caveat! Conversion performance and allocations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I mentioned there is a caveat to the above. We created a whole new &lt;code&gt;Vec&amp;lt;String&amp;gt;&lt;/code&gt; to pass to the inner function which is another allocation and has it's own performance implications. However, perhaps this is a case were an extra allocation like that is acceptable compared to the code bloat and compile times. You'll have to be the judge in your specific case.&lt;/p&gt;

&lt;p&gt;This is also partially only due to the strange contrived API I used for this example as well!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We learned that Rust will duplicate generic functions for all concrete types that use said function, which can cause a decent bit of code duplication and increase compile times. &lt;/p&gt;

&lt;p&gt;By turning our generic function into a small wrapping shim, that immediately dispatches to an internal &lt;em&gt;non-generic&lt;/em&gt; function only the shim gets duplicated while all our "real code" stays as a single logical function.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>crypto</category>
      <category>announcement</category>
      <category>offers</category>
    </item>
    <item>
      <title>Using navi for CLI Cheats</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Sun, 27 Nov 2022 03:00:27 +0000</pubDate>
      <link>https://dev.to/kbknapp/using-navi-for-cli-cheats-945</link>
      <guid>https://dev.to/kbknapp/using-navi-for-cli-cheats-945</guid>
      <description>&lt;p&gt;Diving into &lt;code&gt;navi&lt;/code&gt; as an interactive command builder, and using &lt;code&gt;strace&lt;/code&gt; as a demo for concise cheat sheet!&lt;/p&gt;

&lt;p&gt;In the previous post I spent a short time detailing steps I take to make my command line experience more pleasant and efficient. One of the steps I listed was using the tool &lt;a href="https://github.com/denisidoro/navi" rel="noopener noreferrer"&gt;&lt;code&gt;navi&lt;/code&gt;&lt;/a&gt; to quickly recall&lt;br&gt;
commands.&lt;/p&gt;

&lt;p&gt;This is incredibly helpful for commands that I don't use often, or for variations of commands with specific options that I use less frequently. I find fuzzy searching through my &lt;code&gt;navi&lt;/code&gt; cheats is 100x faster than &lt;code&gt;grep&lt;/code&gt;ping through&lt;br&gt;
Manpages or &lt;code&gt;--help&lt;/code&gt; output. Now, of course there are times where my &lt;code&gt;navi&lt;/code&gt; cheats don't cover something I need and I must fall back to older methods, but then I just update my cheats and go about my day.&lt;/p&gt;

&lt;p&gt;I recently found a new (to me) way to use &lt;code&gt;navi&lt;/code&gt;, as a "command builder" of sorts. It makes sense to use on commands where the flags/options are additive, and not individual commands (which is somewhat of a pet peeve of mine...)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;¯\(°_o)/¯&lt;/p&gt;

&lt;p&gt;I should make a post on CLI UX about why certain CLI patterns are sub-optimal...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Enter &lt;code&gt;strace&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;A good example is &lt;code&gt;strace&lt;/code&gt;, which allows one to display system calls made by particular commands and processes. Several other blog posts have recently mentioned &lt;code&gt;strace&lt;/code&gt;, and it's a tool that has come in hand for me more than a&lt;br&gt;
couple times so in it's honor it'll be the demo today.&lt;/p&gt;

&lt;p&gt;We won't be adding all the options that &lt;code&gt;strace&lt;/code&gt; has, but the ones I find most common to my use cases, which probably covers a pretty vast swath of people as well.&lt;/p&gt;

&lt;p&gt;Our goal is to build a &lt;code&gt;navi&lt;/code&gt; cheat sheet that walks us through building an &lt;code&gt;strace&lt;/code&gt; command with all the options we want to expose.&lt;/p&gt;

&lt;p&gt;This post won't cover all the details of &lt;code&gt;strace&lt;/code&gt; or even what all the options mean, although most of the ones we're adding are pretty self explanatory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(ᕗ ͠° ਊ ͠° )ᕗ&lt;/p&gt;

&lt;p&gt;Like a good CLI should be!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a pretty good summary, see &lt;a href="https://blogs.oracle.com/linux/strace-the-sysadmins-microscope-v2" rel="noopener noreferrer"&gt;"&lt;code&gt;strace&lt;/code&gt; The Sysadmins&lt;br&gt;
Microscope"&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;code&gt;navi&lt;/code&gt; Overview
&lt;/h1&gt;

&lt;p&gt;As mentioned in my previous post, I bind &lt;code&gt;navi&lt;/code&gt; to &lt;code&gt;&amp;lt;CTRL&amp;gt;-n&lt;/code&gt; in my terminal, using the following ZSH function in my &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

_call_navi&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;selected
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nv"&gt;selected&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;navi &lt;span class="nt"&gt;--print&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/Projects/navi-cheats/cheats &amp;lt;/dev/tty&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;LBUFFER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$selected&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi
  &lt;/span&gt;zle redisplay
&lt;span class="o"&gt;}&lt;/span&gt;

zle &lt;span class="nt"&gt;-N&lt;/span&gt; _call_navi
bindkey &lt;span class="s1"&gt;'^n'&lt;/span&gt; _call_navi


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

&lt;/div&gt;

&lt;p&gt;The post important parts are the &lt;code&gt;--path&lt;/code&gt; argument, which tells &lt;code&gt;navi&lt;/code&gt; to look in a specific location for cheat sheets (I prefer to use my own directories, instead of the built in ones and "adding repos" feature). You can add multiple&lt;br&gt;
directories separated via &lt;code&gt;:&lt;/code&gt; (and technically I have a few directories, including a &lt;code&gt;$work&lt;/code&gt; one that I pulled out of the example above).&lt;/p&gt;

&lt;p&gt;The path listed above is the &lt;code&gt;cheats/&lt;/code&gt; directory of &lt;a href="https://github.com/kbknapp/navi-cheats" rel="noopener noreferrer"&gt;my public repository&lt;/a&gt;. It's just a big list of &lt;code&gt;.cheat&lt;/code&gt; files. More on that soon.&lt;/p&gt;

&lt;p&gt;Also the &lt;code&gt;--print&lt;/code&gt; flag tells &lt;code&gt;navi&lt;/code&gt; to simply print the final command, instead of running it. This is useful because often I want to make some additional edits to the command that either my cheat sheet didn't account for, or the features simply don't exist to add the flexibility I wanted.&lt;/p&gt;

&lt;p&gt;Normally, &lt;code&gt;--print&lt;/code&gt; would just print the command to &lt;code&gt;stdout&lt;/code&gt;, however with ZSH you can have the current command line replaced by the output of a command, which is what is happening the remainder of the function.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a &lt;code&gt;.cheat&lt;/code&gt; file?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;navi&lt;/code&gt; looks for files ending in &lt;code&gt;.cheat&lt;/code&gt; with a particular structure. I won't re-hash the &lt;a href="https://github.com/denisidoro/navi/blob/master/docs/cheatsheet_syntax.md" rel="noopener noreferrer"&gt;entire tutorial from the &lt;code&gt;navi&lt;/code&gt; repository&lt;/a&gt; since it's quite good and comprehensive, but the TL;DR is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.cheat&lt;/code&gt; files can be split up and named however you like, as the file names aren't used by &lt;code&gt;navi&lt;/code&gt;. I tend to use either command names or situations as file names.&lt;/li&gt;
&lt;li&gt;Lines starting with &lt;code&gt;;&lt;/code&gt; are ignored (comments)&lt;/li&gt;
&lt;li&gt;Lines starting with &lt;code&gt;%&lt;/code&gt; are categories and comma separated key words. These make good "tags" when fuzzy matching. I tend to use command names, or variations of the names to assist with matching.&lt;/li&gt;
&lt;li&gt;Command descriptions are lines starting with &lt;code&gt;#&lt;/code&gt; and used as a short description of a command&lt;/li&gt;
&lt;li&gt;Commands templates are on the line below a description with no leading characters.

&lt;ul&gt;
&lt;li&gt;Commands templates can be multi-line with &lt;code&gt;\&lt;/code&gt; like regular shell commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KEY&lt;/strong&gt; Commands templates can have "variables" that get expanded &lt;em&gt;later&lt;/em&gt; if
the command is selected. Variables are words surrounded by angle brackets
(i.e. &lt;code&gt;&amp;lt;foo&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;"variable expansions" are optional, but are lines that start with &lt;code&gt;$&lt;/code&gt; followed by the variable name, then &lt;code&gt;:&lt;/code&gt; followed by the command to expand the variable (i.e. the command to present options to user for selection). So our &lt;code&gt;&amp;lt;foo&amp;gt;&lt;/code&gt; variable could have an expansion &lt;code&gt;$ foo: echo -e "true\nfalse"&lt;/code&gt; which would present the two options &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; to the user using &lt;code&gt;fzf&lt;/code&gt;, then whatever the user selected would replace the &lt;code&gt;&amp;lt;foo&amp;gt;&lt;/code&gt; in the command template.&lt;/li&gt;

&lt;li&gt;If no variable expansion line is provided, an &lt;code&gt;fzf&lt;/code&gt; text box is presented to the user allowing them to type whatever they want, which will replace the variable in the template.&lt;/li&gt;

&lt;li&gt;Files can have as many "categories" as you like&lt;/li&gt;

&lt;li&gt;Multiple command templates can share a single expansion. I.e. think of of a bunch of firewall commands, all of which need to allow a user to select a port number. All firewall template command could list a &lt;code&gt;&amp;lt;port&amp;gt;&lt;/code&gt; variable, and the file would contain a single &lt;code&gt;$ port: ...&lt;/code&gt; expansion that applies to all templates.&lt;/li&gt;

&lt;li&gt;Beyond functioning as tags, categories separate out variable expansions. So variables expansions only apply to command templates within the same category.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So a typical &lt;code&gt;.cheat&lt;/code&gt; file follows this kind of a pattern:&lt;/p&gt;

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


% foo, bar

# Description of command
command -f -b &amp;lt;qux&amp;gt;

# Description of other command
other_command -b -z &amp;lt;bar&amp;gt; &amp;lt;foo&amp;gt;

$ bar: ...
$ foo: ...



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

&lt;/div&gt;

&lt;p&gt;Again, a single &lt;code&gt;.cheat&lt;/code&gt; file can have multiple &lt;code&gt;%&lt;/code&gt; categories, splitting up the expansions, to allow you to re-use variable names with different concrete expansions. Although, I &lt;em&gt;normally&lt;/em&gt; only have a single &lt;code&gt;%&lt;/code&gt; per file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable Expansions
&lt;/h2&gt;

&lt;p&gt;This is where the true power of &lt;code&gt;navi&lt;/code&gt; comes in to play. By default, &lt;code&gt;navi&lt;/code&gt; presents a blank &lt;code&gt;fzf&lt;/code&gt; text box for variables without an expansion line. Such as the &lt;code&gt;&amp;lt;qux&amp;gt;&lt;/code&gt; variable above.&lt;/p&gt;

&lt;p&gt;So let's first build out our first &lt;code&gt;strace&lt;/code&gt; &lt;code&gt;.cheat&lt;/code&gt; file:&lt;/p&gt;

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

% strace

# Display system calls for a command
strace &amp;lt;CMD&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;Running &lt;code&gt;navi&lt;/code&gt;, and typing something in the fuzzy match area to select our &lt;code&gt;strace&lt;/code&gt; command then brings up a new screen asking us to fill in the &lt;code&gt;CMD&lt;/code&gt; variable (since we did not provide an expansion). If we type &lt;code&gt;firefox&lt;/code&gt;, &lt;code&gt;navi&lt;/code&gt; drops us back to the terminal with the following command ready to run:&lt;/p&gt;

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

$ strace firefox


&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%2Fkbknapp.dev%2Fimgs%2Fnavi_01.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_01.gif" alt="Fig. 01"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Expansions
&lt;/h2&gt;

&lt;p&gt;We can present a limited set of options for the user (which by default also allows them to type something outside of our presented options).&lt;/p&gt;

&lt;p&gt;So if we instead add the following line below our command template, we'll get a list of two options.&lt;/p&gt;

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

$ CMD: echo -e 'firefox\ngoogle-chrome'


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;br&gt;
the user can still type something outside of our two options, although we can prevent this behavior which we'll see in a minute.&lt;/p&gt;
&lt;/blockquote&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%2Fkbknapp.dev%2Fimgs%2Fnavi_02.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_02.gif" alt="Fig. 02"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;fzf&lt;/code&gt; by default delimits options via a newline &lt;code&gt;\n&lt;/code&gt;, we can actually make the expansion a little more readable using spaces, since the values themselves don't have any spaces.&lt;/p&gt;

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

$ CMD: echo 'firefox google-chrome' | tr ' ' '\n'


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

&lt;/div&gt;

&lt;p&gt;This is functionally equivalent to what we had before, but some prefer it. It also points out that expansions can use standard pipes &lt;code&gt;|&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's add a new command (with description) to our file:&lt;/p&gt;

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

% strace

# Display system calls for a command
strace &amp;lt;CMD&amp;gt;

; 👇 is new
# Display system calls for a single PID
strace -p &amp;lt;PID&amp;gt;

$ CMD: echo 'firefox google-chrome' | tr ' ' '\n'


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

&lt;/div&gt;

&lt;p&gt;Now we can type out a PID we wish to attach &lt;code&gt;strace&lt;/code&gt; to.&lt;/p&gt;

&lt;p&gt;But there is a problem; since we didn't provide an expansion, it's up to us to type in a valid PID. For example, typing &lt;code&gt;foo&lt;/code&gt; just blindly makes our command line:&lt;/p&gt;

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

$ strace -p foo


&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%2Fkbknapp.dev%2Fimgs%2Fnavi_03.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_03.gif" alt="Fig. 03"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which will error when run.&lt;/p&gt;

&lt;p&gt;Using a static expansion can help with this somewhat:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; on 64bit systems &lt;code&gt;PID_MAX_LIMIT&lt;/code&gt; is around 4 million...but for simplicity and demo sake we'll make it the 32bit limit since we'll be changing it shortly anyways.&lt;/p&gt;

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

$ PID: echo {0..32768} | tr ' ' '\n'


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

&lt;/div&gt;

&lt;p&gt;Which is better, we'll get a &lt;em&gt;huge&lt;/em&gt; list of numbers (that we can fuzzy match through). And we'll be dropped on the command line with a PID:&lt;/p&gt;

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

$ strace -p 28267


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

&lt;/div&gt;

&lt;p&gt;But we still have the problem of someone can just type &lt;code&gt;foo&lt;/code&gt; and again we're in invalid territory.&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%2Fkbknapp.dev%2Fimgs%2Fnavi_04.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_04.gif" alt="Fig. 04"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;navi&lt;/code&gt; provides a delimiter we can use on the variable expansions &lt;code&gt;---&lt;/code&gt; to provide additional context &lt;code&gt;navi&lt;/code&gt; either about the selection itself, or presentation of the options. One such option is &lt;code&gt;--prevent-extra&lt;/code&gt; which limits the user to list of options you provided, and nothing more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;br&gt;
&lt;code&gt;--prevent-extra&lt;/code&gt; is listed as experimental. And when user provides something outside the presented list, &lt;code&gt;navi&lt;/code&gt; exits with an error. I'm on the fence about if that's better or not. But it's an option no less.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Changing our expansion to the following solves the invalid issue we had before:&lt;/p&gt;

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

;                                    👇 is new
$ PID: echo {0..32768} | tr ' ' '\n' --- --prevent-extra


&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%2Fkbknapp.dev%2Fimgs%2Fnavi_05.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_05.gif" alt="Fig. 05"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Expansions
&lt;/h2&gt;

&lt;p&gt;That crazy list of PIDs with no context isn't a ton of help either. Luckily &lt;code&gt;navi&lt;/code&gt; can come up with options dynamically!&lt;/p&gt;

&lt;p&gt;So instead of just providing 32,000 numbers in sequence, with no process names, or even knowing if its a valid PID of a current process we can just ask &lt;code&gt;navi&lt;/code&gt; to look at the currently running processes via standard shell commands and&lt;br&gt;
present those to the user.&lt;/p&gt;

&lt;p&gt;But we have a slight problem, something like &lt;code&gt;ps -aux&lt;/code&gt; prints out far more information than we need. We need a PID and a name, more or less.&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;navi&lt;/code&gt; expansions are just shell pipes, we can use standard utilities like &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; to fix that!&lt;/p&gt;

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

$ PID: ps -aux | grep -v PID | awk '{print $2"    "$11}' --- --prevent-extra


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

&lt;/div&gt;

&lt;p&gt;We leave the &lt;code&gt;--prevent-extra&lt;/code&gt; because we're still limited on if the PID isn't present in this list, well its not valid.&lt;/p&gt;

&lt;p&gt;Now we get a nice fuzzy match-able list of PIDs and the associated processes!&lt;/p&gt;

&lt;p&gt;However, running this shows one more issue...we get the &lt;em&gt;whole&lt;/em&gt; selection on our command line:&lt;/p&gt;

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

$ strace -p 3860    /usr/bin/firefox


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;br&gt;
the extra spaces in there come from our expansion option too!&lt;/p&gt;
&lt;/blockquote&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%2Fkbknapp.dev%2Fimgs%2Fnavi_06.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_06.gif" alt="Fig. 06"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;navi&lt;/code&gt; options to the rescue again! There is a &lt;code&gt;--column&lt;/code&gt; option which allows us to use only a single column of output as the final selection!&lt;/p&gt;

&lt;p&gt;Changing our expansion to:&lt;/p&gt;

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

;                                                            👇 is new
$ PID: ps -aux | grep -v PID | awk '{print $2"    "$11}' --- --column 1 --prevent-extra


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

&lt;/div&gt;

&lt;p&gt;Gives us the correct output.&lt;/p&gt;

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

$ strace -p 3860


&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%2Fkbknapp.dev%2Fimgs%2Fnavi_07.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_07.gif" alt="Fig. 07"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much better!&lt;/p&gt;

&lt;h2&gt;
  
  
  Additive Options
&lt;/h2&gt;

&lt;p&gt;Ok, so we can now build an &lt;code&gt;strace&lt;/code&gt; command, fuzzy match through a valid list of processes running on our computer, but &lt;code&gt;strace&lt;/code&gt; provides all kinds of additional options for us. For example, what we want to suppress &lt;code&gt;attach/detach&lt;/code&gt; messages (i.e. &lt;code&gt;-q&lt;/code&gt;), or it's variations (&lt;code&gt;-qq&lt;/code&gt; or &lt;code&gt;-qqq&lt;/code&gt;)?&lt;/p&gt;

&lt;p&gt;Turns out, we can use expansions for that too!&lt;/p&gt;

&lt;p&gt;Changing our command template slightly, to add a placeholder for the &lt;code&gt;-q|-qq|-qqq&lt;/code&gt;:&lt;/p&gt;

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

# Display system calls for a single PID
strace &amp;lt;QUIET&amp;gt; -p &amp;lt;PID&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;We can then add another expansion this variable:&lt;/p&gt;

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

$ QUIET: echo -e '\t\tNo suppression;-q\t\tSuppress attach/detach messages;-qq\t\tAlso suppress exit statuses;-qqq\t\tSuppress every suppressible message' | tr ';' '\n' --- --column 1


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

&lt;/div&gt;

&lt;p&gt;We're just building off what we already know. Splitting options into two columns with the flag we want to add on the left, and description on the right, separating all options with &lt;code&gt;;&lt;/code&gt; which we can replace with a newline via &lt;code&gt;tr&lt;/code&gt;,&lt;br&gt;
then telling &lt;code&gt;navi&lt;/code&gt; to only use the first column as the actual selected output for the expansion.&lt;/p&gt;

&lt;p&gt;Now we get a new screen asking us if we want to suppress messages or not, with the associated option on the left!&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%2Fkbknapp.dev%2Fimgs%2Fnavi_08.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_08.gif" alt="Fig. 08"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PRO TIP:&lt;/strong&gt; It's a good idea to place the "none" or "no" option that represents no additional flags first, as the user can then just fly through pressing &lt;code&gt;&amp;lt;enter&amp;gt;&lt;/code&gt; when they don't wish to add anything additional. This greatly helps when there are a bunch of optional flags.&lt;/p&gt;

&lt;p&gt;One final nicety I like to add is the &lt;code&gt;--header&lt;/code&gt; option, which allows one to give a short text describing what the user is actually selecting. This comes in handy sometimes when the choices aren't super explanatory.&lt;/p&gt;

&lt;p&gt;So our final expansion version becomes:&lt;/p&gt;

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

$ QUIET: echo -e '\t\tNo suppression;-q\t\tSuppress attach/detach messages;-qq\t\tAlso suppress exit statuses;-qqq\t\tSuppress every suppressible message' | tr ';' '\n' --- --column 1 --header "Suppress any output?"


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

&lt;/div&gt;

&lt;p&gt;This shows a text message above the input box with description of what &lt;code&gt;navi&lt;/code&gt; is&lt;br&gt;
asking.&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%2Fkbknapp.dev%2Fimgs%2Fnavi_09.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_09.gif" alt="Fig. 09"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can continue fleshing out the options repeating the above steps for the flags we want to present.&lt;/p&gt;

&lt;p&gt;Here is more complete set of expansions:&lt;/p&gt;

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

# Display system calls for a command
strace &amp;lt;SUMMARY&amp;gt; &amp;lt;QUIET&amp;gt; &amp;lt;FOLLOW_FORKS&amp;gt; &amp;lt;SYSCALL_TIMES&amp;gt; &amp;lt;SUCCESS_FAILED&amp;gt; &amp;lt;DECODE_FDS&amp;gt; &amp;lt;CMD&amp;gt;
;      👆 these variables are new
# Display system calls for a single PID
strace &amp;lt;SUMMARY&amp;gt; &amp;lt;QUIET&amp;gt; &amp;lt;FOLLOW_FORKS&amp;gt; &amp;lt;SYSCALL_TIMES&amp;gt; &amp;lt;SUCCESS_FAILED&amp;gt; &amp;lt;DECODE_FDS&amp;gt; -p &amp;lt;PID&amp;gt;
;      👆 these variables are new

$ PID: ps aux | grep -v 'PID' | awk '{print $2"    "$11}' --- --column 1 --header "PID to attach to?"
$ QUIET: echo -e '\t\tNo suppression;-q\t\tSuppress attach/detach messages;-qq\t\tAlso suppress exit statuses;-qqq\t\tSuppress every suppressible message' | tr ';' '\n' --- --column 1 --header "Suppress any output?"

; 👇 These expansions are new
$ TIME_STAMPS: echo -e "-t\t\tabsolute;-tt\t\tabsolute usecs;-ttt\t\tabsolute UNIX time" | tr ';' '\n' --- --column 1 --header "Print Timestamps?"
$ SUMMARY: echo -e "\t\tnone;-c\t\tsummary;-C\t\tsummary only" | tr ';' '\n' --- --column 1 --header "Print Summary?"
$ FOLLOW_FORKS: echo -e "\t\tno;-f\t\tfollow forks;-ff\t\tfollow forks and split output" | tr ';' '\n' --- --column 1 --header "Follow Forks?"
$ SYSCALL_TIMES: echo -e "\t\tno;-T\t\ttime spent in syscalls" | tr ';' '\n' --- --column 1 --header "Display time spent in syscalls?"
$ SUCCESS_FAILED: echo -e "\t\tdon't filter;-z\t\tsuccess only;-Z\t\tfailed only" | tr ';' '\n' --- --column 1 --header "Filter success or failed exits?"
$ DECODE_FDS: echo -e "\t\tno;-yy\t\tdecode all fds" | tr ';' '\n' --- --column 1 --header "Decode File Descriptors?"


&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%2Fkbknapp.dev%2Fimgs%2Fnavi_10.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_10.gif" alt="Fig. 10"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we'll have more expansions, you'll notice that in the upper section of the &lt;code&gt;navi&lt;/code&gt; window, there is a preview of what expansions have been expanded to thus var. This comes in handy at times.&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%2Fkbknapp.dev%2Fimgs%2Fnavi_11.jpg" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_11.jpg" alt="Fig. 11"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This brings us to one of the limitations of &lt;code&gt;navi&lt;/code&gt; (thus far), in that it's difficult to see if a previous variable has been expanded into something or another. There is &lt;a href="https://github.com/denisidoro/navi/blob/master/docs/cheatsheet_syntax.md#variable-dependency" rel="noopener noreferrer"&gt;variable dependencies&lt;/a&gt; but those don't quite do what I want.&lt;/p&gt;

&lt;p&gt;A good example is the next (and probably most important) option for &lt;code&gt;strace&lt;/code&gt; and that is the filtering.&lt;/p&gt;

&lt;p&gt;For example, so see all syscalls related to processes (such as &lt;code&gt;execve(2)&lt;/code&gt; for when a process is created), you could use:&lt;/p&gt;

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

$ strace -e trace=process ...


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-e&lt;/code&gt; option takes expressions in the form of &lt;code&gt;option=value&lt;/code&gt;. There are quite a few predefined options, as well as values, groups, etc.&lt;/p&gt;

&lt;p&gt;The way &lt;code&gt;navi&lt;/code&gt; works now, you can't for example ask, "Do you want to add an expression" and insert &lt;code&gt;-e foo=bar&lt;/code&gt; or nothing if they answer no. So we end up with two different command templates, one with expressions and one without.&lt;/p&gt;

&lt;p&gt;Additionally, &lt;code&gt;navi&lt;/code&gt; is limited to a single expression, you can't for example loop and provide multiple expressions. &lt;code&gt;navi&lt;/code&gt; does provide a &lt;code&gt;--multi&lt;/code&gt; option which allows FZF to pick multiple options from the list (i.e. imagine multiple&lt;br&gt;
firewall ports), but not multiple pairs in the syntax &lt;code&gt;strace&lt;/code&gt; expects. This is normally fine, as you can always add additional expressions after &lt;code&gt;navi&lt;/code&gt; is finished, and many times a single expression is all you want anyways.&lt;/p&gt;

&lt;p&gt;To get a better sense of this, we'll add two more command templates, adding expressions, and &lt;code&gt;navi&lt;/code&gt; provided lists for the &lt;code&gt;options&lt;/code&gt; and &lt;code&gt;values&lt;/code&gt; pairs:&lt;/p&gt;

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

# Display system calls for a command (with a filter)
strace -e &amp;lt;EXPR_OPT&amp;gt;=&amp;lt;EXPR_SET&amp;gt; &amp;lt;SUMMARY&amp;gt; &amp;lt;QUIET&amp;gt; &amp;lt;FOLLOW_FORKS&amp;gt; &amp;lt;SYSCALL_TIMES&amp;gt; &amp;lt;SUCCESS_FAILED&amp;gt; &amp;lt;DECODE_FDS&amp;gt; &amp;lt;CMD&amp;gt;
;      👆 the -e variables are new
# Display system calls for a single PID (with a filter)
strace -e &amp;lt;EXPR_OPT&amp;gt;=&amp;lt;EXPR_SET&amp;gt; &amp;lt;SUMMARY&amp;gt; &amp;lt;QUIET&amp;gt; &amp;lt;FOLLOW_FORKS&amp;gt; &amp;lt;SYSCALL_TIMES&amp;gt; &amp;lt;SUCCESS_FAILED&amp;gt; &amp;lt;DECODE_FDS&amp;gt; -p &amp;lt;PID&amp;gt;
;      👆 the -e variables are new

$ EXPR_OPT: echo 'trace abbrev verbose raw signal read write fault inject status quiet kvm decode-fds' | tr ' ' '\n' --- --header "Expression Option (or type custom)?"
$ EXPR_SET: echo 'clock creds desc file fstat fstatfs ipc llstat memory net process pure signal stat statfs all none' | tr ' ' '\n' --- --header "Expression Set (or type custom)?"


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

&lt;/div&gt;

&lt;p&gt;Now we can interactively build a full &lt;code&gt;strace&lt;/code&gt; command!&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%2Fkbknapp.dev%2Fimgs%2Fnavi_12.gif" 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%2Fkbknapp.dev%2Fimgs%2Fnavi_12.gif" alt="Fig. 12"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want to allow the user to type something outside our list, because &lt;code&gt;strace&lt;/code&gt; supports a bunch more options, and regex, or &lt;code&gt;!&lt;/code&gt; not expressions, etc. However, &lt;code&gt;navi&lt;/code&gt; doesn't have a full way to express those options so we're limited.&lt;/p&gt;

&lt;p&gt;But this is still &lt;em&gt;leaps and bounds&lt;/em&gt; better than nothing!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Hopefully, this has shown how having a command builder can be a huge help. Yes...it is work to make the cheat sheets, however there are plenty out there ripe for copying. &lt;code&gt;navi&lt;/code&gt; also has built in functionality to add public &lt;code&gt;git&lt;/code&gt;&lt;br&gt;
repos as cheat repositories, and have them automatically updated. I prefer to use my own and have more control over them, but that option exists for those that want to bootstrap making their own cheats.&lt;/p&gt;

&lt;p&gt;There is quite a bit more &lt;code&gt;navi&lt;/code&gt; can do, but this post is long enough!&lt;/p&gt;

&lt;p&gt;Happy cheating.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>navi</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>My Shell Setup</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Sun, 27 Nov 2022 02:49:59 +0000</pubDate>
      <link>https://dev.to/kbknapp/my-shell-setup-5f15</link>
      <guid>https://dev.to/kbknapp/my-shell-setup-5f15</guid>
      <description>&lt;p&gt;Details a few steps I take to make my terminal experience a little morepleasant.&lt;/p&gt;

&lt;p&gt;I spend most of my day in the terminal in one form or another. There are a few steps I've collected over the years to make my experience more pleasant and most importantly more efficient.&lt;/p&gt;

&lt;p&gt;Most of the steps require some level of software to be installed or configuration to be changed, so I can't perform these steps on all production servers I work in. However, many of the steps are only applicable to my local machine, and the short period of time I'm working in a remote server is minimal, or aided by changes I made locally.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuration
&lt;/h1&gt;

&lt;p&gt;Before I talk about the actual steps, I should mention where I store my custom configuration files. Manually entering these on each machine I wish to configure would be huge pain.&lt;/p&gt;

&lt;p&gt;Like many people, I keep all of my configuration files stored in a public &lt;a href="https://github.com/kbknapp/dotfiles" rel="noopener noreferrer"&gt;&lt;code&gt;dotfiles&lt;/code&gt;&lt;/a&gt; repository on GitHub. It's a bit of a mess as I only use particular parts on particular machines. So it's not&lt;br&gt;
meant to be publicly read or analyzed. However, my point is that the configuration files are stored in a central location where I can simply clone the repository down to my machine, symlink the files or directories I care about and want to use and go about my day.&lt;/p&gt;

&lt;p&gt;I don't use anything like Ansible to set up my machine because there are too many variables that control how I use a particular machine and which steps I want to actually utilize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aside:&lt;/strong&gt; I actually have a &lt;a href="https://github.com/kbknapp/baseline" rel="noopener noreferrer"&gt;&lt;code&gt;baseline&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
set of scripts that do all the copying/symlinking for me based on a TUI dialog I fill out. To be clear, this is in no way meant to be publicly consumed as many of the steps are hard-coded for my specific machines.&lt;/p&gt;
&lt;h1&gt;
  
  
  Notes on Distribution
&lt;/h1&gt;

&lt;p&gt;I use Fedora on all my workstations, but I've also run variants of Ubuntu at times for work, so all the steps work on either distro. The install commands listed in this post are for Fedora. The package names may be different in Ubuntu&lt;br&gt;
and I try to call those out where I'm aware of any differences.&lt;/p&gt;
&lt;h1&gt;
  
  
  Improvements
&lt;/h1&gt;

&lt;p&gt;These steps change some way in which I interact with the terminal, whether they be standalone tools, or work-flows I use. All these steps are used to improve the speed at which I work, or to better the experience.&lt;/p&gt;

&lt;p&gt;Most of the changes build on each-other, or other skills I've built up along the years so they may not be widely applicable unless you're in a similar boat. For example, using the plugin &lt;code&gt;vi-mode&lt;/code&gt; in my shell combined with &lt;code&gt;fzf&lt;/code&gt; searching&lt;br&gt;
through my command history is lightning fast (especially when I need to edit a previous command).&lt;/p&gt;
&lt;h1&gt;
  
  
  ZSH
&lt;/h1&gt;

&lt;p&gt;While the default Bash shell is fine for many cases (and ubiquitous) it definitely has it's limitations. Many people are familiar with and prefer the more modern Fish shell. However, I find Fish breaks too many of my existing scripts (well, almost all of them) as well as my muscle memory, and causes me to have to change commands when Googling around for fixes because everyone assumes Bash (or Sh at the least).&lt;/p&gt;

&lt;p&gt;Add to that, the thing most people ooooh and ahhhhh over with Fish, at least initially, is the auto-suggestions and syntax highlighting, which my preferred shell (ZSH) can do as well as you'll see soon.&lt;/p&gt;

&lt;p&gt;ZSH is nearly fully compatible with Bash, in fact I've had to make zero changes to any existing scripts or commands to adapt. All my Bash knowledge works in ZSH.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aside:&lt;/strong&gt; The one area where I've personally hit differences is when &lt;em&gt;writing&lt;/em&gt; completion scripts for programs (i.e. the menus that pop up when you hit &lt;code&gt;&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/code&gt;). ZSH completion scripts are pretty different (and far more functional), but I'd also wager that 99.7% of people out there are not writing&lt;br&gt;
completion scripts regularly, or at all, so this should not affect them.&lt;/p&gt;

&lt;p&gt;Since I mentioned completion scripts in the aside, programs that support ZSH completions are &lt;em&gt;so much nicer&lt;/em&gt;, than the Bash completion variants.&lt;/p&gt;

&lt;p&gt;Here's an example of completions of &lt;code&gt;git&lt;/code&gt; in Bash:&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_bash_git.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_bash_git.gif" alt="Bash Completions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's an example of completions of &lt;code&gt;git&lt;/code&gt; in ZSH:&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_zsh_git.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_zsh_git.gif" alt="ZSH Completions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a bunch of ZSH features that I love, but the few that sound the smallest yet I probably use the most are case-insensitive paths, command-fix-suggestions, and not using &lt;code&gt;cd&lt;/code&gt; to change directories.&lt;/p&gt;

&lt;p&gt;Those sound tiny. But they add up quickly when using the terminal constantly.&lt;/p&gt;

&lt;p&gt;In ZSH, you can type &lt;code&gt;cat foo&lt;/code&gt;, when the file is really &lt;code&gt;Foo&lt;/code&gt; and ZSH will auto-correct the path for you.&lt;/p&gt;

&lt;p&gt;If you typo the command, and it's close enough to a real command, or file/directory ZSH will also suggest a fix that you can accept or ignore. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gti commit -m "foo"
zsh: correct 'gti' to 'git' [nyae]?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, instead of typing &lt;code&gt;cd ../blah/&lt;/code&gt; you can just type &lt;code&gt;../blah/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Even though there is so much more ZSH can do, let's just assume you're sold, how do we install and use it? Here's my setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo dnf install zsh
  (install ZSH)

$ sudo chsh -s $(which zsh) $USER
  (change my default shell to ZSH)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;chsh&lt;/code&gt; is no longer available by default in some distributions. In Fedora, it's included in the package &lt;code&gt;util-linux-user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then I use the following &lt;code&gt;~/.zshrc&lt;/code&gt; configuration:&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;ENABLE_CORRECTION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;
&lt;span class="nv"&gt;COMPLETION_WAITING_DOTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin:&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.local/bin:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_KEY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/.ssh/rsa_id"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TERM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"xterm-256color"&lt;/span&gt;
fpath+&lt;span class="o"&gt;=&lt;/span&gt;~/.zfunc
compinit &lt;span class="nt"&gt;-U&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Oh-My-ZSH
&lt;/h2&gt;

&lt;p&gt;ZSH by itself is pretty plain, even if functional. There is a ZSH framework that&lt;br&gt;
adds a ton of useful functionality called &lt;code&gt;oh-my-zsh&lt;/code&gt;. It also supports things&lt;br&gt;
like themeing your prompt and whatnot but I don't really use that part as I rely&lt;br&gt;
on other prompt software.&lt;/p&gt;

&lt;p&gt;To install, you clone the repository and add a few lines to your &lt;code&gt;~/.zshrc&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;$ git clone https://github.com/ohmyzsh/ohmyzsh ~/.oh-my-zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a few lines to the &lt;em&gt;top&lt;/em&gt; your ZSH configuration file:&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ZSH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.oh-my-zsh
&lt;span class="nv"&gt;ZSH_THEME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"robbyrussell"&lt;/span&gt;
&lt;span class="nv"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;git systemd&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="nv"&gt;$ZSH&lt;/span&gt;/oh-my-zsh.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;ZSH_THEME&lt;/code&gt; variable controls the theme, and there are a ton. However, in the following steps I disable it in favor of other options.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;plugins&lt;/code&gt; is the next most important line. There are a ton of &lt;a href="https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins" rel="noopener noreferrer"&gt;plugins&lt;/a&gt;, and the ones listed above just a few that apply to almost any box. In the following sections we'll add a few more. Many plugins simply add the shell completions for particular commands, while others add entirely new functionality. It's&lt;br&gt;
definitely worth a look through the list of plugins to see if any catch your eye for software you use frequently.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;br&gt;
There is a small startup cost associated with plugins, so it's good to only add the ones you'll use frequently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Auto-Suggestions
&lt;/h3&gt;

&lt;p&gt;This is the feature that most people love from Fish. It uses your command history to suggest commands live as you type, and frankly I love it too.&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_auto_suggest.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_auto_suggest.gif" alt="auto-suggest"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add this functionality to ZSH you clone a repo, and add a plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add &lt;code&gt;zsh-autosuggestions&lt;/code&gt; to your &lt;code&gt;plugins&lt;/code&gt; array in your &lt;code&gt;~/.zshrc&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax Highlighting
&lt;/h3&gt;

&lt;p&gt;Another feature people love from Fish. This one colors the command you're typing green if the command is found and valid, or red if not. This again sounds so small, but can be such a huge help when typing commands you don't use often or&lt;br&gt;
when copy/pasting from other medium. It can even catch typos &lt;em&gt;before&lt;/em&gt; running the command. I love it.&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_syntax.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_syntax.gif" alt="syntax-highlight"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, a simple clone and add a plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add &lt;code&gt;zsh-syntax-highlighting&lt;/code&gt; to the &lt;code&gt;plugins&lt;/code&gt; array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Abbrev-Alias
&lt;/h3&gt;

&lt;p&gt;This plugin &lt;strong&gt;expands&lt;/strong&gt; aliases automatically. For example, I have an alias of &lt;code&gt;gl='git log --graph --all --oneline --decorate'&lt;/code&gt;. Using this plugin, when I type &lt;code&gt;gl&lt;/code&gt; followed by &lt;code&gt;&amp;lt;space&amp;gt;&lt;/code&gt; (assuming I want to add on to the command) or&lt;br&gt;
&lt;code&gt;&amp;lt;enter&amp;gt;&lt;/code&gt; to run the command the &lt;code&gt;gl&lt;/code&gt; is replaced by the &lt;em&gt;real underlying command&lt;/em&gt;.&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_abbrev.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_abbrev.gif" alt="abbrev-alias"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why would you want this?! Because all too often people memorize the alias, but not the command it represents. This means when you SSH into a server, or on a machine without all your custom aliases you can feel at a disadvantage. Using&lt;br&gt;
&lt;code&gt;abbrev-alias&lt;/code&gt; keeps these real commands front and center so that one at least &lt;em&gt;sees&lt;/em&gt; them as frequently as they're run.&lt;/p&gt;

&lt;p&gt;To install, you clone a repo and &lt;code&gt;source&lt;/code&gt; the script in your &lt;code&gt;~/.zshrc&lt;/code&gt;, and use &lt;code&gt;abbrev-alias&lt;/code&gt; instead of the normal &lt;code&gt;alias&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/momo-lab/zsh-abbrev-alias ~/.config/zsh-abbrev-alias/
$ echo 'source $HOME/.config/zsh-abbrev-alias/abbrev-alias.plugin.zsh' &amp;gt;&amp;gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then for example, to add the &lt;code&gt;gl&lt;/code&gt; alias I mentioned earlier&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;abbrev-alias &lt;span class="nv"&gt;gl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git log --graph --all --oneline --decorate'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Liberal use of aliases is a key aspect of quickly using the terminal. This plugin removes the biggest detriment of why some people dislike aliases!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;br&gt;
The only time I still use normal aliases is if I'm replacing a command with another, i.e. &lt;code&gt;alias ls=exa&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; the flags/options on the two commands are compatible (or nearly so).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Sudo
&lt;/h3&gt;

&lt;p&gt;Another tiny quality of life improvement is the ability to quickly add &lt;code&gt;sudo&lt;/code&gt; to the beginning of any command. If I'm half-way through typing a long command and realize I forgot to add &lt;code&gt;sudo&lt;/code&gt;, in Bash I may have to erase the command and&lt;br&gt;
start over, or move the cursor to the beginning of the line to type &lt;code&gt;sudo&lt;/code&gt; and back to the end, or &lt;strong&gt;if the command is safe&lt;/strong&gt; to run as an unprivileged user just run it and then quickly run &lt;code&gt;sudo !!&lt;/code&gt; to replay the command. However, all&lt;br&gt;
of those are not great and can be slow.&lt;/p&gt;

&lt;p&gt;This plugin allows me to simply type &lt;code&gt;&amp;lt;esc&amp;gt;&amp;lt;esc&amp;gt;&lt;/code&gt; which adds &lt;code&gt;sudo&lt;/code&gt; and keeps my cursor wherever I had it. As a bonus, it doesn't even negatively affect &lt;code&gt;vi-mode&lt;/code&gt; (which we'll see next!) which also uses &lt;code&gt;&amp;lt;esc&amp;gt;&lt;/code&gt;.&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_sudo.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_sudo.gif" alt="sudo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install simply add &lt;code&gt;sudo&lt;/code&gt; to the &lt;code&gt;plugins&lt;/code&gt; array as it's built in to &lt;code&gt;oh-my-zsh&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Vi Mode
&lt;/h3&gt;

&lt;p&gt;This plugin is only useful if you're used to Vi(m) keybindings. I use it constantly. When combined with &lt;code&gt;starship&lt;/code&gt; below, this even better because you get a visual indicator on your prompt if you're in Normal mode or Insert mode.&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/..%2Fimgs%2Fshell_howto_vi_mode.gif" 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/..%2Fimgs%2Fshell_howto_vi_mode.gif" alt="vi-mode"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install, simply add &lt;code&gt;vi-mode&lt;/code&gt; to your &lt;code&gt;plugins&lt;/code&gt; array as it's built in to oh-my-zsh.&lt;/p&gt;
&lt;h2&gt;
  
  
  Custom Prompts
&lt;/h2&gt;

&lt;p&gt;Custom prompts allow you to visually determine facts about you're environment without having to run additional commands. Most of the time, all these bits of information you can find via manual commands, but to efficiently use the terminal we try to minimize the manual commands we have to use.&lt;/p&gt;

&lt;p&gt;Some people prefer this information in other locations like a &lt;code&gt;tmux&lt;/code&gt; status line. However, I prefer to have most of the information about my &lt;strong&gt;ephemeral environment&lt;/strong&gt; in my shell prompt.&lt;/p&gt;

&lt;p&gt;'Ephemeral environment' means it can change from command to command, or directory to directory. Non-ephemeral information is items like machine resource information, tickers, clocks, etc. Non-ephemeral information I prefer in places like &lt;code&gt;tmux&lt;/code&gt; or my desktop environment (DE), not my prompt.&lt;/p&gt;

&lt;p&gt;To combat the problem where long paths, or lots of bits of information can start to take up a large portion of the current line, I prefer prompt solutions which allow multi-line prompts where all the "status info" is on the first line, and my cursor/command is on the second line.&lt;/p&gt;

&lt;p&gt;There are two great solutions to prompts; Starship and Powerlevel10k (based on Powerlevel9k). I find Powerlevel10k to be faster, but Starship is easier to customize, has some great features, and is easier to install. I use Starship by&lt;br&gt;
default, but have switched to Powerlevel10k from time to time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Starship
&lt;/h3&gt;

&lt;p&gt;The starship prompt is run with a single binary, and configured with a single file which is one reason I really like it.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://starship.rs/" rel="noopener noreferrer"&gt;demo site&lt;/a&gt; has a great GIF showing all the features and the &lt;em&gt;why&lt;/em&gt;. As well as how to configure all the various items. I have a customized prompt, but the default is perfectly acceptable as well.&lt;/p&gt;

&lt;p&gt;To install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -fsSL https://starship.rs/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use, simply comment out your &lt;code&gt;ZSH_THEME&lt;/code&gt; variable, and add this line to your &lt;code&gt;~/.zshrc&lt;/code&gt; (which the install script may have already added):&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="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;starship init zsh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Powerlevel10k
&lt;/h3&gt;

&lt;p&gt;To install we clone a repo, set our &lt;code&gt;ZSH_THEME&lt;/code&gt; and configure a &lt;code&gt;~/.p10k&lt;/code&gt; file. I find it less configurable when it comes to the actual items I want displayed, but I also find it faster than starship at times since it was designed with ZSH&lt;br&gt;
in mind (whereas starship is designed to be used with any shell).&lt;/p&gt;

&lt;p&gt;Clone the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we set our &lt;code&gt;ZSH_THEME="powerlevel10k/powerlevel10k"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When we open the terminal again we'll be prompted to configure a &lt;code&gt;.p10k&lt;/code&gt; file interactively.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tools
&lt;/h1&gt;

&lt;p&gt;Now that we've set up our shell and prompt, there are a few tools I use constantly while in the terminal. Some are related to the actual shell, while others are just general use tools I find well worth the install.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminator, Tilix, or &lt;code&gt;tmux&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To begin, I'll mention a bit a cheat. The actual terminal emulator itself. There is one area where the terminal emulator itself can &lt;em&gt;greatly&lt;/em&gt; improve one's efficiency.&lt;/p&gt;

&lt;p&gt;Tiling.&lt;/p&gt;

&lt;p&gt;Both Terminator and Tilix provide "tiling" to allow one to quickly open up another terminal to the side or below the current terminal. Terminator also allows one to define "groups" and type in one terminal, but broadcast each&lt;br&gt;
command to all terminals.&lt;/p&gt;

&lt;p&gt;This can be a huge productivity boost over disjoint terminals that require one to constantly move the mouse back and forth between windows, etc.&lt;/p&gt;

&lt;p&gt;The alternative to this is if you're using a true tiling window manager such as i3, or &lt;code&gt;tmux&lt;/code&gt; to handle the tiling inside a single terminal session.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;br&gt;
Of course you &lt;em&gt;could&lt;/em&gt; use &lt;code&gt;tmux&lt;/code&gt; inside Tilix, inside i3...I feel like there is an Xzibit joke there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many people find using Terminator or Tilix to be a good introduction to tiling that provides a good mix between usability and functionality without fully committing to something like &lt;code&gt;tmux&lt;/code&gt; or a Tiling Window Manager.&lt;/p&gt;

&lt;p&gt;I'd don't personally use Tilix or Terminator much, as i3 handles all the tiling for me. I do, however, use &lt;code&gt;tmux&lt;/code&gt; when SSH'ed into various servers and want to tile panes without having to re-authenticate.&lt;/p&gt;
&lt;h2&gt;
  
  
  FZF
&lt;/h2&gt;

&lt;p&gt;The fuzzy finder. This tool is so amazing that it deserves a full post itself.&lt;/p&gt;

&lt;p&gt;It fuzzy matches through lists and allows one to interactively select one (or multiple) items. Sounds simple.&lt;/p&gt;

&lt;p&gt;When it comes to ZSH and the like the two features I use &lt;em&gt;constantly&lt;/em&gt; are &lt;code&gt;ctrl-r&lt;/code&gt; to fuzzy search through my history and &lt;code&gt;ctrl-t&lt;/code&gt; to search through file paths.&lt;/p&gt;

&lt;p&gt;Most package managers include the &lt;code&gt;fzf&lt;/code&gt; package, and place the appropriate configuration files. All you have to do is install it, and source the ZSH script in your &lt;code&gt;~/.zshrc&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;$ sudo dnf install fzf
$ echo '[ -f ~/.fzf.zsh ] &amp;amp;&amp;amp; source ~/.fzf.zsh' &amp;gt;&amp;gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FZF can also be used anywhere a list is produced and you want to pick an (or multiple) elements.&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_fzf.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_fzf.gif" alt="FZF"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ctrl-r
&lt;/h3&gt;

&lt;p&gt;Pressing &lt;code&gt;&amp;lt;ctrl&amp;gt;-r&lt;/code&gt; will bring up a list of commands which you can fuzzy match through, press &lt;code&gt;&amp;lt;ctrl&amp;gt;-up/down&lt;/code&gt; (or &lt;code&gt;&amp;lt;ctrl&amp;gt;-j/k&lt;/code&gt; for vim keybindings) and hit &lt;code&gt;&amp;lt;enter&amp;gt;&lt;/code&gt; on a selection to have that command pasted into your command line.&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_ctrl_r.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_ctrl_r.gif" alt="CTRL-R"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;S-O-O-O&lt;/strong&gt; much better than pressing &lt;code&gt;up&lt;/code&gt; two hundred times to find the command you want in your history.&lt;/p&gt;

&lt;h3&gt;
  
  
  ctrl-t
&lt;/h3&gt;

&lt;p&gt;This works the same as &lt;code&gt;&amp;lt;ctrl&amp;gt;-r&lt;/code&gt;, except its a list of paths. 'Nuf said.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navi
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/denisidoro/navi" rel="noopener noreferrer"&gt;&lt;code&gt;navi&lt;/code&gt;&lt;/a&gt; is about fuzzy search-able command cheat sheets. Yes please.&lt;/p&gt;

&lt;p&gt;With this tool, I can search through (and create my own) command cheat sheets. It's difficult to explain, but when I press &lt;code&gt;&amp;lt;ctrl&amp;gt;+n&lt;/code&gt; a TUI pops up (also using &lt;code&gt;fzf&lt;/code&gt; by the way) which I can fuzzy match through. Upon selecting a command,&lt;br&gt;
that command can have templates where I fill in the required information. Once complete, I'm dropped back to a terminal with the filled out complete command. Amazing!&lt;/p&gt;

&lt;p&gt;Here's a GIF that explains it better than words can. I'm adding a new port the firewall via &lt;code&gt;firewalld&lt;/code&gt;:&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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_navi.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_howto_navi.gif" alt="navi"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tend to make more generic commands, and then will tweak the invocation manually at the end (which with &lt;code&gt;vi-mode&lt;/code&gt; is super fast).&lt;/p&gt;

&lt;p&gt;Installation is done by either building from source, or using bash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bash &amp;lt;(curl -sL https://raw.githubusercontent.com/denisidoro/navi/master/scripts/install)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Making your own cheat sheets is beyond the scope of this post, but highly worth it. It's also possible to use other's repositories and have them auto updated. You can find my own sheets &lt;a href="https://github.com/kbknapp/navi-cheats" rel="noopener noreferrer"&gt;in a GitHub repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, &lt;code&gt;navi&lt;/code&gt; can be run from the command line normally. Setting up the &lt;code&gt;&amp;lt;ctrl&amp;gt;-n&lt;/code&gt; keybinding can be accomplished by &lt;code&gt;eval&lt;/code&gt;'ing the built-in widget command in your &lt;code&gt;~/.zshrc&lt;/code&gt;:&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="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;navi widget zsh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the keybinding is &lt;code&gt;&amp;lt;ctrl&amp;gt;-g&lt;/code&gt;. I prefer to just run &lt;code&gt;navi widget zsh&lt;/code&gt; and paste the output into my &lt;code&gt;~/.zshrc&lt;/code&gt; and change the keybinding from &lt;code&gt;g&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt;, and also point it to my own cheat repositories locally.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;That's all for now. I could write more (and perhaps will later) about some of the tools I use regularly in the command line, such as &lt;code&gt;exa&lt;/code&gt;, Ripgrep, fd-find, or &lt;code&gt;bat&lt;/code&gt;. There's also the potential to write about the aesthetic changes I make&lt;br&gt;
to improve my enjoyment of the terminal, such as font selection or which terminal emulator I actually use.&lt;/p&gt;

</description>
      <category>shell</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>zsh</category>
    </item>
    <item>
      <title>Network Coordinates</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Sun, 27 Nov 2022 00:22:30 +0000</pubDate>
      <link>https://dev.to/kbknapp/network-coordinates-4pk5</link>
      <guid>https://dev.to/kbknapp/network-coordinates-4pk5</guid>
      <description>&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Imagine you have a distributed system and need to answer something like, "Which node is closest to Node X?" or perhaps "Which N nodes are closest to Node Y?"&lt;/p&gt;

&lt;p&gt;It turns out answering this question naively is &lt;em&gt;wildly&lt;/em&gt; wasteful.&lt;/p&gt;

&lt;p&gt;We'll dig in to a popular Network Coordinates system and how to use it correctly below.&lt;/p&gt;

&lt;p&gt;As an example of the kinds of differences we're talking about, a naive solution to this question for a system of 1,000 nodes (where a "node" could be a host, a VM, or even a container) could require between 1GB to 240GB+ network bandwidth per day depending on how accurate (or the frequency of) one would like the results to be. Whereas the solution we'll be discussing here would require 272KB to 65MB for the same "accuracy" levels.&lt;/p&gt;

&lt;p&gt;This more efficient system is known as Network Coordinates. But these coordinates also need to be used properly or you effectively have a fancy version of the naive solution.&lt;/p&gt;

&lt;p&gt;This problem has come up rather frequently for me, and it's been surprising to me how often the naive solution gets picked.&lt;/p&gt;

&lt;p&gt;When initially presented with this problem many people I've talked to decide to simply conduct a few latency checks (such as a &lt;code&gt;ping&lt;/code&gt; or ICMP message) and store a map of the results at each node. Done. Move on the next problem.&lt;/p&gt;

&lt;p&gt;We've already shown how wasteful this could be, but let me expand on it just to prove my case.&lt;/p&gt;

&lt;h1&gt;
  
  
  Lets Math
&lt;/h1&gt;

&lt;p&gt;To demonstrate how this naive solution adds up, let's do some quick back-of-napkin-math for those 1,000 nodes. First I'll mention 1,000 nodes is a decent sized network yet still entirely possible. If we were to say a "node" could be a container then the 1,000 number becomes not only feasible, but entirely likely even for small to medium distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Requirements
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;ping&lt;/code&gt; (ICMP message) is an 8 byte header plus some payload size. On Linux the packet size is 64 bytes by default, although we also need to include the IP and Ethernet header size as well which adds another 40 bytes (assuming IPv4).&lt;br&gt;
Keep in mind many real world scenarios use additional encapsulation such as tunnels or application layer messages that add more overhead. But let's assume the simple scenario of ~100 bytes per message, or 200 bytes network traffic round trip.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-001.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-001.svg" alt="Fig. 01" width="356" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this rate, a single node conducting a latency check against all other 999 nodes would require about 200KB network traffic round trip. This doesn't sound too bad yet, is probably why this solution gets picked so often.&lt;/p&gt;

&lt;p&gt;However, all other nodes still need to do the same check.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-002.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-002.svg" alt="Fig. 02" width="356" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lets further assume symmetrical results, meaning if &lt;code&gt;A&lt;/code&gt; does a check with &lt;code&gt;B&lt;/code&gt; then &lt;code&gt;B&lt;/code&gt; doesn't need to do a check with &lt;code&gt;A&lt;/code&gt; and just reuse &lt;code&gt;A&lt;/code&gt;'s result.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
Symmetrical results is close, but not actually that realistic for real world&lt;br&gt;
network latencies as packets can take different routes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this change our total isn't &lt;code&gt;2KB * 1,000^2&lt;/code&gt; but instead &lt;code&gt;2KB * (1,000 + 999 + 998 ... 1)&lt;/code&gt; which is slightly better. Although, even this equals just under 1GB of traffic round trip for a single check.&lt;/p&gt;

&lt;p&gt;Because we're talking network latencies which are very unstable and subject to change over time as well as jitter a single latency check isn't very representative of actual network latencies.&lt;/p&gt;

&lt;p&gt;It's common to do several latency checks and take an average, say five checks (on the command line something like &lt;code&gt;ping -c5&lt;/code&gt;). And then one would repeat this test over time, such as every 30 minutes.&lt;/p&gt;

&lt;p&gt;At this rate (five ICMP messages every 30 minutes), we're in the range of 5GB of network traffic every 30 minutes, or 240GB a day just to be able to answer the question, "Which nodes are the closest."&lt;/p&gt;
&lt;h2&gt;
  
  
  Storage Requirements
&lt;/h2&gt;

&lt;p&gt;There's also storage considerations as well, which are admittedly less concerning, however let's briefly address it so we can compare to the Network Coordinate solution later.&lt;/p&gt;

&lt;p&gt;If we assume the "results" of this latency check are an integer, say four bytes, representing the average number of milliseconds round trip latency and a public IPv4 address as the node ID (another 4 bytes) it's around 8KB to store the entire map. This map is duplicated per node so around 8MB in total storage.&lt;/p&gt;

&lt;p&gt;Granted, a 4 byte result and 4 byte ID is about as small as it could be and real world requirements are probably much, much higher doing things such as keeping a history of results, or at least a sliding window, and using longer&lt;br&gt;
node IDs.&lt;/p&gt;
&lt;h1&gt;
  
  
  Network Coordinates
&lt;/h1&gt;

&lt;p&gt;So how would these Network Coordinates work, and why are they so much better?&lt;/p&gt;
&lt;h2&gt;
  
  
  Vivaldi
&lt;/h2&gt;

&lt;p&gt;The system we're discussing here is based on the &lt;a href="https://pdos.csail.mit.edu/papers/vivaldi:sigcomm/paper.pdf" rel="noopener noreferrer"&gt;Vivaldi Network Coordinates&lt;/a&gt; (PDF). Network coordinates function much like physical coordinates on a map. Two locations have some coordinate that represents their location.&lt;/p&gt;

&lt;p&gt;In physical space it's relatively simple to take two coordinates and determine how "close" the points are. Or back to our original problem, trivial to take a list of coordinates and determine which of those are the closest to any other given coordinate.&lt;/p&gt;

&lt;p&gt;Network coordinates are the same, except that they're trying to model a "location" not in physical space but within the network. Unlike physical space, the distance between two "locations" can fluctuate in network space because packets can take different routes, links could go down or become degraded, and we must account for jitter and spikes.&lt;/p&gt;

&lt;p&gt;Vivaldi takes the approach of giving each node a random euclidean coordinate using an N-dimensional coordinate. In physical space we may use a 2D or 3D coordinate, but in Vivaldi you're not limited physical dimensions. In fact,&lt;br&gt;
some research has gone in to picking an optimal number of dimensions for these coordinates. The more dimensions the more network traffic and storage requirements, but theoretically the more accurate as well.&lt;/p&gt;

&lt;p&gt;That "optimal" number appears to be around 8D, although in my anecdotal testing even 6D or 4D coordinates seem to be accurate enough for many scenarios.&lt;/p&gt;

&lt;p&gt;Let me briefly describe how Vivaldi works at a high level and what the code is doing under the hood.&lt;/p&gt;
&lt;h3&gt;
  
  
  How Does it Work?
&lt;/h3&gt;

&lt;p&gt;I said that each node starts with a randomly assigned coordinate. Each node will then conduct round trip latency checks and adjust their coordinate based off observed latency. The goal is for each node to adjust (or move) to a coordinate that accurately reflects it's position.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
"Each node conducts latency checks..." This sounds just as bad our naive&lt;br&gt;
solution! It's not I promise, this will become clear shortly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The way I think about this is for example in a 2D map, with two nodes, the goal is for each node to enter any coordinate where the calculated latency between the two nodes matches (or is within a margin of error) of the observed latency.&lt;/p&gt;

&lt;p&gt;Let's assume nodes &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; are physically 5ms round trip latency from one another. We start by giving them random coordinates (remember we're using 2D just to make this easy to visualize). I've added a dashed circle to represent any coordinate that give a correct distance estimate when comparing the two coordinates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-003.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-003.svg" alt="Fig. 03" width="628" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I've deliberately left out the actual coordinate numbers (i.e. (2,4), etc.) because the coordinates themselves are irrelevant and meaningless. The only meaning comes from comparing two sets within the same system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; do a latency check, observe real world latency and adjust their coordinates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-004.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-004.svg" alt="Fig. 04" width="632" height="989"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Node &lt;code&gt;B&lt;/code&gt; then does the same thing&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-005.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-005.svg" alt="Fig. 05" width="619" height="1007"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point the coordinates have been updated enough that a distance estimate between them is accurate with observed real world latency.&lt;/p&gt;

&lt;p&gt;Like I said in the note above, this doesn't look much better than the naive solution. And with only two nodes it's not.&lt;/p&gt;

&lt;p&gt;If we were to add a third node, let's see what happens. We'll repeat the above, except let's assume this new Node &lt;code&gt;C&lt;/code&gt; is also doing checks with &lt;code&gt;A&lt;/code&gt;, but has a real world latency of 10ms to &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-006.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-006.svg" alt="Fig. 06" width="649" height="1563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice all nodes are now accurate with observed latency.&lt;/p&gt;

&lt;p&gt;But wait! What is the distance between &lt;code&gt;B&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt;? For the sake of this post, and my diagramming skill, lets assume it's also 10ms.&lt;/p&gt;

&lt;p&gt;But then that means the coordinates aren't yet accurate! We need to do some more checking!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-007.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-007.svg" alt="Fig. 07" width="645" height="895"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the diagram a single check made everything accurate again. However, a real world update to &lt;code&gt;C&lt;/code&gt; could have well made it accurate for &lt;code&gt;B&lt;/code&gt; but now &lt;code&gt;A&lt;/code&gt; is not accurate so it needs to adjust, etc. etc.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Additionally, the direction of movement is calculated from the position of the remote, which the diagram doesn't accurately reflect because it would have made the sequence more confusing as stabilization can take many rounds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Error Estimates
&lt;/h3&gt;

&lt;p&gt;Additionally, Vivaldi gives a notion of an "error estimate" or how sure a node is that it's coordinates are accurate. At first, because the coordinates are random the error rate will be very high.&lt;/p&gt;

&lt;p&gt;When doing coordinate updates, if the remote node's error rate is high (it's not sure of it's accuracy) and the local rate is low (you're very sure of your own accuracy) you won't move much. But the inverse (you're not sure at all of your accuracy, but the remote is very sure) will result in your local coordinate updating a lot.&lt;/p&gt;

&lt;p&gt;This allows the coordinates to converge quickly on known good points, but then slowly once the results become more accurate.&lt;/p&gt;
&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;At this point it's looking like all nodes just need to do actual latency checks with all other nodes to have any shot at being accurate. This seems just as bad, if not worse than our naive solution! As we're doing latency checks anyways, why not just use those real latencies!&lt;/p&gt;

&lt;p&gt;This is what I alluded to at the beginning of the post about having a fancy version of the naive solution. Because all nodes start with random coordinates they need to conduct updates with more "stable" nodes (low error estimates) to&lt;br&gt;
converge on accurate results. Additionally, in large networks if the coordinate updates aren't conducted against shared stable nodes, you end up with "islands."&lt;/p&gt;

&lt;p&gt;For example, assume a network of six nodes (&lt;code&gt;A..F&lt;/code&gt;) where &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; are stable accurate coordinates. If &lt;code&gt;C&lt;/code&gt; and &lt;code&gt;D&lt;/code&gt; only update against &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;E&lt;/code&gt; and &lt;code&gt;F&lt;/code&gt; only update against &lt;code&gt;B&lt;/code&gt; you'll end up with two islands of coordinates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-008.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-008.svg" alt="Fig. 08" width="637" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can happen accidentally by relying on "random updates" where all nodes start random, and conduct updates against other nodes randomly or naturally as a side channel of regular communication. Some nodes will stabilize, while other&lt;br&gt;
nodes will not.&lt;/p&gt;

&lt;p&gt;To make matters worse, even if one of the nodes happens to conduct an observed check against another stable island (say &lt;code&gt;C&lt;/code&gt; against &lt;code&gt;B&lt;/code&gt; in our example, or even &lt;code&gt;C&lt;/code&gt; against &lt;code&gt;F&lt;/code&gt; once it's stabilized), that does not actually help &lt;code&gt;D&lt;/code&gt;, or &lt;code&gt;E&lt;/code&gt; at all unless they also start updating against other stable islands/nodes.&lt;/p&gt;

&lt;p&gt;As it turns out, the solution to this problem and the solution to orders of magnitude better performance is the same. Use a single &lt;strong&gt;Origin Node&lt;/strong&gt;, which all nodes conduct their observed latencies checks with. For example, if &lt;code&gt;A&lt;/code&gt; became the only origin node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-009.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkbknapp.dev%2Fimgs%2Fnet-coords-009.svg" alt="Fig. 09" width="637" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This does not preclude a node from checking against another node, but it's not required.&lt;/p&gt;
&lt;h1&gt;
  
  
  Lets Math Again
&lt;/h1&gt;

&lt;p&gt;We'll assume 8D coordinates, which is effectively a &lt;code&gt;[f64; 8]&lt;/code&gt; in Rust plus a few &lt;code&gt;f64&lt;/code&gt;'s of metadata like error estimates and jitter smoothing, in total 88 bytes per Vivaldi message as a payload, and we're free to use whichever protocol best serves our application, say UDP which like ICMP is 8 bytes. We also have our original overhead of 40 bytes for the IPv4 and Ethernet header.&lt;/p&gt;

&lt;p&gt;We add an origin node, so 1,001 nodes, and a single coordinate update for all nodes is about 272KB of traffic. Let's be fair and say we did five updates per node, so total network traffic for all nodes and those five updates is 1.36MB. Even if we did this every 30 minutes, that's only 65.28MB per day (versus our 240GB+ in the naive solution).&lt;/p&gt;
&lt;h1&gt;
  
  
  Real Power
&lt;/h1&gt;

&lt;p&gt;However, it's not just more efficient by network traffic standards. The &lt;em&gt;real power&lt;/em&gt; comes from any two nodes being able to estimate accurately their latency &lt;em&gt;without ever having observed any latency check between one-another!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the naive solution the only way to know what the latency between &lt;code&gt;E&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt; was, was to check it (over and over and over). However, in this new system &lt;code&gt;E&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt; need not ever have sent a single packet to each-other! We can just look&lt;br&gt;
at their two coordinates and perform a quick calculation.&lt;/p&gt;

&lt;p&gt;If the Origin stores all current coordinates (or even gossips them around to various local caches) we can just ask, "what are the N closest nodes to coordinate X?" at which point the origin can just zip through it's list of coordinates doing these calculations and give back a sorted list if desired!&lt;/p&gt;

&lt;p&gt;But how fast are these calculations?&lt;/p&gt;
&lt;h2&gt;
  
  
  Speed
&lt;/h2&gt;

&lt;p&gt;In my Rust Vivaldi implementation (called &lt;a href="https://github.com/kbknapp/violin" rel="noopener noreferrer"&gt;&lt;code&gt;violin&lt;/code&gt;&lt;/a&gt;), a single calculation of two 8D coordinates using stack memory on my 8 core AMD Ryzen 7 5850U laptop with 16GB RAM takes ~16.5ns. A benchmark of 1,000,000 calculations takes 16.5ms.&lt;/p&gt;
&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;I hope this post has given you some insight into how to efficiently get answers to questions like "network closeness." Using a Vivaldi based solution (&lt;em&gt;correctly&lt;/em&gt;!) can vastly improve distributed systems performance.&lt;/p&gt;

&lt;p&gt;If you're into Rust, check out &lt;code&gt;violin&lt;/code&gt;! As a quick sample, this is what it looks like to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;violin&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;heapless&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VecD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Coord&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Create two nodes and an "origin" coordinate, all using a 4-Dimensional&lt;/span&gt;
&lt;span class="c1"&gt;// coordinate. `VecD` is a dimensional vector.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Coord&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VecD&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;4&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="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VecD&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;4&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="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VecD&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;4&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="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// **conduct some latency measurement from a to origin**&lt;/span&gt;
&lt;span class="c1"&gt;// let's assume we observed a value of `0.2` seconds...&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// **conduct some latency measurement from b to origin**&lt;/span&gt;
&lt;span class="c1"&gt;// let's assume we observed a value of `0.03` seconds...&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="nf"&gt;.update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs_f64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.2&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;origin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="nf"&gt;.update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs_f64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.03&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;origin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Estimate from a to b even though we never measured them directly&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;"a's estimate to b: {:.2}ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="nf"&gt;.distance_to&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;b&lt;/span&gt;&lt;span class="nf"&gt;.coordinate&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.as_millis&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a bonus &lt;code&gt;violin&lt;/code&gt; also works in &lt;code&gt;no_std&lt;/code&gt; and no &lt;code&gt;alloc&lt;/code&gt; environments (but with some performance penalties due to lack of platform intrinsics).&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>devcyclechallenge</category>
      <category>learning</category>
      <category>community</category>
    </item>
    <item>
      <title>CLI Shell Completions in Rust</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Fri, 08 Jan 2021 19:09:35 +0000</pubDate>
      <link>https://dev.to/kbknapp/cli-shell-completions-in-rust-37g1</link>
      <guid>https://dev.to/kbknapp/cli-shell-completions-in-rust-37g1</guid>
      <description>&lt;p&gt;In this post we add shell completions to the XKCD CLI utility we made earlier. We'll show how easy it is to support multiple shells, and generate the completions both at compile time and/or run time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Completion Scripts
&lt;/h1&gt;

&lt;p&gt;Perhaps my biggest daily, "Ugh.." moment is working on the command line and typing &lt;code&gt;&amp;lt;TAB&amp;gt;&amp;lt;TAB&amp;gt;&lt;/code&gt; and getting no shell completion help. Even when I'm using a tool that I'm extremely familiar with, I still end up using shell completions (also called &lt;em&gt;tab&lt;/em&gt; completions) to discover new options or explore the flags further.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sometimes I simply forgot the exact syntax..."is it &lt;code&gt;--remove&lt;/code&gt; or &lt;code&gt;--delete&lt;/code&gt;...Oh right, on this tool it's &lt;code&gt;-rm&lt;/code&gt;"&lt;/p&gt;

&lt;p&gt;-- (눈_눈)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think we can agree shell completions are useful. So why don't all utilities provide shell completions? Probably because they're a giant pain to create, they must be kept in sync with the actual CLI flags/options, and there are a ton of shells to support!&lt;/p&gt;

&lt;p&gt;Imagine typing &lt;code&gt;foo --&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;&lt;/code&gt; and seeing &lt;code&gt;--directory&lt;/code&gt; was a valid option, only to hit &lt;code&gt;&amp;lt;return&amp;gt;&lt;/code&gt; and have the CLI tell you, &lt;code&gt;error: --directory option not found&lt;/code&gt; or similar. Turns out the CLI updated and is now using &lt;code&gt;--dir&lt;/code&gt;. Out of&lt;br&gt;
sync completions are terrible.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;clap&lt;/code&gt; to the rescue!
&lt;/h2&gt;

&lt;p&gt;I've got great news. Adding/supporting shell completions with your Rust based CLI is very easy! Using the &lt;a href="https://crates.io/crates/clap" rel="noopener noreferrer"&gt;&lt;code&gt;clap&lt;/code&gt;&lt;/a&gt; crate, we can generate shell completion scripts either at compile time, or provide a&lt;br&gt;
special option to allow users to generate shell completion scripts at run time on the fly. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Or both.&lt;/p&gt;

&lt;p&gt;-- (¬,‿,¬)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using generated completion scripts we get the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our completion scripts will always be in sync with our actual CLI options&lt;/li&gt;
&lt;li&gt;We can support Bash, Zsh, Fish, PowerShell, and Elvish using about five lines of code&lt;/li&gt;
&lt;li&gt;Using both compile time and run time gives our users options for how/where to use these scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Whats so hard?
&lt;/h2&gt;

&lt;p&gt;Before I said that creating shell completion scripts was hard, but how hard? A popular command line tool &lt;a href="https://github.com/BurntSushi/ripgrep" rel="noopener noreferrer"&gt;ripgrep&lt;/a&gt; which has a moderately large CLI space (not huge, but not trivial either) has a Bash completion script that is 213 lines lone (as of v12.1.1)! That's &lt;em&gt;just&lt;/em&gt; Bash. Other shells have similarly sized scripts. &lt;code&gt;rustup&lt;/code&gt; which has a fairly large CLI space has a 1,110 line Bash script.&lt;/p&gt;

&lt;p&gt;Enough preamble, get to the code!&lt;/p&gt;
&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;We'll be updating our &lt;a href="//../rust-cli/index.html"&gt;&lt;code&gt;grab-xkcd&lt;/code&gt; program from a previous&lt;br&gt;
post&lt;/a&gt; with the new code, but in order to clearly demonstrate the different methods and not conflict with the original article I will use two new branches&lt;br&gt;
&lt;a href="https://github.com/kbknapp/grab-xkcd/tree/completions-ct" rel="noopener noreferrer"&gt;&lt;code&gt;completions-ct&lt;/code&gt;&lt;/a&gt; for compile time completions, and&lt;br&gt;
&lt;a href="https://github.com/kbknapp/grab-xkcd/tree/completions-rt" rel="noopener noreferrer"&gt;&lt;code&gt;completions-rt&lt;/code&gt;&lt;/a&gt; for run time completions. If the reader is feeling froggy, you can combine the two!&lt;/p&gt;

&lt;p&gt;Let's start with compile time.&lt;/p&gt;
&lt;h1&gt;
  
  
  Compile Time Completions
&lt;/h1&gt;

&lt;p&gt;I tend prefer compile time completions because those completions scripts can be checked into version control, or even tweaked further from the auto-generated script. Originally, the auto-generated scripts were meant to be a starting point, but they turned out to work so well that almost no one takes the time to actually tweak them further.&lt;/p&gt;

&lt;p&gt;The downsides to the compile time method are that it requires two new "build dependencies" (meaning compile time), and can slow down compile times. Generally, this isn't an issue in practice as generating completion scripts is crazy fast. But, if you're very cautious with build times, or are trying to&lt;br&gt;
avoid compile time dependencies for some reason, the run time method may be better.&lt;/p&gt;

&lt;p&gt;Also, these scripts will still need to be consumed/installed by the user somehow. Normally this is done in a packaging format (deb, rpm, msi, exe, dmg, etc.). But if the CLI tool you're building does not have any packaging, the user will need to install these scripts manually based on the shell they're using.&lt;/p&gt;
&lt;h2&gt;
  
  
  Build Scripts
&lt;/h2&gt;

&lt;p&gt;The process of telling &lt;code&gt;clap&lt;/code&gt; to generate a completion script at compile time happens in a &lt;a href="https://doc.rust-lang.org/cargo/reference/build-scripts.html" rel="noopener noreferrer"&gt;&lt;code&gt;cargo&lt;/code&gt; build&lt;br&gt;
script&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The way completion scripts are generated changed between &lt;code&gt;clap&lt;/code&gt; v2 and the upcoming v3. In v3 (which we used in the previous article) moved the completion generating code to a separate crate to avoid code bloat. Since we're still using v3 we need to add that extra crate.&lt;/p&gt;
&lt;h2&gt;
  
  
  Build Dependencies
&lt;/h2&gt;

&lt;p&gt;We also need to tell &lt;code&gt;cargo&lt;/code&gt; that &lt;code&gt;clap_generate&lt;/code&gt; (and also &lt;code&gt;clap&lt;/code&gt;) is a build dependency. &lt;code&gt;clap&lt;/code&gt; proper will also remain a regular dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo add clap clap_generate --allow-prerelease --build
    Updating 'https://github.com/rust-lang/crates.io-index' index
      Adding clap_generate v3.0.0-beta.2 to build-dependencies
      Adding clap v3.0.0-beta.2 to build-dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we were to look at our &lt;code&gt;Cargo.toml&lt;/code&gt; we'd now see two &lt;code&gt;dependencies&lt;/code&gt; tables, with the new one being &lt;code&gt;[build-dependencies]&lt;/code&gt; listing the two crates above.&lt;br&gt;
[&lt;code&gt;[dependencies]&lt;/code&gt;] is unchanged, and still includes just normal &lt;code&gt;clap&lt;/code&gt; since that's still required to parse run time arguments.&lt;/p&gt;

&lt;p&gt;Next, since &lt;code&gt;clap_generate&lt;/code&gt; needs a&lt;br&gt;
&lt;a href="https://docs.rs/clap/3.0.0-beta.2/clap/struct.App.html" rel="noopener noreferrer"&gt;&lt;code&gt;clap::App&lt;/code&gt;&lt;/a&gt; instance in order to be able to walk our CLI and generate everything, we'll need to use&lt;br&gt;
the &lt;code&gt;into_app()&lt;/code&gt; method that was &lt;code&gt;#[derive]&lt;/code&gt;d on our &lt;code&gt;Args&lt;/code&gt; struct in the previous article.&lt;/p&gt;
&lt;h2&gt;
  
  
  Stubbing
&lt;/h2&gt;

&lt;p&gt;Let's first, stub out the &lt;code&gt;build.rs&lt;/code&gt; file in our project root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in build.rs&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Clap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;include!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/cli.rs"&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;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;into_app&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"generate the completion scripts!"&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 built &lt;code&gt;grab-xkcd&lt;/code&gt; as a binary, and not a library. So we need some way to include our &lt;code&gt;Args&lt;/code&gt; struct in this build script. We could have re-factored out the core logic into a library, and then consumed that library in our &lt;code&gt;main.rs&lt;/code&gt;&lt;br&gt;
binary...but that's overkill for this example. So we simply &lt;code&gt;include!()&lt;/code&gt; the source file directly, which is like a copy/paste.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generate Bash
&lt;/h2&gt;

&lt;p&gt;Now that we have an &lt;code&gt;App&lt;/code&gt; struct, we can pass that to &lt;code&gt;clap_generate&lt;/code&gt; and see the magic!&lt;/p&gt;

&lt;p&gt;Let's add a Bash completion script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in build.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap_generate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Bash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Clap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;include!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/cli.rs"&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;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;into_app&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="nf"&gt;.set_bin_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"grab-xkcd"&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;outdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;env!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CARGO_MANIFEST_DIR"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;generate_to&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Bash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outdir&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;There is a paper-cut that we have to call &lt;code&gt;set_bin_name()&lt;/code&gt; due to some complexities about how the derive magic works, and how it interacts with what &lt;code&gt;generate_to&lt;/code&gt; expects. The short version is &lt;code&gt;generate_to&lt;/code&gt; is written to handle a large swath of CLI types, some of which may have different binary names, than program names (i.e. ripgrep-&lt;code&gt;rg&lt;/code&gt;). Completion scripts are normally based off the binary name (which is how shells find which scripts to call). The &lt;code&gt;derive&lt;/code&gt; magic in &lt;code&gt;clap&lt;/code&gt; has no way of knowing the binary name, as our binary is certainly not called &lt;code&gt;Args&lt;/code&gt;. We could have set the binary name as part of our &lt;code&gt;Args&lt;/code&gt; declaration, which is probably the right way to do it in the long run, but for this demo it's overkill. So we just set it manually on the instance of the &lt;code&gt;App&lt;/code&gt; struct and move on.&lt;/p&gt;

&lt;p&gt;Walking through the rest of the above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We import a single
&lt;a href="https://docs.rs/clap_generate/3.0.0-beta.2/clap_generate/trait.Generator.html" rel="noopener noreferrer"&gt;&lt;code&gt;Generator&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;Bash&lt;/code&gt; which will walk our &lt;code&gt;App&lt;/code&gt; struct and generate all options.&lt;/li&gt;
&lt;li&gt;We get the value of &lt;code&gt;cargo&lt;/code&gt;'s environmental variable &lt;code&gt;CARGO_MANIFEST_DIR&lt;/code&gt; which is our source root and where we will be saving the script to.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;generate_to&lt;/code&gt; we must provide some generic arguments. The first is the most important, and is the &lt;code&gt;Generator&lt;/code&gt; that will be used to make the completion script. The other two are related to the other two final function arguments and just convenience conversion traits. Rust can infer them, hence the &lt;code&gt;_&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The arguments are:

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;App&lt;/code&gt; struct to walk over&lt;/li&gt;
&lt;li&gt;The binary name to use throughout the script (which may differ from the real
binary name in some special circumstances)&lt;/li&gt;
&lt;li&gt;A path directory to save the generated file to&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;That's it! If we look in our project root, you should see a &lt;code&gt;grab-xkcd.bash&lt;/code&gt;! Even our super small CLI has generated a 65 line script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wc -l grab-xkcd.bash
65 grab-xkcd.bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the head you can see some of the boilerplate already:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ head grab-xkcd.bash
_grab-xkcd() {
    local i cur prev opts cmds
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    cmd=""
    opts=""

    for i in ${COMP_WORDS[@]}
    do

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;So let's try it out! We can test it by just &lt;code&gt;source&lt;/code&gt;ing it, if you're using &lt;code&gt;bash&lt;/code&gt; as your shell:&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%2Fkbknapp.dev%2Fimgs%2Fshell_completions_ct.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_completions_ct.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works!&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Cleanup
&lt;/h2&gt;

&lt;p&gt;If we wanted to add additional shells it's just more calls to &lt;code&gt;generate_to&lt;/code&gt;. We'll actually, place all the scripts in a new &lt;code&gt;completions/&lt;/code&gt; dir in our project root, so as not to get unwieldy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we update our build script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in build.rs&lt;/span&gt;
&lt;span class="c1"&gt;// Same as before...&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap_generate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generate_to&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;let&lt;/span&gt; &lt;span class="n"&gt;outdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;env!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CARGO_MANIFEST_DIR"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"completions/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;generate_to&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Bash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;outdir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;generate_to&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Fish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;outdir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;generate_to&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Zsh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;outdir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;generate_to&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PowerShell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;outdir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;generate_to&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Elvish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;outdir&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 had to create a new &lt;code&gt;Path&lt;/code&gt; and &lt;code&gt;join&lt;/code&gt; it to our new directory, but that's not too bad. We also had to take a reference to &lt;code&gt;outdir&lt;/code&gt; in each call to &lt;code&gt;generate_to&lt;/code&gt; since we're not passing a &lt;code&gt;PathBuf&lt;/code&gt; and not a &lt;code&gt;&amp;amp;'static str&lt;/code&gt; any&lt;br&gt;
longer. But hey, notice we didn't need to do anything else special and &lt;code&gt;generate_to&lt;/code&gt; could handle those two totally different types with ease (thanks to the second &lt;code&gt;_&lt;/code&gt; generic parameter which is actually a &lt;code&gt;T: Into&amp;lt;OsString&amp;gt;&lt;/code&gt; for those that care).&lt;/p&gt;

&lt;p&gt;If we look in our &lt;code&gt;completions/&lt;/code&gt; dir, yup, we see a bunch of new completion scripts!&lt;/p&gt;
&lt;h1&gt;
  
  
  Run time
&lt;/h1&gt;

&lt;p&gt;Ok, so compile time was pretty easy. Maybe a little fuss around adding build-dependencies and making a build script, but overall not too bad.&lt;/p&gt;

&lt;p&gt;But let's say you're just making a small CLI, and don't want to have to worry about packaging or installing completions scripts with your program, etc. Luckily, we can have our binary just spit out completion scripts on demand to&lt;br&gt;
stdout! Then the user can source the output if they want, or redirect it to a file if they want to "install" it.&lt;/p&gt;

&lt;p&gt;A traditional way of doing this may have included inserting the completion scripts themselves into your binary file statically...which would probably be terrible (even though they compress well). This still runs the risk of getting&lt;br&gt;
out of sync with your CLI, etc.&lt;/p&gt;

&lt;p&gt;Let's use what we learned with the compile time completion scripts, but just do it at run time instead.&lt;/p&gt;
&lt;h2&gt;
  
  
  Extend the CLI
&lt;/h2&gt;

&lt;p&gt;In order to do this, we'll actually need to extend our CLI a little bit to include a new option/flag for generating these completions. I normally advocate for using subcommands instead of options/flags, but since our CLI is so small and we don't have any other subcommands we'll forgo that idea. Instead we'll add a &lt;code&gt;-c/--completions&lt;/code&gt; option which accepts any of the supported shells and spits out the completion script to stdout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// A utility to grab XKCD comics&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clap)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Args&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// .. Same as before&lt;/span&gt;

    &lt;span class="cd"&gt;/// Generate a SHELL completion script and print to stdout&lt;/span&gt;
    &lt;span class="nd"&gt;#[clap(long,&lt;/span&gt; &lt;span class="nd"&gt;short,&lt;/span&gt; &lt;span class="nd"&gt;arg_enum,&lt;/span&gt; &lt;span class="nd"&gt;value_name=&lt;/span&gt;&lt;span class="s"&gt;"SHELL"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;completions&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;Shell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Clap,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;Clone)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Shell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Bash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Zsh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Fish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PowerShell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Elvish&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should look pretty familiar to you from the previous article, however let's step through it really quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;short, long&lt;/code&gt; we tell &lt;code&gt;clap&lt;/code&gt; to generate a short &lt;code&gt;-c&lt;/code&gt; and long &lt;code&gt;--completions&lt;/code&gt; automatically from the name of the field&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;arg_enum&lt;/code&gt; tells &lt;code&gt;clap&lt;/code&gt; the enum we are using should be used as the only allowed value variants&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;value_name="SHELL"&lt;/code&gt; tells &lt;code&gt;clap&lt;/code&gt; to replace the default placeholder in the &lt;code&gt;--help&lt;/code&gt; message from &lt;code&gt;--completions &amp;lt;completions&amp;gt;&lt;/code&gt; which is just derived  from the field name, to &lt;code&gt;--completions &amp;lt;SHELL&amp;gt;&lt;/code&gt;. It's not required, but I  think it helps readability.&lt;/li&gt;
&lt;li&gt;We create our enum with the variants we wish to support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;--completions&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;With that out of the way we can now look at using this new argument. In our &lt;code&gt;main()&lt;/code&gt; function we will check if that argument was used, and if so generate the script and print to stdout and exit.&lt;/p&gt;

&lt;p&gt;Since we'll need to know which shell to generate our completions for, we can push that logic to the enum itself and keep our &lt;code&gt;main()&lt;/code&gt; function clean.&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="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="py"&gt;.completions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="nf"&gt;.generate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;process&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;client&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;XkcdClient&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could be condensed into a single  &lt;code&gt;args.completions.map(..)&lt;/code&gt;, but for this demo we'll leave it as is since the function is so short and concise anyways. I&lt;br&gt;
also like that the &lt;code&gt;std::process::exit&lt;/code&gt; function is visible so we know this could end execution of our program just from looking at &lt;code&gt;main&lt;/code&gt;. If we were to reduce this to a &lt;code&gt;map&lt;/code&gt; we'd probably also rename the enum's &lt;code&gt;generate&lt;/code&gt; method to something like &lt;code&gt;generate_and_exit&lt;/code&gt; to make it more clear as well. But I digress.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;clap_generate::generate&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of the &lt;code&gt;clap_generate::generate_to&lt;/code&gt; that was used in compile time, we'll be using &lt;code&gt;clap_generate::generate&lt;/code&gt; inside our &lt;code&gt;Shell::generate&lt;/code&gt; method. First let's add &lt;code&gt;clap_generate&lt;/code&gt; to our normal run time dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo add clap_generate --allow-prerelease
    Updating 'https://github.com/rust-lang/crates.io-index' index
      Adding clap_generate v3.0.0-beta.2 to dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can actually implement &lt;code&gt;Shell::generate&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in src/cli.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Clap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IntoApp&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap_generate&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Shell&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;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;into_app&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Bash&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Bash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;fd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zsh&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Zsh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;fd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Fish&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Fish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;fd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PowerShell&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PowerShell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;fd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Elvish&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Elvish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"grab-xkcd"&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;fd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A mouthful of a &lt;code&gt;match&lt;/code&gt; but on closer inspection isn't too bad.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We create the &lt;code&gt;clap::App&lt;/code&gt; struct from our CLI just like in the compile time version&lt;/li&gt;
&lt;li&gt;We get a reference to the stdout buffer which implements the &lt;code&gt;std::io::Write&lt;/code&gt; trait that &lt;code&gt;clap_generate::generate&lt;/code&gt; is expecting.&lt;/li&gt;
&lt;li&gt;We match on our shell type, and then pass on to the real &lt;code&gt;generate&lt;/code&gt; function&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing them out
&lt;/h2&gt;

&lt;p&gt;With that all wired up, it's time for a test!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grab-xkcd --completions bash | head
_grab-xkcd() {
    local i cur prev opts cmds
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    cmd=""
    opts=""

    for i in ${COMP_WORDS[@]}
    do
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks the same as before! I bet we can &lt;code&gt;source&lt;/code&gt;/&lt;code&gt;eval&lt;/code&gt; it.&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%2Fkbknapp.dev%2Fimgs%2Fshell_completions_rt.gif" 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%2Fkbknapp.dev%2Fimgs%2Fshell_completions_rt.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yay!&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap Up
&lt;/h1&gt;

&lt;p&gt;In this article we've seen how we can add shell completion scripts for various shells with relative ease. We've seen both completion scripts generated at compile time, and run time.&lt;/p&gt;

&lt;p&gt;It's totally possible to implement both strategies as well.&lt;/p&gt;

&lt;p&gt;In all honesty, one could mock existing CLIs &lt;em&gt;not&lt;/em&gt; written in Rust, and simply generate completion scripts for them using this method.&lt;/p&gt;

&lt;p&gt;Again, the complete code from this article can be found on the two branches: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile time: &lt;a href="https://github.com/kbknapp/grab-xkcd/tree/completions-ct" rel="noopener noreferrer"&gt;&lt;code&gt;completions-ct&lt;/code&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Run time: &lt;a href="https://github.com/kbknapp/grab-xkcd/tree/completions-rt" rel="noopener noreferrer"&gt;&lt;code&gt;completions-rt&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>cli</category>
      <category>programming</category>
      <category>shell</category>
    </item>
    <item>
      <title>Rust RedBPF Networking (Part 4)</title>
      <dc:creator>Kevin K.</dc:creator>
      <pubDate>Tue, 05 Jan 2021 17:55:44 +0000</pubDate>
      <link>https://dev.to/kbknapp/current-redbpf-networking-di3</link>
      <guid>https://dev.to/kbknapp/current-redbpf-networking-di3</guid>
      <description>&lt;h1&gt;
  
  
  Current lay of the land
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Before we start I need to disclaim that this post/series is &lt;em&gt;NOT&lt;/em&gt;//&lt;em&gt;NOT&lt;/em&gt; a critique of &lt;code&gt;redbpf-*&lt;/code&gt;! This is simply my observations for my own use case, with ideas for improvement. The developers of RedBPF are extremely professional, and my going back and forth with them over chat I can assure you they are also extremely proficient and running laps around me at low level code (especially when it comes to things like LLVM code generation and other topics that make the hair on the back of my neck stand up!).&lt;/p&gt;

&lt;p&gt;First, we need to acknowledge what our state of affairs is, and what our goals should be before we can address whether or not our goals are being met and if we can improve on methods to achieve them.&lt;/p&gt;

&lt;p&gt;Let's look at how it currently works under the hood. We will be spending 99% of our time in &lt;code&gt;redbpf-probes&lt;/code&gt; because that's where the majority of the networking code lives. We may hop over to the companion crate &lt;code&gt;redbpf-macros&lt;/code&gt; for a brief time since although a companion it's basically essential to using the networking modules in &lt;code&gt;redbpf-probes&lt;/code&gt;. Once we get a feel for where we are we'll have a better idea of any shortcomings, if any. If we do find areas we'd like to modify I won't mention any specific changes I'd make just yet, and will wait until I'm done walking through the current implementation so as not to get side tracked down any rabbit holes with possible details on implementation ideas.&lt;/p&gt;

&lt;h1&gt;
  
  
  XDP Entry Point
&lt;/h1&gt;

&lt;p&gt;Like all good programs, we must start somewhere. Unlike a traditional binary that we'd execute on the host machine, BPF programs don't usually have a &lt;code&gt;main()&lt;/code&gt; function. Instead, we have various code sections of the ELF binary that the kernel will run directly, which is typically a function (or multiple&lt;br&gt;
functions that have been inlined into a single function) of some form. This means we only need to define a function with a correct signature, and tell the kernel where it's located in the final ELF binary. &lt;/p&gt;

&lt;p&gt;In &lt;code&gt;redbpf-probes&lt;/code&gt; we define our entry point function by tagging it with the attribute &lt;code&gt;#[xdp]&lt;/code&gt;. This attribute is a procedural macro that performs a few useful tasks.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;#[xdp]&lt;/code&gt; macro is defined in &lt;code&gt;redbpf-macros&lt;/code&gt;. Of the tasks it performs for us, perhaps most importantly it &lt;a href="https://github.com/redsift/redbpf/blob/9e1d5b36066d0df3a0b1962a1526c79c3109ca05/redbpf-macros/src/lib.rs#L356-L374" rel="noopener noreferrer"&gt;wraps our user function&lt;/a&gt; in an outer function with the correct kernel BPF API. &lt;/p&gt;

&lt;p&gt;It then places this outer function in a particular ELF section (the section name &lt;code&gt;xdp/foo&lt;/code&gt; [where &lt;code&gt;foo&lt;/code&gt; is our inner function] is used arbitrarily). Next this macro takes the kernel context pointer which is a raw pointer (&lt;code&gt;*mut&lt;/code&gt;) to an&lt;br&gt;
&lt;code&gt;xdp_md&lt;/code&gt; struct and wraps it in a more friendly &lt;code&gt;redbpf-probes&lt;/code&gt; type before handing that to &lt;em&gt;our&lt;/em&gt; inner function. The new type is called &lt;code&gt;XdpContext&lt;/code&gt; which is the actual value that gets passed to our inner function. This new type allows&lt;br&gt;
&lt;code&gt;redbpf-probes&lt;/code&gt; to implement additional methods and functionality on top of the raw pointer handed out by the kernel. &lt;/p&gt;

&lt;p&gt;The outer XDP function also takes the return value we (inner function) finish with and performs a &lt;code&gt;match&lt;/code&gt; on it, turning this value into something BPF can understand. It's worth noting that if we return an &lt;code&gt;Err&lt;/code&gt; variant, it will get&lt;br&gt;
translated into &lt;code&gt;XdpAction::Pass&lt;/code&gt; (accept packet and continue up the networking stack).&lt;/p&gt;

&lt;p&gt;If you're not into procedural macros, no worries the simplified expansion of our &lt;code&gt;#[xdp]&lt;/code&gt; marked function &lt;code&gt;foo()&lt;/code&gt; is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="nd"&gt;#[link_section&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"xdp/foo"&lt;/span&gt;&lt;span class="nd"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;outer_xdp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;xdp_md&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;XdpAction&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;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XdpContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&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;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&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;XdpAction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Pass&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;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;XdpContext&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;XdpResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// our code here ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this post we'll dive into all the pieces that make up the above expansion, as well as the components that make up our example BPF program from Part 3 as well.&lt;/p&gt;

&lt;p&gt;First up, let's start with that new type &lt;code&gt;XdpContext&lt;/code&gt; given to us by the outer function.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;XdpContext&lt;/code&gt; struct
&lt;/h2&gt;

&lt;p&gt;At the beginning of &lt;em&gt;our&lt;/em&gt; inner function, we're given an instance of &lt;code&gt;XdpContext&lt;/code&gt; where the inner value is pointer to a binding of a C struct &lt;a href="https://ingraind.org/api/redbpf_probes/bindings/struct.xdp_md.html" rel="noopener noreferrer"&gt;&lt;code&gt;xdp_md&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
The &lt;code&gt;xdp_md&lt;/code&gt; struct contains a couple of values that'll we'll be interested in, but only two are used in &lt;code&gt;redbpf-probes&lt;/code&gt;, the &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;data_end&lt;/code&gt; fields which are addresses in memory (not pointers) for the beginning and end of the packet&lt;br&gt;
memory.&lt;/p&gt;

&lt;p&gt;This means the &lt;code&gt;XdpContext&lt;/code&gt; struct wraps a pointer, which itself contains "pointers" directly to packet memory. Unlike other contexts we'll see later on, the memory addresses within the range pointed to by these fields is directly&lt;br&gt;
mutable.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;XdpContext&lt;/code&gt; struct doesn't provide a whole lot on top of the &lt;code&gt;xdp_md&lt;/code&gt; struct, just a method to retrieve the inner raw pointer to the &lt;code&gt;xdp_md&lt;/code&gt; struct. It &lt;em&gt;does&lt;/em&gt; however implement a trait that lets us do a lot more with that memory.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;NetworkBuffer&lt;/code&gt; trait.&lt;/p&gt;

&lt;h1&gt;
  
  
  The &lt;code&gt;NetworkBuffer&lt;/code&gt; trait
&lt;/h1&gt;

&lt;p&gt;The current design of the networking portions of&lt;code&gt;redbpf-probes&lt;/code&gt; in a way revolves around the trait &lt;code&gt;NetworkBuffer&lt;/code&gt;. Its purpose is to represent abstract functionality for any buffer of network memory as described by two memory addresses (for the beginning and end of the buffer).&lt;/p&gt;

&lt;p&gt;This trait allows a type to implement accessing raw pointers and memory of the buffer (with some basic bounds checking math), and also some convenience methods for retrieving pointers to specific header structs that may be contained&lt;br&gt;
in the buffer itself. This is all done via pointer arithmetic to increase or decrease the addresses of either the beginning or end of buffer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wait, what is a network packet?
&lt;/h1&gt;

&lt;p&gt;Let's take quick step back and look at what a network packet is made of first.&lt;/p&gt;

&lt;p&gt;You can think of a network packet as a "header" followed by a "body/payload".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I use the terms body and payload interchangeably. As well as the terms header and prefix.&lt;/p&gt;

&lt;p&gt;-- ¯\&lt;em&gt;(ツ)&lt;/em&gt;/¯&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The header lays out a very strict set of packed fields/values along with their byte offsets. In this way we can pack as much information into as few bytes as possible without having to waste space (bandwidth) on sending "useless" data such as things like padding. Directly after the header starts that particular packet type's body.&lt;/p&gt;

&lt;p&gt;The body, is many times an encapsulated header of another type, along with another inner body. These header/body encapsulations can continue for an arbitrary depth until you reach the final body/payload which is the application&lt;br&gt;
data being transmitted.&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%2Fkbknapp.dev%2Fimgs%2Febpf_09.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%2Fkbknapp.dev%2Fimgs%2Febpf_09.png" alt="fig. 04"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Headers can be various sizes depending on the protocol they're representing, and almost all of them have varying fields. The total packet size (so all the headers + the final body) is limited by the Maximum Transmission Unit (MTU) for&lt;br&gt;
a given network medium. For example with Ethernet and it's family that is 1500 bytes. So we can't really just recursively encapsulate forever, or we'd not have any room left for the actual application data.&lt;/p&gt;

&lt;p&gt;If we have application data that is too large for the space left (after all headers have been encapsulated) that data can be broken up into multiple network packets at either the application level (which is preferred), or the network level (known as packet fragmenting).&lt;/p&gt;

&lt;p&gt;There are also minimum packet sizes, such as 64 bytes for Ethernet, so there are instances were we could end up adding padding of some sort to the final body if the application data was extremely small.&lt;/p&gt;

&lt;p&gt;All this talk of "levels" means I should bring up the &lt;a href="https://en.wikipedia.org/wiki/OSI_model" rel="noopener noreferrer"&gt;OSI networking model&lt;/a&gt;; which defines nice delineations of responsibilities for a typical network packet. When creating a network packet&lt;br&gt;
(i.e. the bytes are being written to a buffer by the application or OS) it's standard to first have a "layer 2" header, followed by a "layer 3" header, and finally a "layer 4" header whose &lt;em&gt;body&lt;/em&gt; contains the application data. &lt;/p&gt;

&lt;p&gt;If you're not familiar with that model, it's OK, it's just to say for example an Ethernet packet will encapsulate a IPv4 packet, which will encapsulate a TCP packet, who will encapsulate the application data. The layers just refer to how the model stacks the protocols and where they fit in the abstraction stack.&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%2Fkbknapp.dev%2Fimgs%2Febpf_10.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%2Fkbknapp.dev%2Fimgs%2Febpf_10.png" alt="fig. 04"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above image "packet" can be confusing because the term is overloaded, but it only refers to "layer 3" protocols. Also note that layer 1, "physical" is the actual bits on the wire and not something we are concerned with while parsing&lt;br&gt;
network packets. We're primarily concerned with layers 2 through 4, and final body/payload which makes up layers 5 through 7 which the application is responsible for.&lt;/p&gt;

&lt;h1&gt;
  
  
  Accessing Raw Headers in a &lt;code&gt;NetworkBuffer&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;When we have a raw network buffer, we'll most likely want to find out what the first header is, so we can start to do some further parsing.&lt;/p&gt;

&lt;p&gt;At least for the first header, we can make an educated guess at type of header based off the network medium the packet is coming from. For example, if we're attaching this XDP program to an ethernet NIC, chances are good (if not certain) the packet's first header is an &lt;a href="https://ingraind.org/api/redbpf_probes/net/trait.NetworkBuffer.html#method.eth" rel="noopener noreferrer"&gt;Ethernet (802.3) header&lt;/a&gt;. Likewise, if we're attaching this XDP program to a wireless NIC, chances are&lt;br&gt;
good (if not certain) the first header will be an &lt;a href="https://en.wikipedia.org/wiki/802.11_Frame_Types" rel="noopener noreferrer"&gt;802.11 header for Wireless LAN&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;redbpf-probes&lt;/code&gt; currently only supports Ethernet (802.3) out of the box, one would have to parse the bytes as another header type manually.&lt;/p&gt;

&lt;p&gt;For example, the trait provides &lt;code&gt;NetworkBuffer::eth&lt;/code&gt; which returns &lt;code&gt;Option&amp;lt;*const ethhdr&amp;gt;&lt;/code&gt; by trying to interpret the first few bytes of the buffer as an Ethernet (802.3) header and gives back a raw constant pointer on success or an &lt;code&gt;Err&lt;/code&gt; otherwise.&lt;/p&gt;

&lt;p&gt;But what constitutes success? Currently, the only way to fail this is &lt;em&gt;not&lt;/em&gt; if the packet does not contain an Ethernet header, but instead if the packet buffer is too small to contain an Ethernet header. So long as the packet contains&lt;br&gt;
enough bytes to hold an Ethernet header, the bytes will be interpreted as an Ethernet header (&lt;code&gt;*const ethhdr&lt;/code&gt;) regardless of what the actual bytes were supposed to represent.&lt;/p&gt;

&lt;p&gt;This means validation of any kind is left to the caller.&lt;/p&gt;

&lt;p&gt;Other methods on the trait do similar, such as &lt;code&gt;NetworkBuffer::ip&lt;/code&gt; which assumes the first few bytes of the buffer are an ethernet header, then tries to parse the next few bytes as an &lt;a href="https://en.wikipedia.org/wiki/IPv4#Header" rel="noopener noreferrer"&gt;IPv4 header&lt;/a&gt; giving out a raw constant pointer on success.&lt;/p&gt;

&lt;p&gt;This method &lt;a href="https://github.com/redsift/redbpf/blob/38b69273e4eb2cf2078f69b7ae055bc625dd505b/redbpf-probes/src/net.rs#L133-L135" rel="noopener noreferrer"&gt;does a little bit of validation&lt;/a&gt;, because as part of the Ethernet header, there is a field that lists the encapsulated packet type. If the field is anything other than IPv4, an &lt;code&gt;Err&lt;/code&gt; is&lt;br&gt;
returned. Like the &lt;code&gt;NetworkBuffer::eth&lt;/code&gt; method, having a packet that is too small to contain both an Ethernet and IPv4 header will be considered invalid and return &lt;code&gt;None&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;Further down the list we see two interesting methods, as they don't return raw pointers (at least on first glance);&lt;br&gt;
&lt;a href="https://ingraind.org/api/redbpf_probes/net/trait.NetworkBuffer.html#method.transport" rel="noopener noreferrer"&gt;&lt;code&gt;NetworkBuffer::transport&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://ingraind.org/api/redbpf_probes/net/trait.NetworkBuffer.html#method.data" rel="noopener noreferrer"&gt;&lt;code&gt;NetworkBuffer::data&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transport Headers
&lt;/h2&gt;

&lt;p&gt;We'll first look at &lt;code&gt;NetworkBuffer::transport&lt;/code&gt; which we're using in the example code in Part 3. It returns an &lt;a href="https://ingraind.org/api/redbpf_probes/net/enum.Transport.html" rel="noopener noreferrer"&gt;enum where each variant is a tuple struct with an inner value of a raw constant pointer to some type of transport protocol header (such as TCP or UDP)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This enum provides access methods to both source and destination ports since both TCP and UDP utilize such.&lt;/p&gt;

&lt;p&gt;Like the &lt;code&gt;NetworkBuffer::ip&lt;/code&gt; method, it also uses the built in IPv4 header fields to determine which type of packet it is encapsulating, and returns the appropriate variant, as well as the standard size checking like all previous methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Payload Data
&lt;/h2&gt;

&lt;p&gt;Finally, &lt;code&gt;NetworkBuffer::data&lt;/code&gt; returns a new struct we haven't seen yet called &lt;a href="https://ingraind.org/api/redbpf_probes/net/struct.Data.html" rel="noopener noreferrer"&gt;&lt;code&gt;Data&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; which&lt;br&gt;
represents a packet payload after all the known headers. An interesting note about &lt;code&gt;Data&amp;lt;T&amp;gt;&lt;/code&gt; is that it's generic over some type &lt;code&gt;T&lt;/code&gt; that implements &lt;code&gt;NetworkBuffer&lt;/code&gt;, which is essentially &lt;code&gt;XdpContext&lt;/code&gt; or &lt;code&gt;SkBuff&lt;/code&gt; (which we haven't&lt;br&gt;
discussed quite yet, but will shortly).&lt;/p&gt;

&lt;p&gt;Also, the way a &lt;code&gt;Data&amp;lt;T&amp;gt;&lt;/code&gt; is created is by first matching on the &lt;code&gt;NetworkBuffer::transport&lt;/code&gt; return, and then calculating a base address of the payload after the headers. If you'll remember from just a moment ago, to get the &lt;code&gt;Transport&lt;/code&gt; enum, we first make the assumption that the packet contains an&lt;br&gt;
Ethernet and IPv4 header.&lt;/p&gt;

&lt;p&gt;The type &lt;code&gt;Data&amp;lt;T&amp;gt;&lt;/code&gt; itself provides a few basic methods for getting the current offset from the base of the packet memory, viewing this data as a Rust slice, and perhaps most interestingly reading raw bytes into a &lt;code&gt;NetworkBufferArray&lt;/code&gt;. As it turns out &lt;code&gt;NetworkBufferArray&lt;/code&gt; is just a marker trait for byte arrays of &lt;a href="https://ingraind.org/api/src/redbpf_macros/lib.rs.html#147-153" rel="noopener noreferrer"&gt;512 bytes or smaller&lt;/a&gt; (and is our second/final tiny dip into &lt;code&gt;redbpf-macros&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursive Packets
&lt;/h2&gt;

&lt;p&gt;It's important to note that &lt;code&gt;Data&amp;lt;T&amp;gt;&lt;/code&gt; requires that &lt;code&gt;T&lt;/code&gt; implement &lt;code&gt;NetworkBuffer&lt;/code&gt;. In theory this should allow us to parse recursive packets which is something is somewhat common in network traffic. A recursive packet is instead of the traditional Layer 2 containing Layer 3 which contains Layer 4 (as I'll abbreviate &lt;code&gt;L2-&amp;gt;L3-&amp;gt;L4&lt;/code&gt;, where &lt;code&gt;-&amp;gt;&lt;/code&gt; means "contains" or "encapsulates), a layer contains either another header of the same layer, or potentially even a layer above itself. For example, where a TCP payload contains another TCP header, or an IPv6 payload contains an IPv4 header (which then contains&lt;br&gt;
something like a UDP header, etc. etc.).&lt;/p&gt;

&lt;p&gt;However, while parsing down the headers past the first layer 4 header (i.e. TCP or UDP), there doesn't seem to be an easy way to get a new &lt;code&gt;NetworkBuffer&lt;/code&gt; of just the payload region where all the pointer addresses are pointing to the new&lt;br&gt;
"base" (i.e. what was the payload) so that we can continue to parse headers. And even if there were, because the current implementation assumes the headers are strictly &lt;code&gt;L2-&amp;gt;L3-&amp;gt;L4&lt;/code&gt;, there is not easy way (i.e. not manual) to parse a packet&lt;br&gt;
that is something like &lt;code&gt;L2-&amp;gt;L3-&amp;gt;L4-&amp;gt;L4&lt;/code&gt; or even &lt;code&gt;L2-&amp;gt;L3-&amp;gt;L3-&amp;gt;L4-&amp;gt;L4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, the &lt;code&gt;L2-&amp;gt;L3-&amp;gt;L4-&amp;gt;L4&lt;/code&gt; mentioned above, may look like this if the packet was a "TCP in TCP" packet (Note, this is &lt;a href="http://sites.inka.de/sites/bigred/devel/tcp-tcp.html" rel="noopener noreferrer"&gt;generally a bad idea&lt;/a&gt;...but sometimes things like this are required or unavoidable):&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%2Fkbknapp.dev%2Fimgs%2Febpf_11.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%2Fkbknapp.dev%2Fimgs%2Febpf_11.png" alt="fig. 04"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  SkBuff
&lt;/h1&gt;

&lt;p&gt;The final piece to talk about is &lt;a href="https://ingraind.org/api/redbpf_probes/socket/struct.SkBuff.html" rel="noopener noreferrer"&gt;&lt;code&gt;SkBuff&lt;/code&gt;&lt;/a&gt; which is the sibling to &lt;code&gt;XdpContext&lt;/code&gt; except for Socket or TC BPF programs. Instead of a &lt;code&gt;*mut xdp_md&lt;/code&gt;, it wraps a &lt;code&gt;*const __sk_buff&lt;/code&gt;. If you'll glance back&lt;br&gt;
at part 2, &lt;code&gt;__sk_buff&lt;/code&gt; is the struct context that is created once the kernel has done some basic parsing of the packet data, and allocated some memory to hold a &lt;code&gt;sk_buff&lt;/code&gt; struct (Socket Buffer). BPF programs aren't given direct access to the packet memory anymore, and instead are given the &lt;code&gt;__sk_buff&lt;/code&gt; which mirrors the kernel's in memory &lt;code&gt;sk_buff&lt;/code&gt; struct. In order to mutate the contents of the actual packet, one must call the &lt;code&gt;bpf_skb_write_bytes&lt;/code&gt; helper function.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SkBuff&lt;/code&gt; struct provides one method, &lt;code&gt;SkBuff::load&lt;/code&gt; for reading raw bytes out of the internal buffer by offset.&lt;/p&gt;

&lt;p&gt;Because the bytes pointed to in either the &lt;code&gt;XdpContext&lt;/code&gt; or &lt;code&gt;SkBuff&lt;/code&gt; are networking bytes, they are stored in "network byte order" (Big Endian) and must be converted to "host byte order" (which is often Little Endian, but determined by platform). &lt;code&gt;SkBuff::load&lt;/code&gt; takes care of the conversion for us, but &lt;code&gt;XdpContext&lt;/code&gt;, &lt;code&gt;NetworkBuffer&lt;/code&gt;, or &lt;code&gt;Data&amp;lt;T&amp;gt;&lt;/code&gt; do not, and leave that to the calling code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; A full discussion on Endianess is beyond the scope of this series (&lt;a href="https://www.section.io/engineering-education/what-is-little-endian-and-big-endian/" rel="noopener noreferrer"&gt;see here for a quick intro&lt;/a&gt;), but essentially it's the order in which bytes are stored (least significant bits first is Little Endian, and most significant bits first is Big Endian).&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap Up
&lt;/h1&gt;

&lt;p&gt;Now that we've done a good quick deep dive of what's currently implemented and available in the RedBPF networking modules, we can begin to look at improvements we could make in the next post!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>networking</category>
      <category>bpf</category>
      <category>xdp</category>
    </item>
  </channel>
</rss>
