<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>tag:blog.danieljanus.pl,2019:category:rust</id>
  <title>Daniel Janus – Rust</title>
  <link href="http://blog.danieljanus.pl/category/rust/"/>
  <updated>2023-07-20T00:00:00Z</updated>
  <author>
    <name>Daniel Janus</name>
    <uri>http://danieljanus.pl</uri>
    <email>dj@danieljanus.pl</email>
  </author>
  <entry>
    <id>tag:blog.danieljanus.pl,2023-07-20:post:iterating-trees</id>
    <title>A visual tree iterator in Rust</title>
    <link href="http://blog.danieljanus.pl/iterating-trees/"/>
    <updated>2023-07-20T00:00:00Z</updated>
    <content type="html">&lt;div&gt;&lt;p&gt;My &lt;a href="/2023/07/06/learning-to-learn-rust/"&gt;adventure with learning Rust&lt;/a&gt; continues. As a quick recap from the previous post, I’m writing a &lt;a href="https://github.com/nathell/treeviewer"&gt;tree viewer&lt;/a&gt;. I have now completed another major milestone, which is to rewrite the tree-printing function to use an iterator. (Rationale: it makes the code more reusable – I can, for instance, easily implement a tree-drawing view for &lt;a href="https://github.com/gyscos/cursive"&gt;Cursive&lt;/a&gt; with it.)&lt;/p&gt;&lt;p&gt;And, as usual, I’ve fallen into many traps before arriving at a working version. In this post, I’ll reflect on the mistakes I’ve made.&lt;/p&gt;&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;&lt;p&gt;Let’s start with establishing the problem. Given a &lt;code&gt;Tree&lt;/code&gt; struct defined as:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title class_"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; {
    value: T,
    children: &lt;span class="hljs-type"&gt;Vec&lt;/span&gt;&amp;lt;Tree&amp;lt;T&amp;gt;&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I want it to have a &lt;code&gt;lines()&lt;/code&gt; method returning an iterator, so that I can implement &lt;code&gt;print_tree&lt;/code&gt; as:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;print_tree&lt;/span&gt;&amp;lt;T: Display&amp;gt;(t: &amp;amp;Tree&amp;lt;T&amp;gt;) {
    &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; &lt;span class="hljs-variable"&gt;line&lt;/span&gt; &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; t.&lt;span class="hljs-title function_ invoke__"&gt;lines&lt;/span&gt;() {
        &lt;span class="hljs-built_in"&gt;println!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;, line);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and have the output identical to the previous version.&lt;/p&gt;&lt;h2 id="the-algorithm"&gt;The algorithm&lt;/h2&gt;&lt;p&gt;Before we dive into the iterator sea, let’s have a look at the algorithm. Imagine that we’re printing the tree (in sexp-notation) &lt;code&gt;(root (one (two) (three (four))) (five (six)))&lt;/code&gt;. This is its dissected visual representation:&lt;/p&gt;&lt;img src="/img/blog/tree-anatomy.png" alt="Anatomy of a tree"&gt;
&lt;p&gt;Each line consists of three concatenated elements, which I call “parent prefix”, “immediate prefix”, and “node value”. The immediate prefix is always (except for the root node) &lt;code&gt;"└─ "&lt;/code&gt; or &lt;code&gt;"├─ "&lt;/code&gt;, depending on whether the node in question is the last child of its parent or not. The parent prefix has variable length that depends on the node’s depth, and has the following properties:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;For any node, all its subnodes’ parent prefixes start with its parent prefix.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;For any node, the parent prefixes of its direct children are obtained by appending &lt;code&gt;"   "&lt;/code&gt; or &lt;code&gt;"│  "&lt;/code&gt; to its own parent prefix, again depending on whether the node is its parent’s last child or not.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This gives rise to the following algorithm that calls itself recursively:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;print_tree&lt;/span&gt;&amp;lt;T&amp;gt;(t: &amp;amp;Tree&amp;lt;T&amp;gt;,
                 parent_prefix: &amp;amp;&lt;span class="hljs-type"&gt;str&lt;/span&gt;,
                 immediate_prefix: &amp;amp;&lt;span class="hljs-type"&gt;str&lt;/span&gt;,
                 parent_suffix: &amp;amp;&lt;span class="hljs-type"&gt;str&lt;/span&gt;)
    &lt;span class="hljs-keyword"&gt;where&lt;/span&gt; T: Display
{
    &lt;span class="hljs-comment"&gt;// print the line for node t&lt;/span&gt;
    &lt;span class="hljs-built_in"&gt;println!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{0}{1}{2}&amp;quot;&lt;/span&gt;, parent_prefix, immediate_prefix, t.value);

    &lt;span class="hljs-comment"&gt;// print all children of t recursively&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-keyword"&gt;mut &lt;/span&gt;&lt;span class="hljs-variable"&gt;it&lt;/span&gt; = t.children.&lt;span class="hljs-title function_ invoke__"&gt;iter&lt;/span&gt;().&lt;span class="hljs-title function_ invoke__"&gt;peekable&lt;/span&gt;();
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;child_prefix&lt;/span&gt; = &lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{0}{1}&amp;quot;&lt;/span&gt;, parent_prefix, parent_suffix);

    &lt;span class="hljs-keyword"&gt;while&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;Some&lt;/span&gt;(child) = it.&lt;span class="hljs-title function_ invoke__"&gt;next&lt;/span&gt;() {
        &lt;span class="hljs-keyword"&gt;match&lt;/span&gt; it.&lt;span class="hljs-title function_ invoke__"&gt;peek&lt;/span&gt;() {
            &lt;span class="hljs-literal"&gt;None&lt;/span&gt;    =&amp;gt; &lt;span class="hljs-title function_ invoke__"&gt;print_tree&lt;/span&gt;(child, &amp;amp;child_prefix, &lt;span class="hljs-string"&gt;&amp;quot;└─ &amp;quot;&lt;/span&gt;, &lt;span class="hljs-string"&gt;&amp;quot;   &amp;quot;&lt;/span&gt;),
            &lt;span class="hljs-title function_ invoke__"&gt;Some&lt;/span&gt;(_) =&amp;gt; &lt;span class="hljs-title function_ invoke__"&gt;print_tree&lt;/span&gt;(child, &amp;amp;child_prefix, &lt;span class="hljs-string"&gt;&amp;quot;├─ &amp;quot;&lt;/span&gt;, &lt;span class="hljs-string"&gt;&amp;quot;│  &amp;quot;&lt;/span&gt;),
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The three extra string arguments start out as empty strings and become populated as the algorithm descends into the tree. The implementation uses a &lt;a href="https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html"&gt;peekable&lt;/a&gt; iterator over the &lt;code&gt;children&lt;/code&gt; vector to construct the prefixes appropriately.&lt;/p&gt;&lt;h2 id="building-an-iterator,-take-1"&gt;Building an iterator, take 1&lt;/h2&gt;&lt;p&gt;So the printing implementation is recursive. How do we write a recursive iterator in Rust? Is it even possible? I initially thought I would have to replace the recursion with an explicit stack stored in the iterator’s mutable state, started to write some code, and promptly got lost.&lt;/p&gt;&lt;p&gt;I then searched for the state-of-the-art on iterating through trees, and found &lt;a href="https://fasterthanli.me/articles/recursive-iterators-rust"&gt;this post&lt;/a&gt; by Amos Wenger. You might want to read it first before continuing; my final implementation ended up being an adaptation of one of the techniques described there.&lt;/p&gt;&lt;p&gt;My definition of tree is slightly different than Amos’s (mine has only one value in a node), but it’s easy enough to adapt his final solution to iterate over its values:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;impl&lt;/span&gt;&amp;lt;T&amp;gt; Tree&amp;lt;T&amp;gt; &lt;span class="hljs-keyword"&gt;where&lt;/span&gt; T: Display {
    &lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;lines&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;(&amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;) &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &lt;span class="hljs-type"&gt;String&lt;/span&gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;child_iter&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.children.&lt;span class="hljs-title function_ invoke__"&gt;iter&lt;/span&gt;().&lt;span class="hljs-title function_ invoke__"&gt;map&lt;/span&gt;(|n| n.&lt;span class="hljs-title function_ invoke__"&gt;lines&lt;/span&gt;()).&lt;span class="hljs-title function_ invoke__"&gt;flatten&lt;/span&gt;();

        &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(
            &lt;span class="hljs-title function_ invoke__"&gt;once&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value.&lt;span class="hljs-title function_ invoke__"&gt;to_string&lt;/span&gt;()).&lt;span class="hljs-title function_ invoke__"&gt;chain&lt;/span&gt;(child_iter)
        )
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(Note the &lt;code&gt;dyn&lt;/code&gt; keyword; Rust started requiring it in this context sometime after Amos’s article was published.)&lt;/p&gt;&lt;p&gt;Clever! This sidesteps the issue of writing a custom iterator altogether, by chaining some standard ones, wrapping them in a box and sprinkling some lifetime annotation magic powder to appease the borrow checker. We also make it explicit that the iterator is returning strings, no matter what the type of tree nodes is.&lt;/p&gt;&lt;p&gt;&lt;em&gt;But…&lt;/em&gt; while it compiles and produces a sequence of strings, they don’t reflect the structure of the tree: there’s no pretty prefixing going on.&lt;/p&gt;&lt;p&gt;Let’s try to fix that. Clearly, the iterator-returning function will now need to take three additional arguments, just like &lt;code&gt;print_tree&lt;/code&gt; – the first one will now be a &lt;code&gt;String&lt;/code&gt; because we’ll be building it at runtime, and the other two are string literals so can just be &lt;code&gt;&amp;'static str&lt;/code&gt;s. Let’s try:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-comment"&gt;// changing the name because we now accept extra params&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// I want the original lines() to keep its signature&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;prefixed_lines&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;(&amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;,
                          parent_prefix: &lt;span class="hljs-type"&gt;String&lt;/span&gt;,
                          immediate_prefix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;,
                          parent_suffix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;)
                         &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &lt;span class="hljs-type"&gt;String&lt;/span&gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;
{
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;value&lt;/span&gt; = &lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{0}{1}{2}&amp;quot;&lt;/span&gt;, parent_prefix, immediate_prefix, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value);
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-keyword"&gt;mut &lt;/span&gt;&lt;span class="hljs-variable"&gt;peekable&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.children.&lt;span class="hljs-title function_ invoke__"&gt;iter&lt;/span&gt;().&lt;span class="hljs-title function_ invoke__"&gt;peekable&lt;/span&gt;();
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;child_iter&lt;/span&gt; = peekable
        .&lt;span class="hljs-title function_ invoke__"&gt;map&lt;/span&gt;(|n| {
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;child_prefix&lt;/span&gt; = &lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{0}{1}&amp;quot;&lt;/span&gt;, parent_prefix, parent_suffix);
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;last&lt;/span&gt; = !peekable.&lt;span class="hljs-title function_ invoke__"&gt;peek&lt;/span&gt;().&lt;span class="hljs-title function_ invoke__"&gt;is_some&lt;/span&gt;();
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;immediate_prefix&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; last { &lt;span class="hljs-string"&gt;&amp;quot;└─ &amp;quot;&lt;/span&gt; } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-string"&gt;&amp;quot;├─ &amp;quot;&lt;/span&gt; };
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;parent_suffix&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; last { &lt;span class="hljs-string"&gt;&amp;quot;   &amp;quot;&lt;/span&gt; } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-string"&gt;&amp;quot;│  &amp;quot;&lt;/span&gt; };
            n.&lt;span class="hljs-title function_ invoke__"&gt;prefixed_lines&lt;/span&gt;(child_prefix, immediate_prefix, parent_suffix)
        })
        .&lt;span class="hljs-title function_ invoke__"&gt;flatten&lt;/span&gt;();

    &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(
        &lt;span class="hljs-title function_ invoke__"&gt;once&lt;/span&gt;(value).&lt;span class="hljs-title function_ invoke__"&gt;chain&lt;/span&gt;(child_iter)
    )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And, sure enough, it doesn’t compile. One of the things that Rust complains about is:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;error[E0373]: closure may outlive the current function,
    but it borrows `peekable`, which is owned by the current function
  --&gt; src/main.rs:55:18
   |
55 |     .map(|n| {
   |          ^^^ may outlive borrowed value `peekable`
56 |         let child_prefix = format!("{0}{1}"...
57 |         let last = !peekable.peek().is_some();
   |                     -------- `peekable` is borrowed here
   |
note: closure is returned here
  --&gt; src/main.rs:64:9
   |
64 | Box::new(once(value).chain(child_iter))
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `peekable`
      (and any other referenced variables), use the `move` keyword
   |
55 |     .map(move |n| {
   |          ++++
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So trying to borrow the iterator from within the closure passed to &lt;code&gt;map()&lt;/code&gt; is non-kosher. I’m not sure where the “may outlive the current function” comes from, but I think this is because &lt;a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map"&gt;the iterator returned by &lt;code&gt;map&lt;/code&gt; is lazy&lt;/a&gt;, and so the closure needs to be able to live for at least as long as the resulting iterator does. The suggestion of using &lt;code&gt;move&lt;/code&gt; doesn’t work, because it then invalidates the &lt;code&gt;map&lt;/code&gt; call. (Rust complained about borrowing &lt;code&gt;parent_prefix&lt;/code&gt; and &lt;code&gt;parent_suffix&lt;/code&gt; as well, and &lt;code&gt;move&lt;/code&gt; does work for those.)&lt;/p&gt;&lt;h2 id="taking-a-step-back"&gt;Taking a step back&lt;/h2&gt;&lt;p&gt;I was not able to find a way out of this conundrum. But after re-reading Amos’s post, I’ve decided to revisit his “bad” approach, with a custom iterator (which I now think is actually not bad at all). It made all the more sense to me when I considered future extensibility: eventually I want to be able to render certain subtrees collapsed, and I want the iterator to know about that.&lt;/p&gt;&lt;p&gt;It took me a while to understand how that &lt;a href="https://play.rust-lang.org/?version=stable&amp;amp;mode=debug&amp;amp;edition=2018&amp;amp;gist=c2cf6a965c3637553edd95eecc1993cd"&gt;custom iterator&lt;/a&gt; works. It doesn’t have an explicit stack and doesn’t try to “de-recursivize” the process! Instead, it holds two sub-iterators, one initially iterating over the node values (&lt;code&gt;viter&lt;/code&gt;) and the other over children (&lt;code&gt;citer&lt;/code&gt;). The &lt;code&gt;next()&lt;/code&gt; method just tries &lt;code&gt;viter&lt;/code&gt; first; if it returns nothing, then a next subtree is picked from &lt;code&gt;citer&lt;/code&gt;, and &lt;code&gt;viter&lt;/code&gt; (by now already consumed) &lt;em&gt;is replaced by another instance of the same iterator, but for that subtree&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Meditate on this for a while. There’s a lot going on here.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;&lt;code&gt;viter&lt;/code&gt; starts out as an iterator over a vector (a &lt;code&gt;std::slice::Iter&lt;/code&gt;), and then gets replaced by a tree iterator (Amos’s &lt;code&gt;NodeIter&lt;/code&gt;).&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;This is possible because it’s declared as a &lt;code&gt;Box&amp;lt;Iterator&amp;lt;Item = &amp;'a i32&gt; + 'a&gt;&lt;/code&gt;. TIL: in Rust, you can’t use a trait directly as a type for a struct field (because there’s no telling what its size will be), but you &lt;em&gt;can&lt;/em&gt; put it into a &lt;code&gt;Box&lt;/code&gt; (or, I guess, &lt;code&gt;Rc&lt;/code&gt; or &lt;code&gt;Arc&lt;/code&gt;). Polymorphism, baby!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Recursion is achieved by having &lt;code&gt;NodeIter&lt;/code&gt; contain a member that, at times, is itself another &lt;code&gt;NodeIter&lt;/code&gt;; whereas the correct behaviour is obtained by having those &lt;code&gt;NodeIters&lt;/code&gt; instantiated at the right moment.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Whoa. Now &lt;em&gt;that’s&lt;/em&gt; clever. I probably wouldn’t have thought about this. It’s good to be standing on the shoulders of giants. Thanks, Amos.&lt;/p&gt;&lt;p&gt;Anyway, let’s adapt it to our use-case and add the prefixes to the iterator’s state:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title class_"&gt;TreeIterator&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt; {
    parent_prefix: &lt;span class="hljs-type"&gt;String&lt;/span&gt;,
    immediate_prefix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;,
    parent_suffix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;,
    viter: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &lt;span class="hljs-type"&gt;String&lt;/span&gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;,
    citer: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; Tree&amp;lt;T&amp;gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And our iterator implementation follows Amos’s, except that we handle the prefixes and initialize &lt;code&gt;viter&lt;/code&gt; with a &lt;a href="https://doc.rust-lang.org/std/iter/struct.Once.html"&gt;&lt;code&gt;Once&lt;/code&gt;&lt;/a&gt; iterator:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;impl&lt;/span&gt;&amp;lt;T&amp;gt; Tree&amp;lt;T&amp;gt; &lt;span class="hljs-keyword"&gt;where&lt;/span&gt; T: Display {
    &lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;prefixed_lines&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;(&amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;,
                      parent_prefix: &lt;span class="hljs-type"&gt;String&lt;/span&gt;,
                      immediate_prefix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;,
                      parent_suffix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;)
                     &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; TreeIterator&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt;
    {
        TreeIterator {
            parent_prefix: parent_prefix,
            immediate_prefix: immediate_prefix,
            parent_suffix: parent_suffix,
            viter: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(&lt;span class="hljs-title function_ invoke__"&gt;once&lt;/span&gt;(&lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;, &amp;amp;&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value))),
            citer: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.children.&lt;span class="hljs-title function_ invoke__"&gt;iter&lt;/span&gt;().&lt;span class="hljs-title function_ invoke__"&gt;peekable&lt;/span&gt;()),
        }
    }
}

&lt;span class="hljs-keyword"&gt;impl&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt; &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; &lt;span class="hljs-title class_"&gt;TreeIterator&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt; &lt;span class="hljs-keyword"&gt;where&lt;/span&gt; T: Display {
    &lt;span class="hljs-keyword"&gt;type&lt;/span&gt; &lt;span class="hljs-title class_"&gt;Item&lt;/span&gt; = &lt;span class="hljs-type"&gt;String&lt;/span&gt;;

    &lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;next&lt;/span&gt;(&amp;amp;&lt;span class="hljs-keyword"&gt;mut&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;) &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="hljs-type"&gt;Option&lt;/span&gt;&amp;lt;&lt;span class="hljs-keyword"&gt;Self&lt;/span&gt;::Item&amp;gt; {
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;Some&lt;/span&gt;(val) = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.viter.&lt;span class="hljs-title function_ invoke__"&gt;next&lt;/span&gt;() {
            &lt;span class="hljs-title function_ invoke__"&gt;Some&lt;/span&gt;(&lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{0}{1}{2}&amp;quot;&lt;/span&gt;, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.parent_prefix, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.immediate_prefix, val))
        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;Some&lt;/span&gt;(child) = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.citer.&lt;span class="hljs-title function_ invoke__"&gt;next&lt;/span&gt;() {
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;last&lt;/span&gt; = !&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.citer.&lt;span class="hljs-title function_ invoke__"&gt;peek&lt;/span&gt;().&lt;span class="hljs-title function_ invoke__"&gt;is_some&lt;/span&gt;();
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;immediate_prefix&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; last { &lt;span class="hljs-string"&gt;&amp;quot;└─ &amp;quot;&lt;/span&gt; } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-string"&gt;&amp;quot;├─ &amp;quot;&lt;/span&gt; };
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;parent_suffix&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; last { &lt;span class="hljs-string"&gt;&amp;quot;   &amp;quot;&lt;/span&gt; } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-string"&gt;&amp;quot;│  &amp;quot;&lt;/span&gt; };
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;subprefix&lt;/span&gt; = &lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{0}{1}&amp;quot;&lt;/span&gt;, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.parent_prefix, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.parent_suffix);
            &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.viter = &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(child.&lt;span class="hljs-title function_ invoke__"&gt;prefixed_lines&lt;/span&gt;(subprefix, immediate_prefix, parent_suffix));
            &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.&lt;span class="hljs-title function_ invoke__"&gt;next&lt;/span&gt;()
        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
            &lt;span class="hljs-literal"&gt;None&lt;/span&gt;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Looks sensible, right? Except (you guessed it!) it doesn’t compile:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;error[E0599]: no method named `peek` found &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; &lt;span class="hljs-title class_"&gt;struct&lt;/span&gt;
    `&lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;(&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; Tree&amp;lt;T&amp;gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;)&amp;gt;` &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; the current scope
  -&lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; src/main.rs:&lt;span class="hljs-number"&gt;38&lt;/span&gt;:&lt;span class="hljs-number"&gt;36&lt;/span&gt;
   |
&lt;span class="hljs-number"&gt;38&lt;/span&gt; |     &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;last&lt;/span&gt; = !&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.citer.&lt;span class="hljs-title function_ invoke__"&gt;peek&lt;/span&gt;().&lt;span class="hljs-title function_ invoke__"&gt;is_some&lt;/span&gt;();
   |                            ^^^^ help: there is a method with a
   |                                 similar name: `peekable`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ah, right. We’ve forgotten to tell Rust that &lt;code&gt;citer&lt;/code&gt; contains a &lt;code&gt;Peekable&lt;/code&gt;. Let’s fix that:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title class_"&gt;TreeIterator&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt; {
    &lt;span class="hljs-comment"&gt;// … other fields as before&lt;/span&gt;
    citer: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;Peekable&amp;lt;&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; Tree&amp;lt;T&amp;gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nope, that doesn’t compile either:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;error[E0277]: the size &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; &lt;span class="hljs-title class_"&gt;values&lt;/span&gt; of &lt;span class="hljs-keyword"&gt;type&lt;/span&gt; `(&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; Tree&amp;lt;T&amp;gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;)`
    cannot be known at compilation time
  -&lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; src/main.rs:&lt;span class="hljs-number"&gt;16&lt;/span&gt;:&lt;span class="hljs-number"&gt;12&lt;/span&gt;
   |
&lt;span class="hljs-number"&gt;16&lt;/span&gt; |     citer: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;Peekable&amp;lt;&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; Tree&amp;lt;T&amp;gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;&amp;gt;,
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |            doesn&lt;span class="hljs-symbol"&gt;&amp;#x27;t&lt;/span&gt; have a size known at compile-time
   |
   = help: the &lt;span class="hljs-keyword"&gt;trait&lt;/span&gt; `&lt;span class="hljs-built_in"&gt;Sized&lt;/span&gt;` is not implemented &lt;span class="hljs-keyword"&gt;for&lt;/span&gt;
           `(&lt;span class="hljs-keyword"&gt;dyn&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Iterator&lt;/span&gt;&amp;lt;Item = &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; Tree&amp;lt;T&amp;gt;&amp;gt; + &lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;)`
note: required by a bound &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; `Peekable`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bummer. We can put a trait of unknown size in a &lt;code&gt;Box&lt;/code&gt;, but we can’t put a &lt;code&gt;Peekable&lt;/code&gt; in between! &lt;code&gt;Peekable&lt;/code&gt; needs to know the size of its contents at compile time. Trying to convince it by sprinkling &lt;code&gt;+ Sized&lt;/code&gt; in various places doesn’t work.&lt;/p&gt;&lt;p&gt;Fortunately, we know the &lt;em&gt;actual&lt;/em&gt; type of &lt;code&gt;citer&lt;/code&gt;. It’s an iterator over &lt;code&gt;Vec&amp;lt;Tree&amp;lt;T&gt;&gt;&lt;/code&gt;, so it’s a &lt;code&gt;std::slice::Iter&amp;lt;Tree&amp;lt;T&gt;&gt;&lt;/code&gt;. Let’s put it in the definition of &lt;code&gt;TreeIterator&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;use&lt;/span&gt; std::slice::Iter;

&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title class_"&gt;TreeIterator&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt; {
    &lt;span class="hljs-comment"&gt;// … other fields as before&lt;/span&gt;
    citer: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;&amp;lt;Peekable&amp;lt;Iter&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, Tree&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And it compiles!&lt;/p&gt;&lt;h2 id="removing-the-root"&gt;Removing the root&lt;/h2&gt;&lt;p&gt;Here’s what happens when you try to run treeviewer with this implementation on a very simple tree:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs bash"&gt;$ &lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; -e &lt;span class="hljs-string"&gt;&amp;#x27;one\ntwo&amp;#x27;&lt;/span&gt; | ./target/debug/treeviewer

├─ one
└─ two
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Seems good, but that empty line is worrying. That’s because treeviewer takes slash-separated paths as input, and because the paths can begin with anything, it puts everything under a pre-existing root node with an empty &lt;code&gt;value&lt;/code&gt;. We don’t want the output to contain that root node.&lt;/p&gt;&lt;p&gt;Simple, right? We just need to initialize &lt;code&gt;viter&lt;/code&gt; with an empty iterator if one of the prefixes is also empty:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;prefixed_lines&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;(&amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;,
                          parent_prefix: &lt;span class="hljs-type"&gt;String&lt;/span&gt;,
                          immediate_prefix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;,
                          parent_suffix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;)
                         &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; TreeIterator&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt;
{
    TreeIterator {
        &lt;span class="hljs-comment"&gt;// … other fields as before&lt;/span&gt;
        viter: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;if&lt;/span&gt; immediate_prefix.&lt;span class="hljs-title function_ invoke__"&gt;is_empty&lt;/span&gt;() {
                           &lt;span class="hljs-title function_ invoke__"&gt;empty&lt;/span&gt;()
                        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
                           &lt;span class="hljs-title function_ invoke__"&gt;once&lt;/span&gt;(&lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;, &amp;amp;&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value))
                        }),
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And (this is becoming obvious by now) we’re rewarded by yet another interesting error message:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;error[E0308]: `&lt;span class="hljs-keyword"&gt;if&lt;/span&gt;` and `&lt;span class="hljs-keyword"&gt;else&lt;/span&gt;` have incompatible types
  -&lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; src/main.rs:&lt;span class="hljs-number"&gt;49&lt;/span&gt;:&lt;span class="hljs-number"&gt;32&lt;/span&gt;
   |
&lt;span class="hljs-number"&gt;46&lt;/span&gt; |   viter: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;if&lt;/span&gt; immediate_prefix.&lt;span class="hljs-title function_ invoke__"&gt;is_empty&lt;/span&gt;() {
   |  _________________-
&lt;span class="hljs-number"&gt;47&lt;/span&gt; | |                    &lt;span class="hljs-title function_ invoke__"&gt;empty&lt;/span&gt;()
   | |                    ------- expected because of this
&lt;span class="hljs-number"&gt;48&lt;/span&gt; | |                 } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
&lt;span class="hljs-number"&gt;49&lt;/span&gt; | |                    &lt;span class="hljs-title function_ invoke__"&gt;once&lt;/span&gt;(&lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;, &amp;amp;&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value))
   | |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   | |                      expected `Empty&amp;lt;_&amp;gt;`, found `Once&amp;lt;&lt;span class="hljs-type"&gt;String&lt;/span&gt;&amp;gt;`
&lt;span class="hljs-number"&gt;50&lt;/span&gt; | |                 }),
   | |_________________- `&lt;span class="hljs-keyword"&gt;if&lt;/span&gt;` and `&lt;span class="hljs-keyword"&gt;else&lt;/span&gt;` have incompatible types
   |
   = note: expected &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; `std::iter::Empty&amp;lt;_&amp;gt;`
              found &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; `std::iter::Once&amp;lt;&lt;span class="hljs-type"&gt;String&lt;/span&gt;&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ahhh. Even though both branches of the &lt;code&gt;if&lt;/code&gt; expression have types that meet the trait requirement (&lt;code&gt;Iterator&lt;Item = String&gt;&lt;/code&gt;), these are &lt;em&gt;different types&lt;/em&gt;. Apparently, &lt;code&gt;if&lt;/code&gt; insists on both branches being the same type.&lt;/p&gt;&lt;p&gt;What we can do is lift the &lt;code&gt;if&lt;/code&gt; upwards:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;prefixed_lines&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;(&amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;,
                          parent_prefix: &lt;span class="hljs-type"&gt;String&lt;/span&gt;,
                          immediate_prefix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;,
                          parent_suffix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;)
                         &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; TreeIterator&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt;
{
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; immediate_prefix.&lt;span class="hljs-title function_ invoke__"&gt;is_empty&lt;/span&gt;() {
        TreeIterator {
            &lt;span class="hljs-comment"&gt;// … other fields as before&lt;/span&gt;
            viter: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(&lt;span class="hljs-title function_ invoke__"&gt;empty&lt;/span&gt;()),
        }
    } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
        TreeIterator {
            &lt;span class="hljs-comment"&gt;// … other fields as before, repeated&lt;/span&gt;
            viter: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(&lt;span class="hljs-title function_ invoke__"&gt;once&lt;/span&gt;(&lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;, &amp;amp;&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value))),
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Yuck. We needed to duplicate most of the instantiation details of &lt;code&gt;TreeIterator&lt;/code&gt;. But at least it compiles and works – the root is gone!&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs bash"&gt;$ &lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; -e &lt;span class="hljs-string"&gt;&amp;#x27;one\ntwo&amp;#x27;&lt;/span&gt; | ./target/debug/treeviewer
├─ one
└─ two
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="fixing-a-bug"&gt;Fixing a bug&lt;/h2&gt;&lt;p&gt;Or does it? Let’s try the original tree from our illustration:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs bash"&gt;$ &lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; -e &lt;span class="hljs-string"&gt;&amp;#x27;one/two\none/three/four\nfive/six&amp;#x27;&lt;/span&gt; | ./target/debug/treeviewer
├─ one
├─ │  ├─ two
├─ │  └─ three
├─ │  └─ │     └─ four
└─ five
└─    └─ six
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Uh oh. It’s totally garbled. Time to go back to the drawing board.&lt;/p&gt;&lt;p&gt;It took me quite a few &lt;code&gt;println!()&lt;/code&gt; debugging statements to figure out what was going on. Remember, the &lt;code&gt;TreeIterator&lt;/code&gt; for the whole tree will contain a nested &lt;code&gt;TreeIterator&lt;/code&gt; in its &lt;code&gt;viter&lt;/code&gt; field, which in turn may contain another nested &lt;code&gt;TreeIterator&lt;/code&gt;, and so on. Each of these nested iterators eventually passes its value to the “parent” iterator… decorating it with prefixes, again and again!&lt;/p&gt;&lt;p&gt;To fix this, we need to differentiate between two cases:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;span&gt;We’re producing the value for the node we’re holding (that’s when we need the prefixes);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;We’re propagating up the value returned by &lt;code&gt;viter&lt;/code&gt; that holds a nested &lt;code&gt;TreeIterator&lt;/code&gt; (in this case we need to return it unchanged).&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We’ll add two more fields to &lt;code&gt;TreeIterator&lt;/code&gt;: a boolean indicating whether we’ve already &lt;code&gt;emitted&lt;/code&gt; the value at the node in question, and a reference to that &lt;code&gt;value&lt;/code&gt; itself.&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title class_"&gt;TreeIterator&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt; {
    &lt;span class="hljs-comment"&gt;// … other fields as before&lt;/span&gt;
    emitted: &lt;span class="hljs-type"&gt;bool&lt;/span&gt;,
    value: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; T,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we initialize them as follows:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;pub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;prefixed_lines&lt;/span&gt;&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;&amp;gt;(&amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;,
                          parent_prefix: &lt;span class="hljs-type"&gt;String&lt;/span&gt;,
                          immediate_prefix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;,
                          parent_suffix: &amp;amp;&lt;span class="hljs-symbol"&gt;&amp;#x27;static&lt;/span&gt; &lt;span class="hljs-type"&gt;str&lt;/span&gt;)
                         &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; TreeIterator&amp;lt;&lt;span class="hljs-symbol"&gt;&amp;#x27;a&lt;/span&gt;, T&amp;gt;
{
    TreeIterator {
        emitted: immediate_prefix.&lt;span class="hljs-title function_ invoke__"&gt;is_empty&lt;/span&gt;(),
        value: &amp;amp;&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value,
        viter: &lt;span class="hljs-type"&gt;Box&lt;/span&gt;::&lt;span class="hljs-title function_ invoke__"&gt;new&lt;/span&gt;(&lt;span class="hljs-title function_ invoke__"&gt;empty&lt;/span&gt;()),
        &lt;span class="hljs-comment"&gt;// … other fields as before&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that the logic of skipping emitting the root has been moved to the initialization of &lt;code&gt;emitted&lt;/code&gt;. This lets us kill the duplication! We now initialize &lt;code&gt;viter&lt;/code&gt; to &lt;code&gt;empty()&lt;/code&gt; – it no longer matters; this initial value will be unused and eventually replaced by child &lt;code&gt;TreeIterator&lt;/code&gt;s.&lt;/p&gt;&lt;p&gt;Finally, we need to amend the implementation of &lt;code&gt;next()&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs rust"&gt;&lt;span class="hljs-keyword"&gt;fn&lt;/span&gt; &lt;span class="hljs-title function_"&gt;next&lt;/span&gt;(&amp;amp;&lt;span class="hljs-keyword"&gt;mut&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;) &lt;span class="hljs-punctuation"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="hljs-type"&gt;Option&lt;/span&gt;&amp;lt;&lt;span class="hljs-keyword"&gt;Self&lt;/span&gt;::Item&amp;gt; {
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; !&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.emitted {
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.emitted = &lt;span class="hljs-literal"&gt;true&lt;/span&gt;;
        &lt;span class="hljs-comment"&gt;// decorate value with prefixes&lt;/span&gt;
        &lt;span class="hljs-title function_ invoke__"&gt;Some&lt;/span&gt;(&lt;span class="hljs-built_in"&gt;format!&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;{0}{1}{2}&amp;quot;&lt;/span&gt;, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.parent_prefix, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.immediate_prefix, &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value))
    } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;Some&lt;/span&gt;(val) = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.viter.&lt;span class="hljs-title function_ invoke__"&gt;next&lt;/span&gt;() {
        &lt;span class="hljs-title function_ invoke__"&gt;Some&lt;/span&gt;(val) &lt;span class="hljs-comment"&gt;// propagate unchanged&lt;/span&gt;
    } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-variable"&gt;Some&lt;/span&gt;(child) = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.citer.&lt;span class="hljs-title function_ invoke__"&gt;next&lt;/span&gt;() {
        &lt;span class="hljs-comment"&gt;// … this part doesn’t change&lt;/span&gt;
    } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
        &lt;span class="hljs-literal"&gt;None&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And &lt;em&gt;this&lt;/em&gt; version, finally, compiles and works as expected:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs bash"&gt;$ &lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; -e &lt;span class="hljs-string"&gt;&amp;#x27;one/two\none/three/four\nfive/six&amp;#x27;&lt;/span&gt; | ./target/debug/treeviewer
├─ one
│  ├─ two
│  └─ three
│     └─ four
└─ five
   └─ six
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="takeaways"&gt;Takeaways&lt;/h2&gt;&lt;p&gt;There are quite a few things I learned about Rust in the process, and then there are meta-learnings. Let’s recap the Rust-specific ones first.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;You can’t put a trait in a struct directly, but you can put a &lt;code&gt;Box&lt;/code&gt; of traits.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;But not a &lt;code&gt;Box&lt;/code&gt; of &lt;code&gt;Foo&lt;/code&gt; of traits, where &lt;code&gt;Foo&lt;/code&gt; expect its parameter to be &lt;code&gt;Sized&lt;/code&gt;.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;If you’re &lt;code&gt;map()&lt;/code&gt;ping a closure over an iterator, you can’t access that iterator itself from within the closure.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Closures by default borrow stuff that they close over, but you can move that stuff to the closure instead with the &lt;code&gt;move&lt;/code&gt; keyword. If I understand correctly, it’s an all-or-nothing move; no mix and match.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;In an &lt;code&gt;if&lt;/code&gt; expression, all branch expressions must be of the same type; conforming to the same trait is not enough.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;And now the general ones.&lt;/p&gt;&lt;p&gt;First off, Rust is &lt;em&gt;hard&lt;/em&gt;. (The least wonder in the world.) Most of the traps I’ve fallen into are accidental complexity, not inherent in the simple problem. I guess that it’s really a matter of the initial steepness of Rust’s learning curve, and that things become easier once you’re past the initial hurdles – you train your instincts to avoid these tarpits and keep the compiler happy.&lt;/p&gt;&lt;p&gt;I’m still very much a newcomer to Rust, so I’m pretty sure I ended up taking a suboptimal approach. A seasoned Rustacean would probably write this code in an altogether different way. If you have suggestions how to improve my code, or how to attack the problem from different angles, tell me!&lt;/p&gt;&lt;p&gt;As an experiment in learning, I’ve decided to reflect on my mistakes more frequently. I elaborate on it in my &lt;a href="/2023/07/06/learning-to-learn-rust/"&gt;previous post&lt;/a&gt;, which also discusses changes I’ve made to my workflow to make learning easier.&lt;/p&gt;&lt;p&gt;Writing the present post showed me how much time it takes. It took me just over an hour to fall into all the traps described in this post and find a way out. A few hours, if you count reading Amos’s post and contemplating the problem. In contrast, this write-up took about two days, plus some &lt;a href="https://mastodon.social/@nathell/110725780205595986"&gt;yak shaving&lt;/a&gt; it led me to. Part of the reason is that the &lt;em&gt;actual&lt;/em&gt; road that I went through was much more bumpy than described here. While writing this, I had to go through no fewer than fifty-six compilation attempts. Here are some of them, with one-line descriptions and a tick or cross to indicate whether the compilation attempt was successful:&lt;/p&gt;&lt;img src="/img/blog/rust-compilation-attempts.png" alt="Some compilation attempts"&gt;
&lt;p&gt;Yet I think it’s worth it. Some of the errors I’ve fixed groping in the dark, kind of randomly: I have now revisited them and I feel I have a much more solid understanding of what’s going on.&lt;/p&gt;&lt;p&gt;And finally: if you’re into Rust, Amos’s blog (&lt;a href="https://mastodon.social/@nathell/110725780205595986"&gt;fasterthanli.me&lt;/a&gt;) is an excellent resource. Go sponsor him on GitHub if these articles are of value to you.&lt;/p&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <id>tag:blog.danieljanus.pl,2023-07-06:post:learning-to-learn-rust</id>
    <title>Learning to learn Rust</title>
    <link href="http://blog.danieljanus.pl/learning-to-learn-rust/"/>
    <updated>2023-07-06T00:00:00Z</updated>
    <content type="html">&lt;div&gt;&lt;p&gt;I’m enjoying a two-month sabbatical this summer. It’s been great so far! I’ve used almost half of the time to &lt;a href="https://danieljanus.substack.com/about"&gt;cycle through the entire Great Britain&lt;/a&gt; and let my body work physically and my mind rest (usually, the opposite is true). And now that I’m back, I’ve switched focus to a few personal projects that I have really wanted to work on for a while but never found time.&lt;/p&gt;&lt;p&gt;One of these projects is to learn Rust. Clojure has made me lazy and it’s really high time for me to flex the language-learning muscles. But while the title says “Rust,” there is nothing Rust-specific about the tip I’m about to share: it can be applied to many programming languages.&lt;/p&gt;&lt;p&gt;I learn best by doing, so after learning the first few chapters of &lt;a href="https://doc.rust-lang.org/book/"&gt;the Rust book&lt;/a&gt;, I set off to write a simple but non-trivial program: a console-based tree viewer. The idea is to have a TUI that you could feed with a set of slash-separated paths:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;one/two
one/three/four
five/six
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and have it render the tree visually:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;├─ one
│  ├─ two
│  └─ three
│     └─ four
└─ five
   └─ six
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;allowing to scroll it, search it and (un)fold individual subtrees. The paths may come from the filesystem (e.g. you could pipe &lt;code&gt;find . -type f&lt;/code&gt; into it), but not necessarily: they might be S3 object paths, hierarchical names of RocksDB keys (my actual use case), or represent any other tree.&lt;/p&gt;&lt;p&gt;Today I hit a major milestone: I &lt;a href="https://github.com/nathell/treeviewer/commit/fb1332aa5bd0f695604522492ccd893dac28066a"&gt;wrote a function&lt;/a&gt;, &lt;code&gt;append_path&lt;/code&gt;, that, given a tree of strings and a slash-separated path, creates new nodes as needed and adds them to the tree. Needless to say, I didn’t get it right on the first attempt. I fought with the compiler and its borrow checker &lt;em&gt;a lot&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;I guess that’s a typical ordeal that a Rust newbie goes through. But along treeviewer’s code, I keep an org-mode file called &lt;code&gt;LEARN&lt;/code&gt; where I jot down things that I might want to remember for the future. So after getting &lt;code&gt;append_path&lt;/code&gt; right, I wanted to pause and look back at the failed attempts and the corresponding compiler errors, to try to make sense of them, armed with my new knowledge.&lt;/p&gt;&lt;p&gt;But… &lt;em&gt;which&lt;/em&gt; versions of the code caused &lt;em&gt;which&lt;/em&gt; errors? I had no idea! And the Emacs undo tree is really hard to dive in.&lt;/p&gt;&lt;p&gt;An obvious way out is to commit early and often. But this (1) requires a discipline that I don’t have at the moment, and (2) pollutes the Git history. So, instead, I automated it.&lt;/p&gt;&lt;p&gt;I’ve added a Makefile to my repo. Instead of &lt;code&gt;cargo run&lt;/code&gt;, I will now be compiling and executing the code via &lt;code&gt;make run&lt;/code&gt;. In addition to Cargo, this runs &lt;a href="https://github.com/nathell/treeviewer/blob/main/scripts/record.sh"&gt;a script&lt;/a&gt; that:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;Commits everything that’s uncommitted yet&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Creates an annotated tag with that commit, named &lt;code&gt;build-$TIMESTAMP&lt;/code&gt;, that serves as a snapshot of the code that was built&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Reverts the working tree to the state it was in (whatever was staged stays staged, whatever was unstaged remains unstaged)&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This workflow change has the nice property of being unintrusive. I can hack on the code, compile, commit and rebase to my heart’s delight. But when I need to look back at the most recent compilation attempts, all I need to do is &lt;code&gt;git tag&lt;/code&gt; and from there I can meditate on individual mistakes I made.&lt;/p&gt;&lt;p&gt;Why tags and not branches, one might ask? I guess this is a matter of personal preference. I opted for tags because I want to minimise the chance of accidentally pushing the branch. The resulting tags are technically dangling, which I don’t see as an issue: the older the build tag, the less likely I am to need it in the future, so I see myself cleaning up old builds every now and then.&lt;/p&gt;&lt;p&gt;When working with a language I’m proficient in, I don’t need this. But as a learning aid, I already see the idea as indispensable. Feel free to reuse it!&lt;/p&gt;&lt;/div&gt;</content>
  </entry>
</feed>
