<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Rusty Times]]></title><description><![CDATA[This is Mahdi's (aka Asder's) blog site where I post about tech-related topics. Oftentimes, these topics I'll cover will be in Rust, which is the primary language I code in.]]></description><link>https://asder8215.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 03 May 2026 17:35:56 GMT</lastBuildDate><atom:link href="https://asder8215.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[🦀 My First Contribution to the Official Rust Repo 🦀]]></title><description><![CDATA[January 11, 2026 marks the day that the first PR I made to the Rust repository officially got merged into the main branch. :)
Context
The PR I made revolves around std::fs::create_dir_all() function. To quote what the function does:

Recursively crea...]]></description><link>https://asder8215.com/my-first-contribution-to-the-official-rust-repo</link><guid isPermaLink="true">https://asder8215.com/my-first-contribution-to-the-official-rust-repo</guid><category><![CDATA[Rust]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Mahdi Ali-Raihan]]></dc:creator><pubDate>Mon, 12 Jan 2026 08:11:34 GMT</pubDate><content:encoded><![CDATA[<p>January 11, 2026 marks the day that the <a target="_blank" href="https://github.com/rust-lang/rust/pull/148196#event-21968479876">first PR</a> I made to the Rust repository officially got merged into the <code>main</code> branch. :)</p>
<h2 id="heading-context">Context</h2>
<p>The PR I made revolves around <a target="_blank" href="https://doc.rust-lang.org/std/fs/fn.create_dir_all.html"><code>std::fs::create_dir_all()</code></a> function. To quote what the function does:</p>
<blockquote>
<p>Recursively create a directory and all of its parent components if they are missing.</p>
<p>This function is not atomic. If it returns an error, any parent components it was able to create will remain.</p>
<p>If the empty path is passed to this function, it always succeeds without creating any directories.</p>
</blockquote>
<p>It’s essentially similar to what the <code>mkdir -p &lt;path&gt;</code> command does in the terminal.</p>
<p>Funnily enough, the reason why I made this PR was because of a PR I oversaw in uutils’ coreutils repository on <a target="_blank" href="https://github.com/uutils/coreutils/pull/8947#event-20648959716">fixing a stack overflow issue with mkdir -p on deeply nested directories</a>. Prior to this change for the mkdir command, uutils’ coreutils manually recursed up to the first non-existing path component and used <code>std::fs::create_dir</code> to create each missing directory:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Return true if the directory at `path` has been created by this call.</span>
<span class="hljs-comment">// `is_parent` argument is not used on windows</span>
<span class="hljs-meta">#[allow(unused_variables)]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">create_dir</span></span>(path: &amp;Path, is_parent: <span class="hljs-built_in">bool</span>, config: &amp;Config) -&gt; UResult&lt;()&gt; {
    <span class="hljs-keyword">let</span> path_exists = path.exists();
    ...
    <span class="hljs-keyword">if</span> path == Path::new(<span class="hljs-string">""</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(());
    }

    <span class="hljs-keyword">if</span> config.recursive {
        <span class="hljs-keyword">match</span> path.parent() {
            <span class="hljs-literal">Some</span>(p) =&gt; create_dir(p, <span class="hljs-literal">true</span>, config)?,
            <span class="hljs-literal">None</span> =&gt; {
                USimpleError::new(<span class="hljs-number">1</span>, translate!(<span class="hljs-string">"mkdir-error-failed-to-create-tree"</span>));
            }
        }
    }

    <span class="hljs-keyword">match</span> std::fs::create_dir(path) {
        <span class="hljs-literal">Ok</span>(()) =&gt; {
            ...
            <span class="hljs-literal">Ok</span>(())
        }
        <span class="hljs-literal">Err</span>(_) <span class="hljs-keyword">if</span> path.is_dir() =&gt; <span class="hljs-literal">Ok</span>(()),
        <span class="hljs-literal">Err</span>(e) =&gt; <span class="hljs-literal">Err</span>(e.into()),
    }
}
</code></pre>
<center> Some parts of the code is omitted for simplicity </center>

<p>As naoNao89 pointed out in the PR, the implementation of uutils’ <code>mkdir</code> command had room for a stack overflow issue with nested directories (in his testing, the overflow occurred at 200+ nested directories of <code>“/a”</code> repeated). The solution to this problem is to change the implementation of <code>mkdir -p</code> from creating directories and missing components from recursive to <em>iterative</em>; from allocating the path references in the stack to the <em>heap</em>.</p>
<p>Still, when I first took a look at how uutils’ initially implemented the <code>mkdir</code> command with <code>-p</code> flag set, I thought “why didn’t they just use <code>std::fs::create_dir_all()</code> instead of <code>std::fs::create_dir()</code>?” to create all the directory components with the recursive flag set. There would be no need to re-invent the wheel on creating the given directory and its missing parent components. On second glance, however, it clicked for me. For <code>mkdir</code>, it has other config options like permission bits to set on the directory once it is created. If <code>std::fs::create_dir_all()</code> were to report an error but successfully created some directories, then it could leave the directories in an incorrect state if config options like permission bits were set.</p>
<p>But surely, ignoring the config options for a moment, <code>std::fs::create_dir_all()</code> would have avoided this stack overflow issue, right?</p>
<h2 id="heading-rusts-stdfscreatedirall-implementation">Rust’s std::fs::create_dir_all() Implementation</h2>
<p>That would be an incorrect assumption to make! The following is the implementation of Rust’s <code>create_dir_all()</code>:</p>
<pre><code class="lang-rust">path<span class="hljs-meta">#[stable(feature = <span class="hljs-meta-string">"rust1"</span>, since = <span class="hljs-meta-string">"1.0.0"</span>)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">create_dir_all</span></span>&lt;P: <span class="hljs-built_in">AsRef</span>&lt;Path&gt;&gt;(path: P) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    DirBuilder::new().recursive(<span class="hljs-literal">true</span>).create(path.as_ref())
}

<span class="hljs-keyword">impl</span> DirBuilder {
    ...
    <span class="hljs-meta">#[stable(feature = <span class="hljs-meta-string">"dir_builder"</span>, since = <span class="hljs-meta-string">"1.6.0"</span>)]</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">recursive</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, recursive: <span class="hljs-built_in">bool</span>) -&gt; &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">self</span>.recursive = recursive;
        <span class="hljs-keyword">self</span>
    }

    <span class="hljs-meta">#[stable(feature = <span class="hljs-meta-string">"dir_builder"</span>, since = <span class="hljs-meta-string">"1.6.0"</span>)]</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">create</span></span>&lt;P: <span class="hljs-built_in">AsRef</span>&lt;Path&gt;&gt;(&amp;<span class="hljs-keyword">self</span>, path: P) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-keyword">self</span>._create(path.as_ref())
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">_create</span></span>(&amp;<span class="hljs-keyword">self</span>, path: &amp;Path) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.recursive { <span class="hljs-keyword">self</span>.create_dir_all(path) } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">self</span>.inner.mkdir(path) }
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">create_dir_all</span></span>(&amp;<span class="hljs-keyword">self</span>, path: &amp;Path) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-keyword">if</span> path == Path::new(<span class="hljs-string">""</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(());
        }

        <span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span>.inner.mkdir(path) {
            <span class="hljs-literal">Ok</span>(()) =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(()),
            <span class="hljs-literal">Err</span>(<span class="hljs-keyword">ref</span> e) <span class="hljs-keyword">if</span> e.kind() == io::ErrorKind::NotFound =&gt; {}
            <span class="hljs-literal">Err</span>(_) <span class="hljs-keyword">if</span> path.is_dir() =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(()),
            <span class="hljs-literal">Err</span>(e) =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(e),
        }
        <span class="hljs-keyword">match</span> path.parent() {
            <span class="hljs-literal">Some</span>(p) =&gt; <span class="hljs-keyword">self</span>.create_dir_all(p)?,
            <span class="hljs-literal">None</span> =&gt; {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(io::const_error!(
                    io::ErrorKind::Uncategorized,
                    <span class="hljs-string">"failed to create whole tree"</span>,
                ));
            }
        }
        <span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span>.inner.mkdir(path) {
            <span class="hljs-literal">Ok</span>(()) =&gt; <span class="hljs-literal">Ok</span>(()),
            <span class="hljs-literal">Err</span>(_) <span class="hljs-keyword">if</span> path.is_dir() =&gt; <span class="hljs-literal">Ok</span>(()),
            <span class="hljs-literal">Err</span>(e) =&gt; <span class="hljs-literal">Err</span>(e),
        }
    }
    ...
}
</code></pre>
<center> Key implementation of std::fs::create_dir_all(). <br /> Funny side note: the None block for match path.parent() is kind of useless because the .parent() only returns None on root paths ("/") or prefix, which this should already return Ok(()) or an error by the self.inner.mkdir() earlier </center>

<p>The standard library implementation of Rust’s <code>create_dir_all()</code>, as promised by the doc comments, uses recursion!</p>
<h2 id="heading-whats-wrong-with-recursion-here">What’s Wrong with Recursion Here?</h2>
<p>For all this talk about recursion causing issues, I guess I should go a bit deeper on why recursion may not be so pleasant for this function.</p>
<p>Because the nature of DirBuilder’s <code>create_dir_all()</code> function is recursive, <code>&amp;self</code> and <code>path</code> arguments are stored onto the stack frame repeatedly since it’s possible that the parent directories of the given path needs to be created before the current path can be created; it’s necessary to remember the paths you need to create, hence the allocation is required. This also means Tail Call Optimization (TCO) is not possible here, which means that the recursive block of code cannot be transformed into an iterative version to prevent allocating a new stack frame.</p>
<p>If we were to follow conventional path size limits (filesystems inherently do not have limits on how deeply nested a path is), then recursively creating directories would not pose an issue on:</p>
<ul>
<li><p>Linux-based OSs, which often has a default stack size of 8 MiB and a <code>PATH_MAX</code> of 4096 bytes;</p>
</li>
<li><p>MacOS, which has a default stack size of 8 MiB and maximum path of 1024 bytes;</p>
</li>
<li><p>Windows OS, which has a default stack size of 1 MB and a maximum path of 260 bytes</p>
</li>
</ul>
<p>However, if we consider enabling long paths on Windows OS and multithreading across all OSs, then we would need to be aware of the following:</p>
<ul>
<li><p>Linux-based OSs tends to to default to 8 MB per thread;</p>
</li>
<li><p>MacOS defaults to 512 KB stacks per thread (unrelating to main thread);</p>
</li>
<li><p>And Windows OS allows paths up to 32767 bytes with long path enabled and defaults to 1 MB stacks per thread</p>
</li>
</ul>
<p>On MacOS and Windows OS, it’s definitely possible for a potential stack overflow to occur through multithreaded code or with long paths on Windows. In fact, if we take this code</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::fs;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> dir_path = <span class="hljs-string">""</span>.to_string();

    <span class="hljs-keyword">for</span> letter <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..<span class="hljs-number">16000</span> {
        dir_path = <span class="hljs-built_in">format!</span>(<span class="hljs-string">"{}{}"</span>, dir_path, <span class="hljs-string">"/a"</span>);
    }
    fs::create_dir_all(&amp;dir_path);
}
</code></pre>
<p>and output the debug build assembly in <a target="_blank" href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=e2ec1f064eb3d745a60b14ddcd4514b6">Rust’s playground for std::fs::create_dir_all()</a></p>
<pre><code class="lang-rust">std::fs::DirBuilder::create:
    subq    $<span class="hljs-number">72</span>, %rsp
    movq    %rdi, <span class="hljs-number">8</span>(%rsp)
    movq    %rsi, <span class="hljs-number">32</span>(%rsp)
    movq    %rdx, <span class="hljs-number">40</span>(%rsp)
    movq    %rdi, <span class="hljs-number">48</span>(%rsp)
    leaq    <span class="hljs-number">32</span>(%rsp), %rdi
    callq    &lt;&amp;T <span class="hljs-keyword">as</span> core::convert::<span class="hljs-built_in">AsRef</span>&lt;U&gt;&gt;::as_ref
    movq    %rdx, <span class="hljs-number">16</span>(%rsp)
    movq    %rax, <span class="hljs-number">24</span>(%rsp)
    jmp    .LBB1_3

.LBB1_1:
    movq    <span class="hljs-number">56</span>(%rsp), %rdi
    callq    _Unwind_Resume@PLT
    movq    %rax, %rcx
    movl    %edx, %eax
    movq    %rcx, <span class="hljs-number">56</span>(%rsp)
    movl    %eax, <span class="hljs-number">64</span>(%rsp)
    jmp    .LBB1_1

.LBB1_3:
    movq    <span class="hljs-number">16</span>(%rsp), %rdx
    movq    <span class="hljs-number">24</span>(%rsp), %rsi
    movq    <span class="hljs-number">8</span>(%rsp), %rdi
    movq    std::fs::DirBuilder::_create@GOTPCREL(%rip), %rax
    callq    *%rax
    movq    %rax, (%rsp)
    jmp    .LBB1_4

.LBB1_4:
    movq    (%rsp), %rax
    addq    $<span class="hljs-number">72</span>, %rsp
    retq

std::fs::create_dir_all:
    subq    $<span class="hljs-number">72</span>, %rsp
    movq    %rdi, <span class="hljs-number">32</span>(%rsp)
    movb    $<span class="hljs-number">1</span>, <span class="hljs-number">55</span>(%rsp)
    movl    $<span class="hljs-number">511</span>, <span class="hljs-number">44</span>(%rsp)
    movb    $<span class="hljs-number">0</span>, <span class="hljs-number">48</span>(%rsp)
    movb    $<span class="hljs-number">1</span>, <span class="hljs-number">48</span>(%rsp)
    leaq    <span class="hljs-number">32</span>(%rsp), %rdi
    callq    &lt;&amp;T <span class="hljs-keyword">as</span> core::convert::<span class="hljs-built_in">AsRef</span>&lt;U&gt;&gt;::as_ref
    movq    %rdx, <span class="hljs-number">16</span>(%rsp)
    movq    %rax, <span class="hljs-number">24</span>(%rsp)
    jmp    .LBB2_3

.LBB2_1:
    movq    <span class="hljs-number">56</span>(%rsp), %rdi
    callq    _Unwind_Resume@PLT
    movq    %rax, %rcx
    movl    %edx, %eax
    movq    %rcx, <span class="hljs-number">56</span>(%rsp)
    movl    %eax, <span class="hljs-number">64</span>(%rsp)
    jmp    .LBB2_1

.LBB2_3:
    movq    <span class="hljs-number">16</span>(%rsp), %rdx
    movq    <span class="hljs-number">24</span>(%rsp), %rsi
    leaq    <span class="hljs-number">44</span>(%rsp), %rdi
    callq    std::fs::DirBuilder::create
    movq    %rax, <span class="hljs-number">8</span>(%rsp)
    jmp    .LBB2_4

.LBB2_4:
    movq    <span class="hljs-number">8</span>(%rsp), %rax
    addq    $<span class="hljs-number">72</span>, %rsp
    retq
</code></pre>
<p>From the instruction <code>subq $72, %rsp</code>, we can observe the following that on Linux systems, each recursive call to <code>std::fs::create_dir_all()</code> takes up 72 bytes of the stack frame. Without inspecting deeply into assembly output, we can infer that this stack allocation is reserved for things like a reference to a path to <code>mkdir</code> on, some permission bits on creation of a directory (as 511 in decimal is 777 in octal, which is used to give <code>rwx</code> permissions across owner, group, and others), and return addresses. Considering shadow space padding on Windows, each recursive call to <code>create_dir_all()</code> could easily take up in the ballpark of ~72-112 bytes. That means on Windows, if we were to try and create a path of <code>“/a”</code> repeated, the stack would overflow around ~8929-13889 function calls deep. In practical cases, it’s very rare to reach this deep in this function, but it exists in the realm of possibility!</p>
<h2 id="heading-the-fix-to-stdfscreatedirall">The Fix to std::fs::create_dir_all()</h2>
<p>The key to solving this issue is just like what was proposed in naoNao89’s PR: just make the function create directories iteratively. To be precise, we should turn DirBuilder’s <code>create_dir_all()</code> into an iterative function. The following is the implementation change to DirBuilder’s <code>create_dir_all()</code>:</p>
<pre><code class="lang-rust">   <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">create_dir_all</span></span>(&amp;<span class="hljs-keyword">self</span>, path: &amp;Path) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-comment">// if path's parent is None, it is "/" path, which should</span>
        <span class="hljs-comment">// return Ok immediately</span>
        <span class="hljs-keyword">if</span> path == Path::new(<span class="hljs-string">""</span>) || path.parent() == <span class="hljs-literal">None</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(());
        }

        <span class="hljs-keyword">let</span> ancestors = path.ancestors();
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> uncreated_dirs = <span class="hljs-number">0</span>;

        <span class="hljs-keyword">for</span> ancestor <span class="hljs-keyword">in</span> ancestors {
            <span class="hljs-comment">// for relative paths like "foo/bar", the parent of</span>
            <span class="hljs-comment">// "foo" will be "" which there's no need to invoke</span>
            <span class="hljs-comment">// a mkdir syscall on</span>
            <span class="hljs-keyword">if</span> ancestor == Path::new(<span class="hljs-string">""</span>) || ancestor.parent() == <span class="hljs-literal">None</span> {
                <span class="hljs-keyword">break</span>;
            }

            <span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span>.inner.mkdir(ancestor) {
                <span class="hljs-literal">Ok</span>(()) =&gt; <span class="hljs-keyword">break</span>,
                <span class="hljs-literal">Err</span>(e) <span class="hljs-keyword">if</span> e.kind() == io::ErrorKind::NotFound =&gt; uncreated_dirs += <span class="hljs-number">1</span>,
                <span class="hljs-comment">// we check if the err is AlreadyExists for two reasons</span>
                <span class="hljs-comment">//    - in case the path exists as a *file*</span>
                <span class="hljs-comment">//    - and to avoid calls to .is_dir() in case of other errs</span>
                <span class="hljs-comment">//      (i.e. PermissionDenied)</span>
                <span class="hljs-literal">Err</span>(e) <span class="hljs-keyword">if</span> e.kind() == io::ErrorKind::AlreadyExists &amp;&amp; ancestor.is_dir() =&gt; <span class="hljs-keyword">break</span>,
                <span class="hljs-literal">Err</span>(e) =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(e),
            }
        }

        <span class="hljs-comment">// collect only the uncreated directories w/o letting the vec resize</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> uncreated_dirs_vec = <span class="hljs-built_in">Vec</span>::with_capacity(uncreated_dirs);
        uncreated_dirs_vec.extend(ancestors.take(uncreated_dirs));

        <span class="hljs-keyword">for</span> uncreated_dir <span class="hljs-keyword">in</span> uncreated_dirs_vec.iter().rev() {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Err</span>(e) = <span class="hljs-keyword">self</span>.inner.mkdir(uncreated_dir) {
                <span class="hljs-keyword">if</span> e.kind() != io::ErrorKind::AlreadyExists || !uncreated_dir.is_dir() {
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(e);
                }
            }
        }

        <span class="hljs-literal">Ok</span>(())
    }
</code></pre>
<p>In order to preserve the behavior and time complexity of recursive version of <code>create_dir_all()</code> to the iterative version, I had to keep in mind that:</p>
<ul>
<li><p>Root path (<code>“/”</code>) and empty string (<code>““</code>) must just return with an <code>Ok(())</code></p>
</li>
<li><p>We must iterate upward to the first non-existing path to create and then we can iterate downward to create the missing path components</p>
</li>
<li><p>The errors returned by <code>self.inner.mkdir()</code> produced have different effects.</p>
<ul>
<li><p><code>io::ErrorKind::NotFound</code> tells us we need to create a missing parent component first</p>
</li>
<li><p><code>io::ErrorKind::AlreadyExists &amp;&amp; ancestor.is_dir()</code> tells us that we have reached the first ancestor directory that exists and we can start building the missing components there</p>
</li>
<li><p>Every other error is a valid error we should return impromptu</p>
</li>
</ul>
</li>
<li><p>We should only allocate onto the heap the required space to contain the remaining paths that we need to create</p>
</li>
</ul>
<p>The last point is pretty subtle on why it’s necessary (or more so efficient than necessary). In the recursive implementation of <code>create_dir_all()</code>, you can see that no extra allocation or re-copying is done for the path and parent components. If we used an empty <code>Vec</code> and kept pushing the paths that we need to <code>mkdir</code> on repeatedly, we would need to resize the <code>Vec</code> repeatedly to allow for more paths to be pushed onto the <code>Vec</code>; there would be unnecessary re-allocations of heap memory occurring here. Hence, a counter variable is used to track how many directories we have left to create, and we can then take from the ancestor iterator the exact number of directories and place that onto our <code>Vec</code>.</p>
<p>In an ideal world, we can make this function better and not need to use heap allocation for the remaining directories we need to create. We could just use the ancestor iterator directly and with the counter variable we can just create the given path and missing parent directories in a forward manner. But unfortunately, the <code>Ancestor&lt;‘_&gt;</code> iterator returned by <code>.ancestors()</code> is not a reversible iterator; repeatedly going backward from the iterator to create the missing directories would result in a <code>O(N²)</code> time complexity instead of <code>O(N)</code>. That said, this implementation matches the time and space complexity of the recursive version of <code>create_dir_all()</code>.</p>
<h2 id="heading-afterwords">Afterwords</h2>
<p>To be honest, it’s a bit surreal that a PR that I made got merged into the Official Rust Repo. I’ve only been programming in Rust as my primary language since summer 2024 (prior to that I mostly worked with Python and C since 2021), so there’s a lot of things that I still need to learn and get comfortable with, like lifetimes and proc macro. On top of that, I started contributing to open source software/projects during last October (uutils’ coreutils being my first!), so a lot of conventions of following contributing guidelines and communicating with people through GitHub were really new to me. So when I made this PR back in October, I thought a change like this might not be looked at or be merged in.</p>
<p>But seeing that this PR got merged in, it made me happy. I’m happy that the code I write can have impact on people— that I could even cause that sort of impact. I’m really glad to be a part of the open source community, and especially be a part of Rust community who have all been super cool to interact with and inspiring to see what projects they’ve worked on.</p>
<p>I hope to be able to contribute more to the open source community and write more blog posts!</p>
<h2 id="heading-informal-citations">Informal Citations</h2>
<ul>
<li><a target="_blank" href="https://www.atlantic.net/dedicated-server-hosting/why-is-the-default-stack-size-huge-in-linux/">Default Stack Sizes Across Linux OSs, MacOS, and Windows OS</a></li>
</ul>
]]></content:encoded></item></channel></rss>