<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Rust - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Rust - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 29 May 2026 23:03:52 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/rust/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Run Rust on Jupyter Notebooks ]]>
                </title>
                <description>
                    <![CDATA[ If you've ever wanted to combine the power of Rust with the interactive goodness of Jupyter notebooks, you're in the right place. Maybe you're tired of compiling every single time you want to test a s ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-run-rust-on-jupyter-notebooks/</link>
                <guid isPermaLink="false">699879483dc17c4862f498f9</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Jupyter Notebook  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WSL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Iwugo ]]>
                </dc:creator>
                <pubDate>Fri, 20 Feb 2026 15:10:00 +0000</pubDate>
                <media:content url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5e1e335a7a1d3fcc59028c64/6e411f5d-65a1-407d-a4f0-0beceb1e784b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've ever wanted to combine the power of Rust with the interactive goodness of Jupyter notebooks, you're in the right place. Maybe you're tired of compiling every single time you want to test a snippet, learn Rust in a more interactive way, or just have a crazy idea pop into your head like I do.</p>
<p>Most people think Jupyter is just for Python and data science stuff, but apparently you can run Rust in one, too.</p>
<p>In this tutorial, we’ll be taking a look at:</p>
<ol>
<li><p><a href="#heading-what-is-evcxr">What is EvCxR?</a></p>
</li>
<li><p><a href="#heading-how-to-install-the-rust-jupyter-kernel">How to Install the Rust Jupyter kernel</a></p>
</li>
<li><p><a href="#heading-step-4-write-your-first-rust-code">How to run your first Rust code in a notebook</a></p>
</li>
<li><p><a href="#heading-handy-tips-and-tricks">Handy Tips and Tricks</a></p>
</li>
<li><p><a href="#heading-common-issues-and-solutions">Common Issues and Solutions</a></p>
</li>
<li><p><a href="#heading-when-not-to-use-jupyter-for-rust">When NOT to Use Jupyter for Rust</a></p>
</li>
</ol>
<p><strong>Friendly Disclaimer</strong>: This tutorial assumes you know the basics of both Rust and Jupyter. If you break something, that's on you, mate 🙂.</p>
<p>So without further ado, let's jump in.</p>
<h2 id="heading-what-is-evcxr"><strong>What is EvCxR?</strong></h2>
<p>EvCxR (pronounced "Evaluator" to my fellow linguists’ horror) is a Rust REPL and Jupyter kernel. It's basically the magic that lets you run Rust code interactively in Jupyter notebooks instead of the traditional compile-run-debug cycle.</p>
<p>The name stands for "Evaluation Context for Rust", and it’s an open source project actively maintained on GitHub. Here are a few things that make this terribly named tool absolutely brilliant:</p>
<ol>
<li><p><strong>Interactive development:</strong> It lets you test Rust snippets without creating a whole project 🧪</p>
</li>
<li><p><strong>Prototyping:</strong> You can quickly try out ideas before committing to a full implementation 💡</p>
</li>
<li><p><strong>Data visualisation:</strong> And yes, you can even plot charts with Rust (more on that later) 📊</p>
</li>
</ol>
<h2 id="heading-how-to-install-the-rust-jupyter-kernel">How to Install the Rust Jupyter kernel</h2>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before we dive into the installation, make sure you have these sorted:</p>
<ol>
<li><p><strong>A Linux System:</strong> Or at least, Windows Subsystem for Linux (There’s a little note below for Windows users.)</p>
</li>
<li><p><strong>The Rust toolchain:</strong> You can get it from <a href="https://rustup.rs/">rustup.rs</a> if you haven't already</p>
</li>
<li><p><strong>Jupyter:</strong> Install via pip – <code>pip install jupyter</code></p>
</li>
<li><p><strong>Patience:</strong> This might take a minute or two ⏱️</p>
</li>
</ol>
<p>Once you’ve got all that, we can get rusty (pun intended).</p>
<p><strong>Note:</strong> If you’re using Windows, you’ll need to do a little extra to get started. Here’s the quick rundown:</p>
<ol>
<li><p>Go to <a href="https://visualstudio.microsoft.com/visual-cpp-build-tools/">https://visualstudio.microsoft.com/visual-cpp-build-tools/</a></p>
</li>
<li><p>Download and run the installer</p>
</li>
<li><p>Select <strong>"Desktop development with C++"</strong></p>
</li>
<li><p>Install it (it's large, ~5GB)</p>
</li>
</ol>
<h3 id="heading-step-1-install-evcxr"><strong>Step 1: Install EvCxR</strong></h3>
<p>Open your terminal and run this command:</p>
<pre><code class="language-rust">cargo install evcxr_jupyter
</code></pre>
<p>Now go grab a cup of joe ☕. This will take a few minutes as Cargo downloads and compiles everything. And don't panic if it seems stuck. Rust compilation is thorough but not particularly fast.</p>
<p>If you get any errors about missing system libraries, you might need to install some dependencies. On Ubuntu/Debian, try:</p>
<pre><code class="language-bash">sudo apt install jupyter-notebook jupyter-core python-ipykernel
sudo apt install cmake
</code></pre>
<p>On macOS with Homebrew:</p>
<pre><code class="language-bash">brew install cmake jupyter
</code></pre>
<h3 id="heading-step-2-install-the-jupyter-kernel"><strong>Step 2: Install the Jupyter Kernel</strong></h3>
<p>Once the installation finishes, you’ll need to register the EvCxR kernel with Jupyter:</p>
<pre><code class="language-bash">evcxr_jupyter --install
</code></pre>
<p>You should see output that looks something like this at the end:</p>
<pre><code class="language-plaintext">Installation complete
</code></pre>
<h3 id="heading-step-3-launch-jupyter-and-create-a-rust-notebook"><strong>Step 3: Launch Jupyter and Create a Rust Notebook</strong></h3>
<p>Let’s test out our baby. Fire up Jupyter:</p>
<pre><code class="language-bash">jupyter notebook
</code></pre>
<p>Your browser should open automatically (if it doesn't, copy the URL from the terminal).</p>
<p>In the Jupyter interface:</p>
<ol>
<li><p>Click <strong>New</strong> in the top right</p>
</li>
<li><p>Select <strong>Rust</strong> from the dropdown (or "evcxr" depending on your version)</p>
</li>
<li><p>A new notebook opens</p>
</li>
</ol>
<p>Welcome to interactive Rust! 🦀</p>
<h3 id="heading-step-4-write-your-first-rust-code"><strong>Step 4: Write Your First Rust Code</strong></h3>
<p>Let's start with a classic:</p>
<pre><code class="language-rust">println!("Hello my fellow Rustaceans! 🦀");
</code></pre>
<p>Hit <code>Shift + Enter</code> to run the cell. You should see the output appear below the cell. Simple as that.</p>
<p>Note that notebooks execute code at the top level, so you don’t have to wrap it around the <code>main()</code> function. If you still want to do that, you’re going to have to call it like this:</p>
<pre><code class="language-rust">fn main(){
    println!("Hello my fellow Rustaceans! 🦀");
}
//Calling the function
main()
</code></pre>
<p>Now let's try something more interesting:</p>
<pre><code class="language-rust">fn fibonacci(n: u32) -&gt; u32 {
    match n {
        0 =&gt; 0,
        1 =&gt; 1,
        _ =&gt; fibonacci(n - 1) + fibonacci(n - 2)
    }
}

for i in 0..10 {
    println!("fibonacci({}) = {}", i, fibonacci(i));
}
</code></pre>
<p>Run it and watch the Fibonacci sequence appear.</p>
<pre><code class="language-plaintext">fibonacci(0) = 0
fibonacci(1) = 1
fibonacci(2) = 1
fibonacci(3) = 2
fibonacci(4) = 3
fibonacci(5) = 5
fibonacci(6) = 8
fibonacci(7) = 13
fibonacci(8) = 21
fibonacci(9) = 34
</code></pre>
<h2 id="heading-handy-tips-and-tricks"><strong>Handy Tips and Tricks</strong></h2>
<p>Functions aren’t the only things that behave differently when using Rust in notebooks. Here are a few other things you might want to keep in mind:</p>
<h3 id="heading-variables-persist-between-cells">Variables Persist Between Cells</h3>
<p>Unlike traditional Rust compilation, variables you define in one cell stick around for the next cells:</p>
<pre><code class="language-rust">let mut counter = 0;
</code></pre>
<p>Then in the next cell:</p>
<pre><code class="language-rust">counter += 1;
println!("Counter: {}", counter);
</code></pre>
<p>The output would be:</p>
<pre><code class="language-plaintext">Counter: 1
</code></pre>
<p>This is great for building up complex examples step by step.</p>
<h3 id="heading-you-can-use-external-crates">You Can Use External Crates</h3>
<p>Add dependencies with the <code>:dep</code> command in one cell:</p>
<pre><code class="language-rust">:dep serde = { version = "1.0", features = ["derive"] }
:dep serde_json = "1.0"
</code></pre>
<p>Then use them normally in the next:</p>
<pre><code class="language-rust">use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Person {
    name: String,
    age: u32,
}

let person = Person {
    name: "Amina".to_string(),
    age: 24,
};

let json = serde_json::to_string(&amp;person).unwrap();
println!("{}", json);
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">{"name":"Amina","age":24}
</code></pre>
<p>Pretty neat, huh?</p>
<h3 id="heading-visualisation-support">Visualisation Support</h3>
<p>You can even create graphs. To get started, install the <code>plotters</code> crate:</p>
<pre><code class="language-rust">:dep plotters = { version = "0.3", default-features = false, features = ["evcxr", "all_series", "bitmap_backend", "bitmap_encoder"] }
</code></pre>
<p>Then create a simple sine graph:</p>
<pre><code class="language-rust">use plotters::prelude::*;

let root = SVGBackend::new("sine_wave.svg", (640, 480)).into_drawing_area();
root.fill(&amp;WHITE).unwrap();

let mut chart = ChartBuilder::on(&amp;root)
    .caption("Sine Wave", ("Arial", 20))
    .margin(5)
    .x_label_area_size(30)
    .y_label_area_size(30)
    .build_cartesian_2d(-3.14..3.14, -1.2..1.2)
    .unwrap();

chart.configure_mesh().draw().unwrap();

chart.draw_series(LineSeries::new(
    (-314..314).map(|x| {
        let x = x as f64 / 100.0;
        (x, x.sin())
    }),
    &amp;RED,
)).unwrap();

root.present().unwrap();
println!("Plot saved to sine_wave.svg");
</code></pre>
<p>Output:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771272251271/c07b1c22-4ea1-408c-984a-4179a47058d9.png" alt="Sine wave graph showing output of the code" style="display:block;margin:0 auto" width="640" height="480" loading="lazy">

<p><strong>A word on plotting:</strong> You can actually display plots directly inline in your notebook. But if you're using WSL with VSCode (like I do), inline plotting may not work properly due to rendering issues on the notebook interface. That’s why I used it as an svg file that I can easily view in my text editor.</p>
<h3 id="heading-checking-types">Checking Types</h3>
<p>Not sure what type something is? Use <code>:vars</code>. This shows all variables and their types:</p>
<pre><code class="language-rust">let x = vec![1, 2, 3];
</code></pre>
<pre><code class="language-rust">:vars
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Variable	    Type
       x	Vec&lt;i32&gt;
</code></pre>
<h2 id="heading-common-issues-and-solutions">Common Issues and Solutions</h2>
<h3 id="heading-compilation-errors-everywhere">Compilation Errors Everywhere</h3>
<p>If you're getting weird compilation errors, remember:</p>
<ul>
<li><p>Each cell is compiled separately</p>
</li>
<li><p>You might need to reimport things in each cell</p>
</li>
</ul>
<h3 id="heading-slow-execution">Slow Execution</h3>
<p>The first time you run code in a session, it's slow due to the compilation overhead. Subsequent runs are faster. If it's really slow, you might want to:</p>
<ul>
<li><p>Use release mode: <code>:opt 2</code></p>
</li>
<li><p>Reduce dependency features to only what you need</p>
</li>
<li><p>Consider if Jupyter is the right tool for your use case</p>
</li>
</ul>
<h3 id="heading-dependencies-not-loading">Dependencies Not Loading</h3>
<p>If a crate won't load:</p>
<ul>
<li><p>Make sure the version exists on <a href="http://crates.io">crates.io</a></p>
</li>
<li><p>Check your internet connection (it needs to download)</p>
</li>
<li><p>Try specifying features explicitly</p>
</li>
<li><p>Clear the cargo cache if things get really wonky: <code>rm -rf ~/.evcxr</code></p>
</li>
</ul>
<h2 id="heading-when-not-to-use-jupyter-for-rust"><strong>When NOT to Use Jupyter for Rust</strong></h2>
<p>Jupyter notebooks are great for learning and experimenting, but they're not always the best choice in:</p>
<ul>
<li><p><strong>Production code:</strong> Use proper projects with cargo</p>
</li>
<li><p><strong>Performance-critical code:</strong> The overhead isn't worth it</p>
</li>
<li><p><strong>Large applications:</strong> Notebooks get very messy, very fast</p>
</li>
<li><p><strong>Team collaboration:</strong> Version control with notebooks is quite the nightmare</p>
</li>
</ul>
<p>Stick to notebooks for prototyping and quick experiments. For anything serious, fire up your favourite editor and create a proper Rust project.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Let's summarise what you've learned:</p>
<ol>
<li><p>How to install the EvCxR Jupyter kernel</p>
</li>
<li><p>How to create and run Rust notebooks</p>
</li>
<li><p>How to use external crates in notebooks</p>
</li>
<li><p>Tips and tricks for interactive Rust development</p>
</li>
</ol>
<p>Jupyter notebooks make Rust more accessible for learning and experimentation. Give it a go next time you want to try out a quick Rust snippet without the ceremony of creating a full project. And with that, we've come to the end of this tutorial.</p>
<p>Cheers.</p>
<h2 id="heading-resources">Resources</h2>
<ol>
<li><p><a href="https://github.com/evcxr/evcxr">EvCxR GitHub Repository</a></p>
</li>
<li><p><a href="https://doc.rust-lang.org/book/">Rust Book</a></p>
</li>
<li><p><a href="https://jupyter.org/documentation">Jupyter Documentation</a></p>
</li>
</ol>
<h2 id="heading-acknowledgements">Acknowledgements</h2>
<p>Thanks to <a href="https://www.linkedin.com/in/a-n-u-o/">Anuoluwapo Victor</a>, <a href="https://www.linkedin.com/in/a-n-u-o/">Chinaza Nwukwa,</a> <a href="https://www.linkedin.com/in/chinaza-nwukwa-22a256230/">Holumidey Mer</a><a href="https://www.linkedin.com/in/mercy-holumidey-88a542232/">cy</a>, <a href="https://www.linkedin.com/in/mercy-holumidey-88a542232/">Favour Ojo,</a> <a href="https://www.linkedin.com/in/favour-ojo-906883199/">Georgina</a> <a href="https://www.linkedin.com/in/georgina-awani-254974233/">Awani</a>, <a href="https://www.linkedin.com/in/georgina-awani-254974233/">and my family</a> for the inspiration, support and knowledge used to put this post together.</p>
<p>And thanks to the EvCxR project maintainers for making this possible, the Rust community for being awesome, and to anyone reading this for wanting to learn. You inspire me daily.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Local-First CLI Financial Tracker with Rust [Full Handbook] ]]>
                </title>
                <description>
                    <![CDATA[ Most financial apps store your sensitive data on remote servers. This requires you to trust a company with your records and rely on their service staying online. But if you build a local-first application, you can keep your data on your own machine i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-local-first-cli-financial-tracker-with-rust/</link>
                <guid isPermaLink="false">696183e6f3839d7c9a8133ff</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Stephen Emmanuel ]]>
                </dc:creator>
                <pubDate>Fri, 09 Jan 2026 22:40:38 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767998415383/82c48f39-cd5e-4f66-af83-2b65bafccd65.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most financial apps store your sensitive data on remote servers. This requires you to trust a company with your records and rely on their service staying online. But if you build a local-first application, you can keep your data on your own machine in a format you can actually read.</p>
<p>In this guide, you’ll learn how to create a financial tracker that runs entirely in your terminal. You’ll use Rust to build a system that saves transactions to a local JSON file, ensuring that you have total ownership of your information.</p>
<p>Along the way, you’ll learn how to use the Rust type system to validate financial data and handle file errors gracefully. You’ll also use the Clap library to create a professional command line interface. By the time you finish, you’ll understand how to manage local state, serialize data with Serde, and structure a modular Rust application.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-commands-youll-build">Commands You’ll Build</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-set-up-the-project">Step 1: Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-design-the-data-model">Step 2: Design the Data Model</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-add-methods-to-the-trackerdata">Add Methods to the TrackerData</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-handle-errors-properly">Step 3: Handle Errors Properly</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-map-system-errors-to-custom-errors">Map System Errors to Custom Errors</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prepare-for-error-output">Prepare for Error Output</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-create-file-operations">Step 4: Create File Operations</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-add-json-utility-functions">Add JSON Utility Functions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-register-the-utilities">Register the Utilities</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-set-up-the-cli-structure">Step 5: Set Up the CLI Structure</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-the-command-architecture">The Command Architecture</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-manage-paths-with-global-context">Manage Paths with Global Context</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-register-the-command-system">Register the Command System</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-create-response-types">Step 6: Create Response Types</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-define-the-response-structures">Define the Response Structures</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-implement-the-output-module">Implement the Output Module</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-update-the-library-registration">Update the Library Registration</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-7-create-argument-parsing-helpers">Step 7: Create Argument Parsing Helpers</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-implement-custom-data-parsers">Implement Custom Data Parsers</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-8-implement-the-init-command">Step 8: Implement the Init Command</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-9-implement-the-add-command">Step 9: Implement the Add Command</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-10-implement-the-list-command">Step 10: Implement the List Command</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-11-implement-the-update-command">Step 11: Implement the Update Command</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-12-implement-the-delete-command">Step 12: Implement the Delete Command</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-13-implement-subcategory-commands">Step 13: Implement Subcategory Commands</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-list-subcategories">List Subcategories</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-add-subcategories">Add Subcategories</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-delete-subcategories">Delete Subcategories</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-rename-subcategories">Rename Subcategories</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-14-implement-the-total-command">Step 14: Implement the Total Command</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-15-wire-up-the-main-function">Step 15: Wire Up the Main Function</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-test-your-application">Test Your Application</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-install-the-binary">Install the Binary</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-whats-next-and-advanced-features">What's Next and Advanced Features</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-advanced-features-to-explore">Advanced Features to Explore</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, you should have a basic comfort level with Rust syntax. You don’t need to be an expert, but you should understand how to use variables, functions, and structs.</p>
<p>You’ll also need the following tools and knowledge:</p>
<ul>
<li><p>Rust installed (version 1.70 or later). If you don't have Rust installed, follow the <a target="_blank" href="https://rust-book.cs.brown.edu/ch01-01-installation.html">official installation guide</a>. You can verify your installation by running <code>rustc --version</code> in your terminal.</p>
</li>
<li><p>Familiarity with command-line tools and terminal usage.</p>
</li>
<li><p>Basic knowledge of the JSON format.</p>
</li>
</ul>
<h2 id="heading-commands-youll-build">Commands You’ll Build</h2>
<p>This tutorial will guide you on how to implement these commands step-by-step:</p>
<ul>
<li><p><code>init</code>: Initializes a new tracker and creates your storage file.</p>
</li>
<li><p><code>add</code>: Saves new income or expense records to your data.</p>
</li>
<li><p><code>list</code>: Allows you to view and filter your saved transactions.</p>
</li>
<li><p><code>update</code>: Modifies existing records in your storage.</p>
</li>
<li><p><code>delete</code>: Removes specific records from your history.</p>
</li>
<li><p><code>subcategory</code>: Manages custom subcategories (list, add, delete, rename)</p>
</li>
<li><p><code>total</code>: Calculates your financial totals and net balance.</p>
</li>
</ul>
<h2 id="heading-step-1-set-up-the-project">Step 1: Set Up the Project</h2>
<p>To start, you need to create a new Rust project. Open your terminal and run these commands:</p>
<pre><code class="lang-bash">cargo new fintrack
<span class="hljs-built_in">cd</span> fintrack
</code></pre>
<p>This creates a new directory called <code>fintrack</code> with a basic Rust project structure. <code>cargo</code> is Rust's package manager and build tool. It handles dependencies, compilation, and project management.</p>
<p>Now, open <code>Cargo.toml</code> in your editor. This file defines the metadata and libraries for your project. Add the following dependencies that your application will need:</p>
<pre><code class="lang-toml"><span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"fintrack"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"1.0.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">chrono</span> = <span class="hljs-string">"0.4.42"</span>
<span class="hljs-attr">clap</span> = { version = <span class="hljs-string">"4.5.53"</span>, features = [<span class="hljs-string">"derive"</span>] }
<span class="hljs-attr">dirs</span> = <span class="hljs-string">"6.0.0"</span>
<span class="hljs-attr">serde</span> = { version = <span class="hljs-string">"1.0.228"</span>, features = [<span class="hljs-string">"derive"</span>] }
<span class="hljs-attr">serde_json</span> = <span class="hljs-string">"1.0.148"</span>
<span class="hljs-attr">strum</span> = { version = <span class="hljs-string">"0.26"</span>, features = [<span class="hljs-string">"derive"</span>] }
</code></pre>
<p>Here’s what each dependency does in your project:</p>
<ul>
<li><p><code>chrono</code>: Handles dates and times. You'll use it to parse dates from user input and format them for display.</p>
</li>
<li><p><code>clap</code>: A library for building command-line interfaces. It manages the process of parsing and validating the arguments you type into the terminal.</p>
</li>
<li><p><code>dirs</code>: Provides a cross-platform way to find the user's home directory, where you'll store the tracker data.</p>
</li>
<li><p><code>serde</code> and <code>serde_json</code>: <code>serde</code> is Rust's serialization framework. Combined with <code>serde_json</code>, it lets you convert Rust structs to JSON and back. This is how you'll save and load your tracker data.</p>
</li>
<li><p><code>strum</code>: Provides macros to automatically generate useful code for enums, like converting them to strings and parsing strings into enums.</p>
</li>
</ul>
<p>The <code>features = ["derive"]</code> for <code>clap</code> and <code>serde</code> enables their derive macros, which will let you use attributes like <code>#[derive(...)]</code> to automatically generate the code needed for parsing and data conversion.</p>
<h2 id="heading-step-2-design-the-data-model">Step 2: Design the Data Model</h2>
<p>Before writing any command logic, you’ll want to define the structure of the data your tracker will store. In Rust, you use structs to group related data much like a record in a database, and <strong>enums</strong> to represent values that can only be one of several fixed variants.</p>
<p>Create a new file src/models.rs and add the code to define a record:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> chrono::NaiveDate;
<span class="hljs-keyword">use</span> serde::{Deserialize, Serialize};
<span class="hljs-keyword">use</span> std::collections::HashMap;

<span class="hljs-meta">#[derive(Debug, Clone, Serialize, Deserialize)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Record</span></span> {
    <span class="hljs-keyword">pub</span> id: <span class="hljs-built_in">usize</span>,
    <span class="hljs-keyword">pub</span> category: <span class="hljs-built_in">usize</span>,
    <span class="hljs-keyword">pub</span> amount: <span class="hljs-built_in">f64</span>,
    <span class="hljs-keyword">pub</span> subcategory: <span class="hljs-built_in">usize</span>,
    <span class="hljs-keyword">pub</span> description: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> date: <span class="hljs-built_in">String</span>,
}
</code></pre>
<p>This Record struct represents a single income or expense transaction. The <code>#[derive(...)]</code> attribute automatically implements traits that allow you to print the struct for debugging, copy it, and convert it to or from JSON. The <code>pub</code> keyword ensures that these fields are accessible to the other modules you will build.</p>
<p>Next, add the main data structure to the <code>src/models.rs</code> file:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug, Clone, Serialize, Deserialize)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">TrackerData</span></span> {
    <span class="hljs-keyword">pub</span> version: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> currency: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> created_at: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> last_modified: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> opening_balance: <span class="hljs-built_in">f64</span>,
    <span class="hljs-keyword">pub</span> categories: HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">usize</span>&gt;,
    <span class="hljs-keyword">pub</span> subcategories_by_id: HashMap&lt;<span class="hljs-built_in">usize</span>, <span class="hljs-built_in">String</span>&gt;,
    <span class="hljs-keyword">pub</span> subcategories_by_name: HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">usize</span>&gt;,
    <span class="hljs-keyword">pub</span> next_subcategory_id: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> records: <span class="hljs-built_in">Vec</span>&lt;Record&gt;,
    <span class="hljs-keyword">pub</span> next_record_id: <span class="hljs-built_in">usize</span>,
}
</code></pre>
<p>This struct holds the state of the entire application. It uses a HashMap for categories and subcategories to allow for fast lookups by name or ID. All individual transactions are stored in the <code>records</code> vector, which can grow dynamically as you add more data.</p>
<p>Now, add enums to handle your fixed categories and supported currencies:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(clap::ValueEnum, Clone, Debug, strum::Display, strum::EnumString)]</span>
<span class="hljs-meta">#[strum(serialize_all = <span class="hljs-meta-string">"lowercase"</span>, ascii_case_insensitive)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Category</span></span> {
    Income,
    Expenses,
}

<span class="hljs-meta">#[derive(clap::ValueEnum, Clone, Debug, strum::Display, strum::EnumString)]</span>
<span class="hljs-meta">#[strum(serialize_all = <span class="hljs-meta-string">"UPPERCASE"</span>, ascii_case_insensitive)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Currency</span></span> {
    NGN,
    USD,
    GBP,
    EUR,
    CAD,
    AUD,
    JPY,
}
</code></pre>
<p>These enums ensure the user can only input valid categories or currencies. The strum attributes handle the conversion between terminal input strings and your Rust code, while <code>clap::ValueEnum</code> allows these types to work directly with your command-line arguments.</p>
<h3 id="heading-add-methods-to-the-trackerdata">Add Methods to the TrackerData</h3>
<p>To interact with this data in the <code>TrackerData</code> struct, you need to add methods using an <code>impl</code> block. These methods will handle adding records and calculating totals:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> TrackerData {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">push_record</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, record: Record) -&gt; &amp;<span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">self</span>.records.push(record);
        <span class="hljs-keyword">self</span>
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">category_id</span></span>(&amp;<span class="hljs-keyword">self</span>, category: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">usize</span> {
        <span class="hljs-keyword">self</span>.categories[category]
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">miscellaneous_subcategory_id</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">usize</span>&gt; {
        <span class="hljs-keyword">self</span>.subcategories_by_name.get(<span class="hljs-string">"miscellaneous"</span>).copied()
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">subcategory_id</span></span>(&amp;<span class="hljs-keyword">self</span>, name: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">usize</span>&gt; {
        <span class="hljs-keyword">self</span>.subcategories_by_name.get(&amp;name.to_lowercase()).copied()
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">category_name</span></span>(&amp;<span class="hljs-keyword">self</span>, id: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">self</span>.categories.iter().find(|(_, v)| **v == id).map(|(k, _)| k)
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">subcategory_name</span></span>(&amp;<span class="hljs-keyword">self</span>, id: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">self</span>.subcategories_by_id.get(&amp;id)
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">totals</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; (<span class="hljs-built_in">f64</span>, <span class="hljs-built_in">f64</span>) {
        <span class="hljs-keyword">self</span>.records.iter().fold((<span class="hljs-number">0.0</span>, <span class="hljs-number">0.0</span>), |<span class="hljs-keyword">mut</span> acc, r| {
            <span class="hljs-keyword">if</span> r.category == <span class="hljs-number">1</span> {
                acc.<span class="hljs-number">0</span> += r.amount;
            } <span class="hljs-keyword">else</span> {
                acc.<span class="hljs-number">1</span> += r.amount;
            }
            acc
        })
    }
}
</code></pre>
<p>These methods utilize key Rust patterns to manage the tracker's state:</p>
<ul>
<li><p><code>&amp;mut self</code> is used when you need to modify the data, such as pushing a new record into the vector.</p>
</li>
<li><p><code>Option</code> handles cases where a value might not exist, returning <code>Some(value)</code> or <code>None</code>.</p>
</li>
<li><p><code>iter()</code> and <code>fold</code> are used in the <code>totals()</code> method to process all records and accumulate the total income and expenses into a single tuple <code>(f64, f64)</code> representing total income and total expenses.</p>
</li>
</ul>
<p>Finally, add a helper function to create the default tracker JSON structure. Add this to <code>src/models.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default_tracker_json</span></span>(currency: &amp;Currency, opening_balance: <span class="hljs-built_in">f64</span>) -&gt; serde_json::Value {
    serde_json::json!({
        <span class="hljs-string">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-string">"currency"</span>: currency.to_string(),
        <span class="hljs-string">"opening_balance"</span>: opening_balance,
        <span class="hljs-string">"created_at"</span>: chrono::Utc::now().to_rfc3339(),
        <span class="hljs-string">"last_modified"</span>: chrono::Utc::now().to_rfc3339(),
        <span class="hljs-string">"categories"</span>: {
            <span class="hljs-string">"income"</span>: <span class="hljs-number">1</span>,
            <span class="hljs-string">"expenses"</span>: <span class="hljs-number">2</span>
        },
        <span class="hljs-string">"subcategories_by_id"</span>: {
            <span class="hljs-string">"1"</span>: <span class="hljs-string">"miscellaneous"</span>
        },
        <span class="hljs-string">"subcategories_by_name"</span>: {
            <span class="hljs-string">"miscellaneous"</span>: <span class="hljs-number">1</span>
        },
        <span class="hljs-string">"records"</span>: [],
        <span class="hljs-string">"next_record_id"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-string">"next_subcategory_id"</span>: <span class="hljs-number">2</span>
    })
}
</code></pre>
<p>Then, register this module in your <code>src/lib.rs</code> file so the rest of your application can use it:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> models;
</code></pre>
<h2 id="heading-step-3-handle-errors-properly">Step 3: Handle Errors Properly</h2>
<p>In a financial application, error handling is critical to ensure you don’t lose or corrupt your data. Rust uses a <code>Result</code> type to handle operations that might fail. A <code>Result</code> is either an <code>Ok</code> containing the successful value or an <code>Err</code> containing the error details. This structure forces you to address potential failures explicitly before your code will compile.</p>
<p>Create a new file named <code>src/error.rs</code> and start with the necessary imports:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::io;
</code></pre>
<p>Now, define your custom error types using enums:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">ValidationErrorKind</span></span> {
    AmountTooSmall { amount: <span class="hljs-built_in">f64</span> },
    InvalidDate { provided: <span class="hljs-built_in">String</span>, expected_format: <span class="hljs-built_in">String</span> },
    SubcategoryNotFound { name: <span class="hljs-built_in">String</span> },
    SubcategoryAlreadyExists { name: <span class="hljs-built_in">String</span> },
    RecordNotFound { id: <span class="hljs-built_in">usize</span> },
    SubcategoryHasRecords { name: <span class="hljs-built_in">String</span>, count: <span class="hljs-built_in">usize</span> },
    CannotDeleteMiscellaneous,
    CategoryImmutable { category: <span class="hljs-built_in">usize</span> },
    InvalidCategoryName { name: <span class="hljs-built_in">String</span>, reason: <span class="hljs-built_in">String</span> },
    InvalidName { name: <span class="hljs-built_in">String</span>, reason: <span class="hljs-built_in">String</span> },
    InvalidAmount { reason: <span class="hljs-built_in">String</span> },
    TrackerAlreadyInitialized,
    InvalidSubcommand { subcommand: <span class="hljs-built_in">String</span> },
}

<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">CliError</span></span> {
    FileNotFound(<span class="hljs-built_in">String</span>),
    InvalidJson(<span class="hljs-built_in">String</span>),
    ValidationError(ValidationErrorKind),
    PermissionDenied(<span class="hljs-built_in">String</span>),
    CorruptedData { backup_restored: <span class="hljs-built_in">bool</span>, timestamp: <span class="hljs-built_in">String</span> },
    FileAlreadyExists,
    Other(<span class="hljs-built_in">String</span>),
}
</code></pre>
<p>This nested structure allows you to categorize every possible failure that can occur during the execution of your program. The CliError enum acts as the top-level container for all errors in the application. It handles errors like missing files, denied permissions, validation errors, file existence conflicts, and so on.</p>
<p>One specific variant, <code>ValidationError</code>, carries a <code>ValidationErrorKind</code> as its payload. This allows you to group all validation-specific failures (such as invalid date formats, duplicate subcategory names, or attempts to delete protected system categories) under a single error type while still preserving the specific details of what went wrong.</p>
<p>Structuring your errors this way allows you to report exactly what caused a failure alongside the specific data that triggered it. For example, a validation error can include the exact amount or date that failed your rules, while a system error can pinpoint the specific file path or permission issue that stopped the program.</p>
<h3 id="heading-map-system-errors-to-custom-errors">Map System Errors to Custom Errors</h3>
<p>To keep your application code clean, you can use the <code>From</code> trait to automatically convert low-level system errors into your custom <code>CliError</code>. This allows you to use the <code>?</code> operator later in your logic to propagate errors gracefully.</p>
<p>Add these implementations to <code>src/error.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;std::io::Error&gt; <span class="hljs-keyword">for</span> CliError {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(err: std::io::Error) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">match</span> err.kind() {
            std::io::ErrorKind::NotFound =&gt; CliError::FileNotFound(err.to_string()),
            std::io::ErrorKind::PermissionDenied =&gt; CliError::PermissionDenied(err.to_string()),
            std::io::ErrorKind::AlreadyExists =&gt; CliError::FileAlreadyExists,
            <span class="hljs-comment">// ... add more here as is required.</span>
            _ =&gt; CliError::Other(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"IO error: {}"</span>, err)),
        }
    }
}

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;serde_json::Error&gt; <span class="hljs-keyword">for</span> CliError {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(err: serde_json::Error) -&gt; <span class="hljs-keyword">Self</span> {
        CliError::InvalidJson(err.to_string())
    }
}
</code></pre>
<p>The <code>match</code> block inside the <code>std::io::Error</code> implementation allows you to inspect the system error and categorize it correctly. If the system reports a "NotFound" error, your application transforms it into a <code>CliError::FileNotFound</code>. This ensures that your user-facing messages remain consistent.</p>
<h3 id="heading-prepare-for-error-output">Prepare for Error Output</h3>
<p>Finally, add a method signature to the <code>CliError</code> block. This will later connect your error logic to a dedicated output module that formats these errors for the terminal:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> CliError {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">write_to</span></span>(&amp;<span class="hljs-keyword">self</span>, writer: &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">impl</span> std::io::Write) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
        crate::output::write_error(<span class="hljs-keyword">self</span>, writer)
    }
}
</code></pre>
<p>The <code>&amp;mut impl std::io::Write</code> parameter is a flexible way to say this method can write to any output stream, whether it’s the standard error stream in the terminal or a log file.</p>
<p>Register the error module in your <code>src/lib.rs</code> file so it’s available to the rest of your project:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> models;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> error;
</code></pre>
<h2 id="heading-step-4-create-file-operations">Step 4: Create File Operations</h2>
<p>To manage your tracker data, you need a reliable way to read and write JSON files. Instead of repeating file logic in every command, you’ll create a trait. In Rust, traits allow you to add new methods to existing types. Here, you’ll add custom file-handling methods directly to <code>Path</code> and <code>PathBuf</code>.</p>
<p>First, create a new directory named <code>src/utils</code> and create a file inside it called <code>src/utils/file.rs</code>. Start with the necessary imports:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::{
  fs::{<span class="hljs-keyword">self</span>, File},
  io::{<span class="hljs-keyword">self</span>, prelude::*},
  path::Path,
};

<span class="hljs-keyword">use</span> serde_json::Value;

<span class="hljs-keyword">use</span> crate::CliError;
</code></pre>
<p>Now, define and implement the FilePath trait:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">FilePath</span></span>: <span class="hljs-built_in">AsRef</span>&lt;Path&gt; {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">create_file_if_not_exists</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;File&gt; {
        <span class="hljs-keyword">let</span> path = <span class="hljs-keyword">self</span>.as_ref();
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        File::options().write(<span class="hljs-literal">true</span>).create_new(<span class="hljs-literal">true</span>).open(path)
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">read_file</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;File&gt; {
        File::options().read(<span class="hljs-literal">true</span>).open(<span class="hljs-keyword">self</span>.as_ref())
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">open_read_write</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;File&gt; {
        File::options().read(<span class="hljs-literal">true</span>).write(<span class="hljs-literal">true</span>).open(<span class="hljs-keyword">self</span>.as_ref())
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">open_read</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;File&gt; {
        File::options().read(<span class="hljs-literal">true</span>).open(<span class="hljs-keyword">self</span>.as_ref())
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">delete_if_exists</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-keyword">let</span> path = <span class="hljs-keyword">self</span>.as_ref();
        <span class="hljs-keyword">if</span> !path.exists() {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(());
        }
        <span class="hljs-keyword">if</span> path.is_dir() {
            fs::remove_dir_all(path)?;
        } <span class="hljs-keyword">else</span> {
            fs::remove_file(path)?;
        }
        <span class="hljs-literal">Ok</span>(())
    }
}

<span class="hljs-keyword">impl</span>&lt;P: <span class="hljs-built_in">AsRef</span>&lt;Path&gt;&gt; FilePath <span class="hljs-keyword">for</span> P {}
</code></pre>
<p>This "blanket implementation" at the end is powerful. It ensures that any type capable of representing a file path, like a <code>PathBuf</code> or a standard <code>String</code>, automatically gains these methods.</p>
<p>Throughout these methods, you use the <code>?</code> operator. This is Rust’s shorthand for error propagation. If an operation like <code>create_dir_all fails</code>, the ? immediately returns the error from the function. If it succeeds, the program continues to the next line. This keeps your logic flat and readable without nested error checks.</p>
<h3 id="heading-add-json-utility-functions">Add JSON Utility Functions</h3>
<p>Writing financial data to a file requires precision. You must ensure that you are completely overwriting the old data rather than just appending to it. Add this helper function to <code>src/utils/file.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">write_json_to_file</span></span>(json: &amp;Value, file: &amp;<span class="hljs-keyword">mut</span> File) -&gt; <span class="hljs-built_in">Result</span>&lt;(), CliError&gt; {
    <span class="hljs-keyword">let</span> json_string = serde_json::to_string_pretty(&amp;json)?;

    file.seek(io::SeekFrom::Start(<span class="hljs-number">0</span>))?;
    file.set_len(<span class="hljs-number">0</span>)?;
    file.write_all(json_string.as_bytes())?;

    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<p>The <code>seek</code> call moves the file pointer back to the very beginning, and <code>set_len(0)</code> truncates the file to zero bytes. Using <code>to_string_pretty</code> ensures your JSON file is human-readable, which fits the local-first goal of keeping your data accessible.</p>
<h3 id="heading-register-the-utilities">Register the Utilities</h3>
<p>To make these tools available to the rest of your application, you need to set up the module tree. Create <code>src/utils.rs</code> and add this line:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> file;
</code></pre>
<p>Then, update your <code>src/lib.rs</code> file to include the new utils module and export the types you've built so far:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> models;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> error;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> utils;

<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> error::{CliError, ValidationErrorKind};
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> models::{Category, Currency, Record, TrackerData};
</code></pre>
<h2 id="heading-step-5-set-up-the-cli-structure">Step 5: Set Up the CLI Structure</h2>
<p>In this step, you will organize the interface that allows users to interact with your code. Building a CLI is more than just reading strings. It involves mapping specific terminal commands to the internal logic of your application.</p>
<h3 id="heading-the-command-architecture">The Command Architecture</h3>
<p>You’ll follow a modular pattern where each command has its own definition and execution logic. This separation ensures that adding a new feature in the future doesn’t break your existing commands.</p>
<p>Create a file named src/commands.rs. This file acts as a central dispatcher that declares your command modules and routes terminal input to the correct function:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> crate::{CliResult, command_prelude::*};
<span class="hljs-keyword">use</span> clap::{ArgMatches, Command};

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Exec</span></span> = <span class="hljs-function"><span class="hljs-keyword">fn</span></span>(&amp;<span class="hljs-keyword">mut</span> GlobalContext, &amp;ArgMatches) -&gt; CliResult;

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; <span class="hljs-built_in">Vec</span>&lt;Command&gt; {
    <span class="hljs-built_in">vec!</span>[
        init::cli(),
        add::cli(),
        list::cli(),
        update::cli(),
        delete::cli(),
        subcategory::cli(),
        total::cli(),
    ]
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">build_exec</span></span>(cmd: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;Exec&gt; {
    <span class="hljs-keyword">match</span> cmd {
        <span class="hljs-string">"init"</span> =&gt; <span class="hljs-literal">Some</span>(init::exec),
        <span class="hljs-string">"add"</span> =&gt; <span class="hljs-literal">Some</span>(add::exec),
        <span class="hljs-string">"list"</span> =&gt; <span class="hljs-literal">Some</span>(list::exec),
        <span class="hljs-string">"update"</span> =&gt; <span class="hljs-literal">Some</span>(update::exec),
        <span class="hljs-string">"delete"</span> =&gt; <span class="hljs-literal">Some</span>(delete::exec),
        <span class="hljs-string">"subcategory"</span> =&gt; <span class="hljs-literal">Some</span>(subcategory::exec),
        <span class="hljs-string">"total"</span> =&gt; <span class="hljs-literal">Some</span>(total::exec),
        _ =&gt; <span class="hljs-literal">None</span>,
    }
}

<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> init;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> add;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> list;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> update;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> delete;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> subcategory;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> total;
</code></pre>
<p>The <code>Exec</code> type alias defines a standard signature for all your command functions. Every command will receive the global context and the arguments parsed by clap, and every command will return a CliResult.</p>
<p>The <code>Exec</code> type alias defines a standard signature for all your command functions. Every command will receive the global context and the arguments parsed by <code>clap</code>. The <code>build_exec</code> function then uses pattern matching to return the specific execution logic associated with the user's input.</p>
<h3 id="heading-manage-paths-with-global-context">Manage Paths with Global Context</h3>
<p>Since your application is local-first, it needs to know exactly where to find the data directory on different operating systems. You will create a <code>GlobalContext</code> struct to centralize these paths so you don’t have to rebuild them manually in every command module.</p>
<p>Now create <code>src/utils/context.rs</code> for managing file paths:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::path::PathBuf;

<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">GlobalContext</span></span> {
    home_path: PathBuf,
    base_path: PathBuf,
    tracker_path: PathBuf,
}

<span class="hljs-keyword">impl</span> GlobalContext {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(home_dir: PathBuf) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">let</span> base_path = home_dir.join(<span class="hljs-string">".fintrack"</span>);
        <span class="hljs-keyword">let</span> tracker_path = base_path.join(<span class="hljs-string">"tracker.json"</span>);

        GlobalContext {
            home_path: home_dir,
            base_path,
            tracker_path,
        }
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tracker_path</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; &amp;PathBuf {
        &amp;<span class="hljs-keyword">self</span>.tracker_path
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">home_path</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; &amp;PathBuf {
        &amp;<span class="hljs-keyword">self</span>.home_path
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">base_path</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; &amp;PathBuf {
        &amp;<span class="hljs-keyword">self</span>.base_path
    }
}
</code></pre>
<p>The <code>join()</code> method is a cross-platform way to combine paths. It automatically uses the correct separator for your operating system, such as a backslash on Windows or a forward slash on Linux.</p>
<h3 id="heading-register-the-command-system">Register the Command System</h3>
<p>To tie these components together, update your utility and library files. In <code>src/utils.rs</code>, add the context module:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> file;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> context;
</code></pre>
<p>Finally, update <code>src/lib.rs</code> to expose the command structures and the new context type. You’ll also define a <code>CliResult</code> type alias to keep your function signatures consistent throughout the project:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> models;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> error;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> utils;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> commands;

<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> error::*;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> models::*;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::command_prelude;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::context::GlobalContext;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::parsers;
</code></pre>
<p>By defining the result type here, you ensure that every command follows the same error-handling and response rules you established in previous steps.</p>
<h2 id="heading-step-6-create-response-types">Step 6: Create Response Types</h2>
<p>Commands in your tracker do more than just execute logic. They return data that must be formatted and displayed to the user.</p>
<p>In a command-line tool, your "user interface" is the text printed to the terminal, so you need a structured way to handle various results. You’ll create a <code>ResponseContent</code> enum to categorize these different outputs, such as single records, transaction lists, or financial totals. This ensures that your application communicates both successful results and informative error messages clearly.</p>
<h3 id="heading-define-the-response-structures">Define the Response Structures</h3>
<p>Open your <code>src/models.rs</code> file and add these structures to manage how the application packages its data:</p>
<p>Add to <code>src/models.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">ResponseContent</span></span> {
    Message(<span class="hljs-built_in">String</span>),
    Record {
        record: Record,
        tracker_data: TrackerData,
        is_update: <span class="hljs-built_in">bool</span>,
    },
    List {
        records: <span class="hljs-built_in">Vec</span>&lt;Record&gt;,
        tracker_data: TrackerData,
    },
    TrackerData(TrackerData),
    Total(Total),
    Categories(<span class="hljs-built_in">Vec</span>&lt;(<span class="hljs-built_in">usize</span>, <span class="hljs-built_in">String</span>)&gt;),
    Subcategories(<span class="hljs-built_in">Vec</span>&lt;(<span class="hljs-built_in">usize</span>, <span class="hljs-built_in">String</span>)&gt;),
}

<span class="hljs-meta">#[derive(Debug, Clone)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Total</span></span> {
    <span class="hljs-keyword">pub</span> currency: Currency,
    <span class="hljs-keyword">pub</span> opening_balance: <span class="hljs-built_in">f64</span>,
    <span class="hljs-keyword">pub</span> income_total: <span class="hljs-built_in">f64</span>,
    <span class="hljs-keyword">pub</span> expenses_total: <span class="hljs-built_in">f64</span>,
}

<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">CliResponse</span></span> {
    content: <span class="hljs-built_in">Option</span>&lt;ResponseContent&gt;,
}

<span class="hljs-keyword">impl</span> CliResponse {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(content: ResponseContent) -&gt; <span class="hljs-keyword">Self</span> {
        CliResponse {
            content: <span class="hljs-literal">Some</span>(content),
        }
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">success</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        CliResponse { content: <span class="hljs-literal">None</span> }
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">content</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;ResponseContent&gt; {
        <span class="hljs-keyword">self</span>.content.as_ref()
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">write_to</span></span>(&amp;<span class="hljs-keyword">self</span>, writer: &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">impl</span> std::io::Write) -&gt; std::io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
        crate::output::write_response(<span class="hljs-keyword">self</span>, writer)
    }
}

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">CliResult</span></span> = <span class="hljs-built_in">Result</span>&lt;CliResponse, CliError&gt;;
</code></pre>
<p>The <code>CliResponse</code> struct acts as a container for your output. By using an <code>Option&lt;ResponseContent&gt;</code>, you can represent a simple success message when the content is <code>None</code>, or provide more complex data like a <code>Total</code> struct when needed. This approach keeps your command logic consistent because every operation will return the same response type.</p>
<h3 id="heading-implement-the-output-module">Implement the Output Module</h3>
<p>Next, you need a central place to turn these Rust types into formatted text for the terminal. Create a new file named <code>src/output.rs</code>. This module will handle the printing logic for both successful responses and the errors you defined earlier.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> crate::{CliError, CliResponse, ResponseContent};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">write_response</span></span>(res: &amp;CliResponse, writer: &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">impl</span> std::io::Write) -&gt; std::io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(content) = res.content() <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"✓ Success"</span>)?;
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(());
    };

    <span class="hljs-keyword">match</span> content {
        ResponseContent::Message(msg) =&gt; {
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"✓ {}"</span>, msg)?;
        }
        ResponseContent::Record { record, .. } =&gt; {
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"✓ Record created:"</span>)?;
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"  ID: {}"</span>, record.id)?;
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"  Amount: {}"</span>, record.amount)?;
            <span class="hljs-comment">// More formatting later</span>
        }
        ResponseContent::List { records, .. } =&gt; {
            <span class="hljs-keyword">for</span> record <span class="hljs-keyword">in</span> records {
                <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"{:?}"</span>, record)?;
            }
        }
        ResponseContent::Total(total) =&gt; {
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Opening Balance: {} {}"</span>, total.opening_balance, total.currency)?;
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Total Income: {} {}"</span>, total.income_total, total.currency)?;
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Total Expenses: {} {}"</span>, total.expenses_total, total.currency)?;
            <span class="hljs-keyword">let</span> net_balance = total.opening_balance + total.income_total - total.expenses_total;
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Net Balance: {} {}"</span>, net_balance, total.currency)?;
        }
        _ =&gt; {}
    }
    <span class="hljs-literal">Ok</span>(())
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">write_error</span></span>(err: &amp;CliError, writer: &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">impl</span> std::io::Write) -&gt; std::io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">match</span> err {
        CliError::FileNotFound(msg) =&gt; <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: File not found: {}"</span>, msg),
        CliError::InvalidJson(msg) =&gt; <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: Invalid JSON: {}"</span>, msg),
        CliError::ValidationError(kind) =&gt; {
            <span class="hljs-keyword">match</span> kind {
                crate::ValidationErrorKind::AmountTooSmall { amount } =&gt; {
                    <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: Amount must be greater than 0, got {}"</span>, amount)
                }
                crate::ValidationErrorKind::SubcategoryNotFound { name } =&gt; {
                    <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: Subcategory '{}' not found"</span>, name)
                }
                crate::ValidationErrorKind::RecordNotFound { id } =&gt; {
                    <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: Record with ID {} not found"</span>, id)
                }
                _ =&gt; <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: Validation failed"</span>),
            }
        }
        CliError::FileAlreadyExists =&gt; {
            <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: Tracker already initialized. Use 'fintrack clear' to start fresh."</span>)
        }
        _ =&gt; <span class="hljs-built_in">writeln!</span>(writer, <span class="hljs-string">"Error: {}"</span>, err),
    }
}
</code></pre>
<p>By centralizing the output logic in this module, you fulfill the goal of reporting the exact data that caused a failure alongside the error message itself. If a user enters an invalid amount, the error output clearly identifies the problematic value.</p>
<h3 id="heading-update-the-library-registration">Update the Library Registration</h3>
<p>To finalize this step, register the output module and export the new response types in your <code>src/lib.rs</code> file:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> commands;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> error;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> models;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> output;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> utils;

<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> error::*;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> models::*;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::command_prelude;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::context::GlobalContext;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::parsers;
</code></pre>
<h2 id="heading-step-7-create-argument-parsing-helpers">Step 7: Create Argument Parsing Helpers</h2>
<p>Extracting specific values like transaction amounts, dates, or categories from raw command-line input can quickly lead to repetitive code. While <code>clap</code> provides the basic parsing, you need a streamlined way to convert those inputs into the specific types used by your tracker. By creating a custom trait to extend <code>clap</code>, you handle type conversion and error reporting in a single, consistent place.</p>
<p>Create a new file named <code>src/utils/cli.rs</code> and add the following implementation:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> chrono::NaiveDate;
<span class="hljs-keyword">use</span> clap::ArgMatches;
<span class="hljs-keyword">use</span> crate::{Category, CliError, Currency};

<span class="hljs-keyword">const</span> DEFAULT_F64: <span class="hljs-built_in">f64</span> = <span class="hljs-number">0.0</span>;
<span class="hljs-keyword">const</span> DEFAULT_USIZE: <span class="hljs-built_in">usize</span> = <span class="hljs-number">0</span>;
<span class="hljs-keyword">const</span> DEFAULT_SUBCATEGORY: &amp;<span class="hljs-built_in">str</span> = <span class="hljs-string">"miscellaneous"</span>;

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">ArgMatchesExt</span></span> {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_category</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;Category, CliError&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_usize</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">usize</span>, CliError&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_category_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;Category&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_f64_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">f64</span>&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_usize_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">usize</span>&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_string_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">String</span>&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_subcategory_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">String</span>&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_date_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;NaiveDate&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_currency_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;Currency&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_f64_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">f64</span>;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_usize_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">usize</span>;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_string_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">String</span>;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_subcategory_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">String</span>;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_currency_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; &amp;Currency;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_vec</span></span>&lt;T: <span class="hljs-built_in">Clone</span> + <span class="hljs-built_in">Send</span> + <span class="hljs-built_in">Sync</span> + <span class="hljs-symbol">'static</span>&gt;(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Vec</span>&lt;T&gt;;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">contains_id</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">bool</span>;
}

<span class="hljs-keyword">impl</span> ArgMatchesExt <span class="hljs-keyword">for</span> ArgMatches {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_category</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;Category, CliError&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;Category&gt;(id).ok_or_else(|| {
            CliError::ValidationError(crate::ValidationErrorKind::InvalidCategoryName {
                name: id.to_string(),
                reason: <span class="hljs-string">"Category not provided"</span>.to_string(),
            })
        })
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_usize</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">usize</span>, CliError&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">usize</span>&gt;(id).copied().ok_or_else(|| {
            CliError::Other(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"Required argument '{}' not provided"</span>, id))
        })
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_category_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;Category&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;Category&gt;(id)
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_f64_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">f64</span>&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">f64</span>&gt;(id).copied()
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_usize_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">usize</span>&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">usize</span>&gt;(id).copied()
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_string_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">String</span>&gt;(id).cloned()
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_subcategory_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">String</span>&gt;(id).cloned()
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_date_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;NaiveDate&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;NaiveDate&gt;(id).copied()
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_currency_opt</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;Currency&gt; {
        <span class="hljs-keyword">self</span>.get_one::&lt;Currency&gt;(id)
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_f64_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">f64</span> {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">f64</span>&gt;(id).copied().unwrap_or(DEFAULT_F64)
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_usize_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">usize</span> {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">usize</span>&gt;(id).copied().unwrap_or(DEFAULT_USIZE)
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_string_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">String</span> {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">String</span>&gt;(id).cloned().unwrap_or_default()
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_subcategory_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">String</span> {
        <span class="hljs-keyword">self</span>.get_one::&lt;<span class="hljs-built_in">String</span>&gt;(id)
            .cloned()
            .unwrap_or_else(|| DEFAULT_SUBCATEGORY.to_string())
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_currency_or_default</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; &amp;Currency {
        <span class="hljs-keyword">self</span>.get_one::&lt;Currency&gt;(id).unwrap_or(&amp;Currency::NGN)
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_vec</span></span>&lt;T: <span class="hljs-built_in">Clone</span> + <span class="hljs-built_in">Send</span> + <span class="hljs-built_in">Sync</span> + <span class="hljs-symbol">'static</span>&gt;(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Vec</span>&lt;T&gt; {
        <span class="hljs-keyword">self</span>.get_many::&lt;T&gt;(id)
            .map(|iter| iter.cloned().collect())
            .unwrap_or_default()
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">contains_id</span></span>(&amp;<span class="hljs-keyword">self</span>, id: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">bool</span> {
        ArgMatches::contains_id(<span class="hljs-keyword">self</span>, id)
    }
}
</code></pre>
<p>These helper methods allow you to decide exactly how to handle missing data. Methods like <code>ok_or_else</code> convert an empty input into a specific <code>CliError</code> that informs the user exactly which argument is missing. In contrast, <code>unwrap_or_else</code> allows the application to provide sensible fallbacks, such as defaulting to the "miscellaneous" subcategory if the user does not specify one.</p>
<h3 id="heading-implement-custom-data-parsers">Implement Custom Data Parsers</h3>
<p>Standard command-line arguments are received as strings. To turn them into useful data types like dates or categories, you need specific parsing logic. Create a new file <code>src/utils/parsers.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> chrono::NaiveDate;
<span class="hljs-keyword">use</span> crate::Category;

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_date</span></span>(s: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;NaiveDate, <span class="hljs-built_in">String</span>&gt; {
    NaiveDate::parse_from_str(s, <span class="hljs-string">"%d-%m-%Y"</span>)
        .map_err(|_| <span class="hljs-built_in">format!</span>(<span class="hljs-string">"'{}' is not in the format DD-MM-YYYY"</span>, s))
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_category</span></span>(s: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;Category, <span class="hljs-built_in">String</span>&gt; {
    s.parse::&lt;Category&gt;().map_err(|_| {
        <span class="hljs-built_in">format!</span>(<span class="hljs-string">"'{}' is not a valid category. Use 'income' or 'expenses'"</span>, s)
    })
}
</code></pre>
<p>We'll use these parsers to ensure that any input that doesn’t match your expected format is caught immediately with a clear error message before it ever reaches your core logic.</p>
<p>To finalize this setup, update <code>src/utils.rs</code> to include the new helper files:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> cli;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> command_prelude;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> context;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> file;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> parsers;
</code></pre>
<p>This infrastructure ensures that when you begin implementing the actual financial commands, you can focus on the business logic instead of fighting with string conversions and repeating argument validation.</p>
<p>Next we'll begin implementing the business logic for the commands, starting with the <code>init</code> command.</p>
<h2 id="heading-step-8-implement-the-init-command">Step 8: Implement the Init Command</h2>
<p>The init command will set up the workspace for the financial tracker. It will handle the creation of the hidden directory structure in your home folder and generate the initial JSON file with default settings like the currency and starting balance.</p>
<p>Create the <code>src/commands/init.rs</code> file and add this code:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{Arg, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::command_prelude::ArgMatchesExt;
<span class="hljs-keyword">use</span> crate::utils::file::{FilePath, write_json_to_file};
<span class="hljs-keyword">use</span> crate::{CliResponse, CliResult, Currency, GlobalContext, default_tracker_json};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"init"</span>)
        .about(<span class="hljs-string">"Initialize a new financial tracker"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"currency"</span>)
                .short(<span class="hljs-string">'c'</span>)
                .value_parser(clap::value_parser!(Currency))
                .default_value(<span class="hljs-string">"ngn"</span>),
        )
        .arg(
            Arg::new(<span class="hljs-string">"opening"</span>)
                .short(<span class="hljs-string">'o'</span>)
                .value_parser(clap::value_parser!(<span class="hljs-built_in">f64</span>)),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> currency = args.get_currency_or_default(<span class="hljs-string">"currency"</span>);
    <span class="hljs-keyword">let</span> opening_balance = args.get_f64_or_default(<span class="hljs-string">"opening"</span>);

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> file = gctx.tracker_path().create_file_if_not_exists()?;

    <span class="hljs-keyword">let</span> default_json = default_tracker_json(currency, opening_balance);
    write_json_to_file(&amp;default_json, &amp;<span class="hljs-keyword">mut</span> file)?;

    <span class="hljs-literal">Ok</span>(CliResponse::success())
}
</code></pre>
<p>The <code>cli</code> function defines the command's interface. <code>Command::new("init")</code> sets the name of the subcommand the user types. Within the <code>.arg()</code> blocks, <code>.short('c')</code> and <code>.long("currency")</code> allow for two different ways to provide the same data. A user can choose the concise short form or the more descriptive long form:</p>
<pre><code class="lang-bash">fintrack init -c usd -o 5000
</code></pre>
<p>OR</p>
<pre><code class="lang-bash">fintrack init --currency usd --opening 5000
</code></pre>
<p>Both commands map to the same internal <code>"currency"</code> and <code>"opening"</code> arguments.</p>
<p>The <code>exec</code> function performs the actual initialization of the tracker. It uses the helpers built in previous steps to keep the logic concise. Specifically, it uses <code>get_currency_or_default</code> and <code>get_f64_or_default</code> from the <code>ArgMatchesExt</code> trait you created in <code>src/utils/cli.rs</code>.</p>
<p>When attempting to create the tracker file, it calls <code>create_file_if_not_exists</code>. This method belongs to the <code>FilePath</code> trait you implemented in <code>src/utils/file.rs</code>. Because that method was built using <code>create_new(true)</code>, it acts as a guard that fails if a tracker already exists with an error <code>std::io::ErrorKind::AlreadyExists</code>. This failure is caught and converted into a <code>CliError::FileAlreadyExists</code> message, which was defined in your error handling logic in <code>src/error.rs</code>.</p>
<p>The <code>default_tracker_json</code> function builds the initial state for the application. It packages the base currency, opening balance, and default "miscellaneous" subcategory into a JSON structure. Finally, the <code>write_json_to_file</code> helper from <code>src/utils/file.rs</code> writes this data to the disk.</p>
<h2 id="heading-step-9-implement-the-add-command">Step 9: Implement the Add Command</h2>
<p>The <code>add</code> command will add a new record. To do this, you’ll implement code that will read the existing data from the JSON file, validate the new input, and save the updated record back to the JSON file.</p>
<p>Create <code>src/commands/add.rs</code> and insert this code:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> chrono::Local;
<span class="hljs-keyword">use</span> clap::{Arg, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::command_prelude::ArgMatchesExt;
<span class="hljs-keyword">use</span> crate::utils::file::{FilePath, write_json_to_file};
<span class="hljs-keyword">use</span> crate::utils::parsers::{parse_category, parse_date};
<span class="hljs-keyword">use</span> crate::{
    CliError, CliResponse, CliResult, GlobalContext, Record, ResponseContent, TrackerData,
};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"add"</span>)
        .about(<span class="hljs-string">"Record a new income or expense transaction"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"category"</span>)
                .index(<span class="hljs-number">1</span>)
                .required(<span class="hljs-literal">true</span>)
                .value_parser(parse_category),
        )
        .arg(
            Arg::new(<span class="hljs-string">"amount"</span>)
                .index(<span class="hljs-number">2</span>)
                .required(<span class="hljs-literal">true</span>)
                .value_parser(clap::value_parser!(<span class="hljs-built_in">f64</span>)),
        )
        .arg(
            Arg::new(<span class="hljs-string">"subcategory"</span>)
                .short(<span class="hljs-string">'s'</span>)
                .long(<span class="hljs-string">"subcategory"</span>)
                .default_value(<span class="hljs-string">"miscellaneous"</span>),
        )
        .arg(
            Arg::new(<span class="hljs-string">"description"</span>)
                .short(<span class="hljs-string">'d'</span>)
                .long(<span class="hljs-string">"description"</span>),
        )
        .arg(
            Arg::new(<span class="hljs-string">"date"</span>)
                .short(<span class="hljs-string">'D'</span>)
                .long(<span class="hljs-string">"date"</span>)
                .value_parser(parse_date),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> file = gctx.tracker_path().open_read_write()?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">let</span> category = args.get_category(<span class="hljs-string">"category"</span>)?;
    <span class="hljs-keyword">let</span> amount = args.get_f64_or_default(<span class="hljs-string">"amount"</span>);

    <span class="hljs-keyword">if</span> amount &lt;= <span class="hljs-number">0.0</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::ValidationError(
            crate::ValidationErrorKind::AmountTooSmall { amount },
        ));
    }

    <span class="hljs-keyword">let</span> subcategory_name = args.get_subcategory_or_default(<span class="hljs-string">"subcategory"</span>);
    <span class="hljs-keyword">let</span> description = args.get_string_or_default(<span class="hljs-string">"description"</span>);

    <span class="hljs-keyword">let</span> category_str = category.to_string();
    <span class="hljs-keyword">let</span> category_id = tracker_data.category_id(&amp;category_str);

    <span class="hljs-keyword">let</span> subcategory_id = tracker_data
        .subcategory_id(&amp;subcategory_name)
        .ok_or_else(|| {
            CliError::ValidationError(crate::ValidationErrorKind::SubcategoryNotFound {
                name: subcategory_name,
            })
        })?;

    <span class="hljs-keyword">let</span> date = args
        .get_date_opt(<span class="hljs-string">"date"</span>)
        .map(|d| d.format(<span class="hljs-string">"%d-%m-%Y"</span>).to_string())
        .unwrap_or_else(|| Local::now().format(<span class="hljs-string">"%d-%m-%Y"</span>).to_string());

    <span class="hljs-keyword">let</span> record_id = tracker_data.next_record_id;
    <span class="hljs-keyword">let</span> record = Record {
        id: record_id,
        category: category_id,
        amount,
        subcategory: subcategory_id,
        description,
        date,
    };

    tracker_data.next_record_id += <span class="hljs-number">1</span>;
    tracker_data.last_modified = chrono::Utc::now().to_rfc3339();
    tracker_data.push_record(record.clone());

    <span class="hljs-keyword">let</span> tracker_json = serde_json::json!(tracker_data);
    write_json_to_file(&amp;tracker_json, &amp;<span class="hljs-keyword">mut</span> file)?;

    <span class="hljs-literal">Ok</span>(CliResponse::new(ResponseContent::Record {
        record,
        tracker_data,
        is_update: <span class="hljs-literal">false</span>,
    }))
}
</code></pre>
<p>The <code>cli</code> function here defines positional arguments using <code>.index(1)</code> and <code>.index(2)</code>. This means users can provide the category and amount without specific flags. An example usage looks like this:</p>
<pre><code class="lang-bash">fintrack add income 1500 -s salary -d <span class="hljs-string">"Monthly pay"</span>
</code></pre>
<p>In this command, <code>"income"</code> maps to the <code>"category"</code> and 1500 maps to the <code>"amount"</code>. The parser logic for these inputs makes use of the <code>parse_category</code> and <code>parse_date</code> functions created in <code>src/utils/parsers.rs</code>.</p>
<p>The <code>exec</code> function here opens the data file with <code>open_read_write</code> from the <code>FilePath</code> trait (<code>src/utils/file.rs</code>) and extracts user input using the <code>ArgMatchesExt</code> trait (<code>src/utils/cli.rs</code>).</p>
<p>The date logic handles optional input through a chain of methods. <code>get_date_opt</code> returns an <code>Option</code>, such that when a date exists, <code>.map</code> transforms it into the required string format. When a date doesn’t exist, <code>.unwrap_or_else</code> provides the current system date as a default.</p>
<p>Once the <code>Record</code> struct is populated, the code updates the <code>TrackerData</code> state and saves the result using the <code>write_json_to_file</code> helper. The final <code>CliResponse</code> contains the record details for the output module in <code>src/output.rs</code> to display.</p>
<h2 id="heading-step-10-implement-the-list-command">Step 10: Implement the List Command</h2>
<p>The <code>list</code> command will provide a way to view and filter records. This logic involves loading the data file, applying criteria like date ranges or categories, and sorting the results chronologically.</p>
<p>Create <code>src/commands/list.rs</code> and add the following code:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> chrono::NaiveDate;
<span class="hljs-keyword">use</span> clap::{Arg, ArgGroup, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::command_prelude::ArgMatchesExt;
<span class="hljs-keyword">use</span> crate::utils::file::FilePath;
<span class="hljs-keyword">use</span> crate::utils::parsers::{parse_category, parse_date};
<span class="hljs-keyword">use</span> crate::{CliResponse, CliResult, GlobalContext, Record, ResponseContent, TrackerData};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"list"</span>)
        .about(<span class="hljs-string">"View and filter your transaction records"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"first"</span>)
                .short(<span class="hljs-string">'f'</span>)
                .long(<span class="hljs-string">"first"</span>)
                .value_parser(clap::value_parser!(<span class="hljs-built_in">usize</span>)),
        )
        .arg(
            Arg::new(<span class="hljs-string">"last"</span>)
                .short(<span class="hljs-string">'l'</span>)
                .long(<span class="hljs-string">"last"</span>)
                .value_parser(clap::value_parser!(<span class="hljs-built_in">usize</span>)),
        )
        .group(
            ArgGroup::new(<span class="hljs-string">"first_or_last"</span>)
                .args([<span class="hljs-string">"first"</span>, <span class="hljs-string">"last"</span>])
                .multiple(<span class="hljs-literal">false</span>),
        )
        .arg(
            Arg::new(<span class="hljs-string">"start"</span>)
                .short(<span class="hljs-string">'S'</span>)
                .long(<span class="hljs-string">"start"</span>)
                .value_parser(parse_date),
        )
        .arg(
            Arg::new(<span class="hljs-string">"end"</span>)
                .short(<span class="hljs-string">'E'</span>)
                .long(<span class="hljs-string">"end"</span>)
                .value_parser(parse_date),
        )
        .arg(
            Arg::new(<span class="hljs-string">"category"</span>)
                .short(<span class="hljs-string">'c'</span>)
                .long(<span class="hljs-string">"category"</span>)
                .value_parser(parse_category),
        )
        .arg(
            Arg::new(<span class="hljs-string">"subcategory"</span>)
                .short(<span class="hljs-string">'s'</span>)
                .long(<span class="hljs-string">"subcategory"</span>),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> file = gctx.tracker_path().open_read()?;
    <span class="hljs-keyword">let</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">let</span> start_date = args.get_date_opt(<span class="hljs-string">"start"</span>);
    <span class="hljs-keyword">let</span> end_date = args.get_date_opt(<span class="hljs-string">"end"</span>);

    <span class="hljs-keyword">let</span> category_filter = args
        .get_category_opt(<span class="hljs-string">"category"</span>)
        .map(|cat| tracker_data.category_id(&amp;cat.to_string()));

    <span class="hljs-keyword">let</span> subcategory_filter = args
        .get_subcategory_opt(<span class="hljs-string">"subcategory"</span>)
        .and_then(|name| tracker_data.subcategory_id(&amp;name));

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> filtered_data: <span class="hljs-built_in">Vec</span>&lt;Record&gt; = tracker_data
        .records
        .iter()
        .filter(|r| {
            <span class="hljs-keyword">let</span> matches_category = category_filter
                .map(|expected_id| r.category == expected_id)
                .unwrap_or(<span class="hljs-literal">true</span>);

            <span class="hljs-keyword">let</span> matches_subcategory = subcategory_filter
                .map(|expected_id| r.subcategory == expected_id)
                .unwrap_or(<span class="hljs-literal">true</span>);

            <span class="hljs-keyword">let</span> matches_date = NaiveDate::parse_from_str(&amp;r.date, <span class="hljs-string">"%d-%m-%Y"</span>)
                .map(|record_date| {
                    <span class="hljs-keyword">let</span> after_start = start_date.map_or(<span class="hljs-literal">true</span>, |start| record_date &gt;= start);
                    <span class="hljs-keyword">let</span> before_end = end_date.map_or(<span class="hljs-literal">true</span>, |end| record_date &lt;= end);
                    after_start &amp;&amp; before_end
                })
                .unwrap_or(<span class="hljs-literal">false</span>);

            matches_category &amp;&amp; matches_subcategory &amp;&amp; matches_date
        })
        .cloned()
        .collect();

    filtered_data.sort_by(|a, b| {
        <span class="hljs-keyword">let</span> date_a = NaiveDate::parse_from_str(&amp;a.date, <span class="hljs-string">"%d-%m-%Y"</span>).unwrap_or(NaiveDate::MIN);
        <span class="hljs-keyword">let</span> date_b = NaiveDate::parse_from_str(&amp;b.date, <span class="hljs-string">"%d-%m-%Y"</span>).unwrap_or(NaiveDate::MIN);
        date_a.cmp(&amp;date_b)
    });

    <span class="hljs-keyword">if</span> args.contains_id(<span class="hljs-string">"first"</span>) {
        <span class="hljs-keyword">let</span> first = args.get_usize_or_default(<span class="hljs-string">"first"</span>);
        <span class="hljs-keyword">if</span> first &gt; <span class="hljs-number">0</span> {
            filtered_data.truncate(first);
        }
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> args.contains_id(<span class="hljs-string">"last"</span>) {
        <span class="hljs-keyword">let</span> last = args.get_usize_or_default(<span class="hljs-string">"last"</span>);
        <span class="hljs-keyword">if</span> last &gt; <span class="hljs-number">0</span> &amp;&amp; filtered_data.len() &gt; last {
            <span class="hljs-keyword">let</span> start_idx = filtered_data.len() - last;
            filtered_data = filtered_data.into_iter().skip(start_idx).collect();
        }
    }

    <span class="hljs-literal">Ok</span>(CliResponse::new(ResponseContent::List {
        records: filtered_data,
        tracker_data,
    }))
}
</code></pre>
<p>The <code>cli</code> function utilizes an <code>ArgGroup</code> named <code>"first_or_last"</code>. This ensures the user cannot request both the first N and last N records at the same time. The command supports multiple filtering flags, which allows a user to run queries like:</p>
<pre><code class="lang-bash">fintrack list -c expenses -S 01-01-2024 -E 31-01-2024
</code></pre>
<p>The command above filters for "expenses" specifically within the month of January 2024.</p>
<p>The <code>exec</code> function uses <code>open_read</code> from the <code>FilePath</code> trait (<code>src/utils/file.rs</code>) to access the tracker file without write permissions. The filtering logic makes use of methods like <code>and_then</code> and <code>map_or</code> to handle optional criteria. For example, the date filter uses <code>map_or(true, ...)</code> to include a record if no specific start or end date was provided.</p>
<p>The record sorting uses <code>sort_by</code> to compare record dates. Since dates are stored as strings in the JSON file, they are parsed into <code>NaiveDate</code> objects temporarily for an accurate chronological comparison. Finally, the function uses <code>truncate</code> or <code>skip</code> to limit the results based on the <code>"first"</code> or <code>"last"</code> arguments before returning a <code>ResponseContent::List</code> for the output module in <code>src/output.rs</code> to process.</p>
<h2 id="heading-step-11-implement-the-update-command">Step 11: Implement the Update Command</h2>
<p>The <code>update</code> command will allow the user to modify specific fields in an existing record. It will accept similar arguments as the <code>add</code> command but unlike the <code>add</code> command, every argument except the ID will be optional, enabling the user to change only what is necessary.</p>
<p>Create <code>src/commands/update.rs</code> and add the following code:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{Arg, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::command_prelude::ArgMatchesExt;
<span class="hljs-keyword">use</span> crate::utils::file::{FilePath, write_json_to_file};
<span class="hljs-keyword">use</span> crate::utils::parsers::{parse_category, parse_date};
<span class="hljs-keyword">use</span> crate::{CliError, CliResponse, CliResult, GlobalContext, ResponseContent, TrackerData};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"update"</span>)
        .about(<span class="hljs-string">"Modify an existing transaction record"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"record_id"</span>)
                .index(<span class="hljs-number">1</span>)
                .required(<span class="hljs-literal">true</span>)
                .value_parser(clap::value_parser!(<span class="hljs-built_in">usize</span>)),
        )
        .arg(
            Arg::new(<span class="hljs-string">"category"</span>)
                .short(<span class="hljs-string">'c'</span>)
                .long(<span class="hljs-string">"category"</span>)
                .value_parser(parse_category),
        )
        .arg(
            Arg::new(<span class="hljs-string">"amount"</span>)
                .short(<span class="hljs-string">'a'</span>)
                .long(<span class="hljs-string">"amount"</span>)
                .value_parser(clap::value_parser!(<span class="hljs-built_in">f64</span>)),
        )
        .arg(
            Arg::new(<span class="hljs-string">"subcategory"</span>)
                .short(<span class="hljs-string">'s'</span>)
                .long(<span class="hljs-string">"subcategory"</span>),
        )
        .arg(
            Arg::new(<span class="hljs-string">"description"</span>)
                .short(<span class="hljs-string">'d'</span>)
                .long(<span class="hljs-string">"description"</span>),
        )
        .arg(
            Arg::new(<span class="hljs-string">"date"</span>)
                .short(<span class="hljs-string">'D'</span>)
                .long(<span class="hljs-string">"date"</span>)
                .value_parser(parse_date),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> file = gctx.tracker_path().open_read_write()?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">let</span> record_id = args
        .get_usize(<span class="hljs-string">"record_id"</span>)
        .map_err(|_| CliError::ValidationError(crate::ValidationErrorKind::RecordNotFound { id: <span class="hljs-number">0</span> }))?;

    <span class="hljs-keyword">let</span> category_id = args.get_category_opt(<span class="hljs-string">"category"</span>).map(|category| {
        <span class="hljs-keyword">let</span> category_str = category.to_string();
        tracker_data.category_id(&amp;category_str)
    });

    <span class="hljs-keyword">let</span> subcategory_id = args
        .get_subcategory_opt(<span class="hljs-string">"subcategory"</span>)
        .map(|name| {
            tracker_data.subcategory_id(&amp;name).ok_or_else(|| {
                CliError::ValidationError(crate::ValidationErrorKind::SubcategoryNotFound { name })
            })
        })
        .transpose()?;

    <span class="hljs-keyword">let</span> record = tracker_data
        .records
        .iter_mut()
        .find(|r| r.id == record_id)
        .ok_or_else(|| {
            CliError::ValidationError(crate::ValidationErrorKind::RecordNotFound { id: record_id })
        })?;

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(cat_id) = category_id {
        record.category = cat_id;
    }

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(amount) = args.get_f64_opt(<span class="hljs-string">"amount"</span>) {
        <span class="hljs-keyword">if</span> amount &lt;= <span class="hljs-number">0.0</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::ValidationError(
                crate::ValidationErrorKind::AmountTooSmall { amount },
            ));
        }
        record.amount = amount;
    }

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(subcat_id) = subcategory_id {
        record.subcategory = subcat_id;
    }

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(description) = args.get_string_opt(<span class="hljs-string">"description"</span>) {
        record.description = description;
    }

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(date) = args.get_date_opt(<span class="hljs-string">"date"</span>) {
        record.date = date.format(<span class="hljs-string">"%d-%m-%Y"</span>).to_string();
    }

    tracker_data.last_modified = chrono::Utc::now().to_rfc3339();

    <span class="hljs-keyword">let</span> updated_record = record.clone();

    <span class="hljs-keyword">let</span> tracker_json = serde_json::json!(tracker_data);
    write_json_to_file(&amp;tracker_json, &amp;<span class="hljs-keyword">mut</span> file)?;

    <span class="hljs-literal">Ok</span>(CliResponse::new(ResponseContent::Record {
        record: updated_record,
        tracker_data,
        is_update: <span class="hljs-literal">true</span>,
    }))
}
</code></pre>
<p>The <code>cli</code> function requires a positional <code>"record_id"</code> so the program knows which record to target. Users can find this ID by running the <code>list</code> command. An <code>update</code> command looks like this:</p>
<pre><code class="lang-bash">fintrack update 5 -a 2000 -d <span class="hljs-string">"Updated price"</span>
</code></pre>
<p>The command above specifically updates the amount and description for record number 5, leaving all other fields unchanged.</p>
<p>The <code>exec</code> function uses <code>iter_mut()</code> and <code>find()</code> to locate the specific record in your data list. Because <code>iter_mut()</code> provides a mutable reference, any changes made to the record variable directly update the object inside <code>tracker_data.records</code>.</p>
<p>To handle the optional subcategory update, the code uses <code>transpose()</code>. This method is essential here because looking up a subcategory name is optional. But if a name is provided and it doesn't exist, the program should stop and return an error. <code>transpose()</code> flips the <code>Option&lt;Result&gt;</code> into a <code>Result&lt;Option&gt;</code>, allowing the <code>?</code> operator to handle the error while still giving you an <code>Option</code> to work with.</p>
<p>The final state is saved back to the file using the <code>write_json_to_file</code> helper from <code>src/utils/file.rs</code>. The <code>CliResponse</code> indicates that an update occurred by setting <code>is_update: true</code>, which the <code>output</code> module uses to format the success message appropriately.</p>
<h2 id="heading-step-12-implement-the-delete-command">Step 12: Implement the Delete Command</h2>
<p>The <code>delete</code> command will remove specific records from the tracker. This implementation will support multiple deletion strategies: targeting individual IDs, removing an entire category, or clearing a specific subcategory.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::collections::HashSet;

<span class="hljs-keyword">use</span> clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::{
    CliResponse, CliResult, GlobalContext, TrackerData,
    command_prelude::ArgMatchesExt,
    utils::file::{FilePath, write_json_to_file},
    utils::parsers::parse_category,
};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"delete"</span>)
        .about(<span class="hljs-string">"Delete transaction records"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"ids"</span>)
                .short(<span class="hljs-string">'i'</span>)
                .long(<span class="hljs-string">"ids"</span>)
                .value_parser(clap::value_parser!(<span class="hljs-built_in">usize</span>))
                .action(ArgAction::Append)
                .value_delimiter(<span class="hljs-string">','</span>),
        )
        .arg(
            Arg::new(<span class="hljs-string">"by-cat"</span>)
                .short(<span class="hljs-string">'c'</span>)
                .long(<span class="hljs-string">"by-cat"</span>)
                .value_parser(parse_category),
        )
        .arg(
            Arg::new(<span class="hljs-string">"by-subcat"</span>)
                .short(<span class="hljs-string">'s'</span>)
                .long(<span class="hljs-string">"by-subcat"</span>),
        )
        .group(
            ArgGroup::new(<span class="hljs-string">"delete_by"</span>)
                .args([<span class="hljs-string">"ids"</span>, <span class="hljs-string">"by-cat"</span>, <span class="hljs-string">"by-subcat"</span>])
                .multiple(<span class="hljs-literal">false</span>)
                .required(<span class="hljs-literal">true</span>),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> file = gctx.tracker_path().open_read_write()?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">if</span> args.contains_id(<span class="hljs-string">"ids"</span>) {
        <span class="hljs-keyword">let</span> ids: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">usize</span>&gt; = args.get_vec::&lt;<span class="hljs-built_in">usize</span>&gt;(<span class="hljs-string">"ids"</span>);
        <span class="hljs-keyword">let</span> ids_set: HashSet&lt;<span class="hljs-built_in">usize</span>&gt; = ids.into_iter().collect();

        tracker_data.records.retain(|r| !ids_set.contains(&amp;r.id));
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> args.contains_id(<span class="hljs-string">"by-cat"</span>) {
        <span class="hljs-keyword">let</span> category = args.get_category(<span class="hljs-string">"by-cat"</span>)?;
        <span class="hljs-keyword">let</span> category_str = category.to_string();
        <span class="hljs-keyword">let</span> category_id = tracker_data.category_id(&amp;category_str);

        tracker_data.records.retain(|r| r.category != category_id);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> args.contains_id(<span class="hljs-string">"by-subcat"</span>) {
        <span class="hljs-keyword">let</span> subcategory_name = args
            .get_subcategory_opt(<span class="hljs-string">"by-subcat"</span>)
            .ok_or_else(|| crate::CliError::Other(<span class="hljs-string">"Subcategory not provided"</span>.to_string()))?;

        <span class="hljs-keyword">let</span> subcategory_id = tracker_data
            .subcategory_id(subcategory_name.as_str())
            .ok_or_else(|| {
                crate::CliError::ValidationError(crate::ValidationErrorKind::SubcategoryNotFound {
                    name: subcategory_name.clone(),
                })
            })?;

        tracker_data
            .records
            .retain(|r| r.subcategory != subcategory_id);
    }

    tracker_data.last_modified = chrono::Utc::now().to_rfc3339();

    <span class="hljs-keyword">let</span> tracker_json = serde_json::json!(tracker_data);
    write_json_to_file(&amp;tracker_json, &amp;<span class="hljs-keyword">mut</span> file)?;

    <span class="hljs-literal">Ok</span>(CliResponse::success())
}
</code></pre>
<p>The <code>cli</code> function makes use of an <code>ArgGroup</code> to enforce that only one deletion method is used at a time (<code>"ids</code>, <code>"by-cat"</code>, or <code>"by-subcat"</code>). The <code>"ids"</code> argument uses <code>value_delimiter(',')</code>, allowing a user to pass multiple IDs separated by a comma (','). For example:</p>
<pre><code class="lang-bash">fintrack delete --ids 1,4,7
</code></pre>
<p>Also, a user can clear all records of a particular category or subcategory using the <code>"by-cat"</code> or <code>"by-subcat"</code> flag. For example:</p>
<pre><code class="lang-bash">fintrack delete --by-cat expenses
</code></pre>
<p>The <code>exec</code> function determines which records to target based on three possible inputs. If <code>--ids</code> is used, it collects the provided values directly into a HashSet. If <code>--by-cat</code> or <code>--by-subcat</code> is used, the code iterates through existing records and gathers the IDs of every record that matches that specific category or subcategory and stores it in a HashSet. Regardless of the flag used, the logic converges on a HashSet containing all IDs scheduled for removal.</p>
<p>Using a HashSet makes the final cleanup highly efficient because it allows the program to check if an ID exists in the "delete list" almost instantly. The retain method then keeps only the records whose IDs are not in that set, effectively pruning the data in place.</p>
<p>After the removal, the code calculates the difference between the initial and final record counts. If no records were removed, it returns a <code>RecordNotFound</code> error. Otherwise, it updates the <code>last_modified</code> timestamp and saves the updated JSON using the <code>write_json_to_file</code> helper from <code>src/utils/file.rs</code>.</p>
<h2 id="heading-step-13-implement-subcategory-commands">Step 13: Implement Subcategory Commands</h2>
<p>The <code>subcategory</code> command will serve as a parent for several nested subcommands, allowing users to organize their records beyond the basic "income" and "expenses" categories. This structure will use a modular approach, where each management task will live in its own dedicated file.</p>
<p>Create the entry point file at <code>src/commands/subcategory.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::{CliResult, GlobalContext, commands::Exec, invalid_subcommand_error};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"subcategory"</span>)
        .about(<span class="hljs-string">"Manage your subcategories"</span>)
        .subcommand_required(<span class="hljs-literal">true</span>)
        .subcommands(build_cli())
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">match</span> args.subcommand() {
        <span class="hljs-literal">Some</span>((cmd, sub_args)) =&gt; {
            <span class="hljs-keyword">let</span> exec_fn = build_exec(cmd).ok_or_else(|| invalid_subcommand_error(cmd))?;

            exec_fn(gctx, sub_args)
        }
        <span class="hljs-literal">None</span> =&gt; <span class="hljs-literal">Err</span>(invalid_subcommand_error(<span class="hljs-string">""</span>)),
    }
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">build_cli</span></span>() -&gt; <span class="hljs-built_in">Vec</span>&lt;Command&gt; {
    <span class="hljs-built_in">vec!</span>[add::cli(), delete::cli(), list::cli(), rename::cli()]
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">build_exec</span></span>(cmd: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;Exec&gt; {
    <span class="hljs-keyword">match</span> cmd {
        <span class="hljs-string">"add"</span> =&gt; <span class="hljs-literal">Some</span>(add::exec),
        <span class="hljs-string">"delete"</span> =&gt; <span class="hljs-literal">Some</span>(delete::exec),
        <span class="hljs-string">"list"</span> =&gt; <span class="hljs-literal">Some</span>(list::exec),
        <span class="hljs-string">"rename"</span> =&gt; <span class="hljs-literal">Some</span>(rename::exec),
        <span class="hljs-string">"update"</span> =&gt; <span class="hljs-literal">Some</span>(rename::exec),
        _ =&gt; <span class="hljs-literal">None</span>,
    }
}

<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> list;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> add;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> delete;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> rename;
</code></pre>
<p>The <code>cli</code> function here sets <code>subcommand_required(true)</code>. This means the user must specify an action. The <code>exec</code> function uses a <code>match</code> statement to delegate the logic to the appropriate module.</p>
<h3 id="heading-list-subcategories">List Subcategories</h3>
<p>Create <code>src/commands/subcategory/list.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::{CliResponse, CliResult, GlobalContext, ResponseContent, TrackerData, utils::file::FilePath};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"list"</span>)
        .about(<span class="hljs-string">"View all available subcategories"</span>)
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, _args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> file = gctx.tracker_path().open_read()?;
    <span class="hljs-keyword">let</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> subcategories: <span class="hljs-built_in">Vec</span>&lt;(<span class="hljs-built_in">usize</span>, <span class="hljs-built_in">String</span>)&gt; = tracker_data
        .subcategories_by_id
        .iter()
        .map(|(&amp;id, name)| (id, name.clone()))
        .collect();

    subcategories.sort_by_key(|(id, _)| *id);

    <span class="hljs-literal">Ok</span>(CliResponse::new(ResponseContent::Subcategories(subcategories)))
}
</code></pre>
<p>The <code>exec</code> function first accesses the data file using the <code>open_read</code> helper method defined earlier in <code>src/utils/file.rs</code>. Once the file is open, it reads the JSON content into the <code>TrackerData</code> struct. The logic then pulls the specific list of IDs and names from the <code>subcategories_by_id</code> map found in <code>src/models.rs</code> and converts them into a simple list for the user to view.</p>
<h3 id="heading-add-subcategories">Add Subcategories</h3>
<p>Create <code>src/commands/subcategory/add.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{Arg, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::{
    CliError, CliResponse, CliResult, GlobalContext, TrackerData,
    utils::file::{FilePath, write_json_to_file},
    utils::parsers::parse_label,
};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"add"</span>)
        .about(<span class="hljs-string">"Create a new subcategory"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"name"</span>)
                .index(<span class="hljs-number">1</span>)
                .required(<span class="hljs-literal">true</span>)
                .value_parser(parse_label),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> file = gctx.tracker_path().open_read_write()?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">let</span> name = args
        .get_one::&lt;<span class="hljs-built_in">String</span>&gt;(<span class="hljs-string">"name"</span>)
        .ok_or_else(|| CliError::Other(<span class="hljs-string">"Subcategory name not provided"</span>.to_string()))?;

    <span class="hljs-keyword">let</span> name_lower = name.to_lowercase();
    <span class="hljs-keyword">let</span> name_title = {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> chars = name_lower.chars();
        <span class="hljs-keyword">match</span> chars.next() {
            <span class="hljs-literal">None</span> =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::Other(<span class="hljs-string">"Invalid name"</span>.to_string())),
            <span class="hljs-literal">Some</span>(first) =&gt; first.to_uppercase().collect::&lt;<span class="hljs-built_in">String</span>&gt;() + &amp;chars.as_str().to_lowercase(),
        }
    };

    <span class="hljs-keyword">if</span> name_lower == <span class="hljs-string">"miscellaneous"</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::ValidationError(
            crate::ValidationErrorKind::CannotDeleteMiscellaneous,
        ));
    }

    <span class="hljs-keyword">if</span> tracker_data.subcategories_by_name.contains_key(&amp;name_lower) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::ValidationError(
            crate::ValidationErrorKind::SubcategoryAlreadyExists {
                name: name_title.clone(),
            },
        ));
    }

    <span class="hljs-keyword">let</span> subcategory_id = tracker_data.next_subcategory_id <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;
    tracker_data.subcategories_by_id.insert(subcategory_id, name_title.clone());
    tracker_data.subcategories_by_name.insert(name_lower, subcategory_id);
    tracker_data.next_subcategory_id += <span class="hljs-number">1</span>;
    tracker_data.last_modified = chrono::Utc::now().to_rfc3339();

    <span class="hljs-keyword">let</span> tracker_json = serde_json::json!(tracker_data);
    write_json_to_file(&amp;tracker_json, &amp;<span class="hljs-keyword">mut</span> file)?;

    <span class="hljs-literal">Ok</span>(CliResponse::new(crate::ResponseContent::Message(<span class="hljs-built_in">format!</span>(
        <span class="hljs-string">"Subcategory '{}' added (ID: {})"</span>,
        name_title, subcategory_id
    ))))
}
</code></pre>
<p>The <code>exec</code> function here makes use of <code>open_read_write</code> to load the data for modification. It retrieves the user's input through the <code>get_string_opt</code> helper from the <code>ArgMatchesExt</code> trait.</p>
<p>To maintain consistency, the <code>normalize_name</code> function ensures all names follow a standard title case format. Before saving, the logic checks the <code>subcategories_by_name</code> map from <code>src/models.rs</code> to ensure the name is unique.</p>
<p>Once validated, it updates the <code>next_subcategory_id</code> and writes the changes back to disk using <code>write_json_to_file</code>.</p>
<h3 id="heading-delete-subcategories">Delete Subcategories</h3>
<p>Create <code>src/commands/subcategory/delete.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{Arg, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::{
    CliError, CliResponse, CliResult, GlobalContext, TrackerData,
    utils::file::{FilePath, write_json_to_file},
    utils::parsers::parse_label,
};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"delete"</span>)
        .about(<span class="hljs-string">"Delete a subcategory"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"name"</span>)
                .index(<span class="hljs-number">1</span>)
                .required(<span class="hljs-literal">true</span>)
                .value_parser(parse_label),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> file = gctx.tracker_path().open_read_write()?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">let</span> name = args
        .get_one::&lt;<span class="hljs-built_in">String</span>&gt;(<span class="hljs-string">"name"</span>)
        .ok_or_else(|| CliError::Other(<span class="hljs-string">"Subcategory name not provided"</span>.to_string()))?;

    <span class="hljs-keyword">let</span> name_lower = name.to_lowercase();

    <span class="hljs-keyword">if</span> name_lower == <span class="hljs-string">"miscellaneous"</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::ValidationError(
            crate::ValidationErrorKind::CannotDeleteMiscellaneous,
        ));
    }

    <span class="hljs-keyword">let</span> subcategory_id = tracker_data
        .subcategory_id(&amp;name_lower)
        .ok_or_else(|| {
            CliError::ValidationError(crate::ValidationErrorKind::SubcategoryNotFound {
                name: name.to_string(),
            })
        })?;

    <span class="hljs-keyword">let</span> record_count = tracker_data
        .records
        .iter()
        .filter(|r| r.subcategory == subcategory_id)
        .count();

    <span class="hljs-keyword">if</span> record_count &gt; <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::ValidationError(
            crate::ValidationErrorKind::SubcategoryHasRecords {
                name: name.to_string(),
                count: record_count,
            },
        ));
    }

    tracker_data.subcategories_by_id.remove(&amp;subcategory_id);
    tracker_data.subcategories_by_name.remove(&amp;name_lower);
    tracker_data.last_modified = chrono::Utc::now().to_rfc3339();

    <span class="hljs-keyword">let</span> tracker_json = serde_json::json!(tracker_data);
    write_json_to_file(&amp;tracker_json, &amp;<span class="hljs-keyword">mut</span> file)?;

    <span class="hljs-literal">Ok</span>(CliResponse::new(crate::ResponseContent::Message(<span class="hljs-built_in">format!</span>(
        <span class="hljs-string">"Subcategory '{}' deleted"</span>,
        name
    ))))
}
</code></pre>
<p>The <code>exec</code> function performs a safety check before removing any data. It first locates the ID of the target subcategory using the name provided by the user. Then, it iterates through the records vector in the tracker data to count if any records are currently linked to that ID. If the count is greater than zero, the operation stops and returns a <code>SubcategoryHasRecords</code> error, preventing you from accidentally creating "orphaned" records that point to a missing subcategory. If the check passes, the subcategory is removed from both HashMaps in <code>src/models.rs</code>.</p>
<h3 id="heading-rename-subcategories">Rename Subcategories</h3>
<p>Create <code>src/commands/subcategory/rename.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{Arg, ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::{
    CliError, CliResponse, CliResult, GlobalContext, TrackerData,
    utils::file::{FilePath, write_json_to_file},
    utils::parsers::parse_label,
};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"rename"</span>)
        .about(<span class="hljs-string">"Rename an existing subcategory"</span>)
        .arg(
            Arg::new(<span class="hljs-string">"old"</span>)
                .index(<span class="hljs-number">1</span>)
                .required(<span class="hljs-literal">true</span>)
                .value_parser(parse_label),
        )
        .arg(
            Arg::new(<span class="hljs-string">"new"</span>)
                .index(<span class="hljs-number">2</span>)
                .required(<span class="hljs-literal">true</span>)
                .value_parser(parse_label),
        )
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, args: &amp;ArgMatches) -&gt; CliResult {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> file = gctx.tracker_path().open_read_write()?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

    <span class="hljs-keyword">let</span> old_name = args
        .get_one::&lt;<span class="hljs-built_in">String</span>&gt;(<span class="hljs-string">"old"</span>)
        .ok_or_else(|| CliError::Other(<span class="hljs-string">"Old subcategory name not provided"</span>.to_string()))?;
    <span class="hljs-keyword">let</span> new_name = args
        .get_one::&lt;<span class="hljs-built_in">String</span>&gt;(<span class="hljs-string">"new"</span>)
        .ok_or_else(|| CliError::Other(<span class="hljs-string">"New subcategory name not provided"</span>.to_string()))?;

    <span class="hljs-keyword">let</span> old_name_lower = old_name.to_lowercase();
    <span class="hljs-keyword">let</span> new_name_lower = new_name.to_lowercase();
    <span class="hljs-keyword">let</span> new_name_title = {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> chars = new_name_lower.chars();
        <span class="hljs-keyword">match</span> chars.next() {
            <span class="hljs-literal">None</span> =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::Other(<span class="hljs-string">"Invalid new name"</span>.to_string())),
            <span class="hljs-literal">Some</span>(first) =&gt; first.to_uppercase().collect::&lt;<span class="hljs-built_in">String</span>&gt;() + &amp;chars.as_str().to_lowercase(),
        }
    };

    <span class="hljs-keyword">let</span> subcategory_id = tracker_data
        .subcategory_id(&amp;old_name_lower)
        .ok_or_else(|| {
            CliError::ValidationError(crate::ValidationErrorKind::SubcategoryNotFound {
                name: old_name.to_string(),
            })
        })?;

    <span class="hljs-keyword">if</span> tracker_data.subcategories_by_name.contains_key(&amp;new_name_lower) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(CliError::ValidationError(
            crate::ValidationErrorKind::SubcategoryAlreadyExists {
                name: new_name_title.clone(),
            },
        ));
    }

    tracker_data
        .subcategories_by_id
        .insert(subcategory_id, new_name_title.clone());
    tracker_data.subcategories_by_name.remove(&amp;old_name_lower);
    tracker_data
        .subcategories_by_name
        .insert(new_name_lower, subcategory_id);
    tracker_data.last_modified = chrono::Utc::now().to_rfc3339();

    <span class="hljs-keyword">let</span> tracker_json = serde_json::json!(tracker_data);
    write_json_to_file(&amp;tracker_json, &amp;<span class="hljs-keyword">mut</span> file)?;

    <span class="hljs-literal">Ok</span>(CliResponse::new(crate::ResponseContent::Message(<span class="hljs-built_in">format!</span>(
        <span class="hljs-string">"Subcategory renamed: '{}' → '{}'"</span>,
        old_name, new_name_title
    ))))
}
</code></pre>
<p>The <code>exec</code> function implements a "swap" logic to preserve record history. It first finds the numeric ID associated with the current name. Instead of changing any individual record, it simply removes the old name from the <code>subcategories_by_name</code> HashMap and inserts the new name with the same ID. This ensures that all existing records in <code>src/models.rs</code> immediately reflect the new name because they reference the subcategory by ID rather than by a string.</p>
<h2 id="heading-step-14-implement-the-total-command">Step 14: Implement the Total Command</h2>
<p>The <code>total</code> command will aggregate every transaction record in your JSON file to provide a clear view of your ledger's standing. It will sum up all income and expenses to show you exactly how your balance has changed since you initialized the tracker.</p>
<p>Create <code>src/commands/total.rs</code> and add the following code:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::{ArgMatches, Command};

<span class="hljs-keyword">use</span> crate::{
    CliError, CliResponse, CliResult, Currency, GlobalContext, Total, TrackerData,
    utils::file::FilePath,
};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cli</span></span>() -&gt; Command {
    Command::new(<span class="hljs-string">"total"</span>)
        .about(<span class="hljs-string">"Display financial summary with totals"</span>)
}


<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(gctx: &amp;<span class="hljs-keyword">mut</span> GlobalContext, _args: &amp;ArgMatches) -&gt; CliResult {
  <span class="hljs-keyword">let</span> file = gctx.tracker_path().open_read()?;
  <span class="hljs-keyword">let</span> tracker_data: TrackerData = serde_json::from_reader(&amp;file)?;

  <span class="hljs-keyword">let</span> opening_balance = tracker_data.opening_balance;

  <span class="hljs-keyword">let</span> currency = tracker_data
    .currency
    .parse::&lt;Currency&gt;()
    .map_err(|e| CliError::Other(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"Invalid currency in tracker data: {}"</span>, e)))?;

  <span class="hljs-keyword">let</span> (income_total, expenses_total) = tracker_data.totals();

  <span class="hljs-literal">Ok</span>(CliResponse::new(crate::ResponseContent::Total(Total {
    currency,
    opening_balance,
    income_total,
    expenses_total,
  })))
}
</code></pre>
<p>The <code>cli</code> function defines a straightforward interface without extra flags. It focuses entirely on processing the complete dataset.</p>
<p>The <code>exec</code> function first accesses the data file using the <code>open_read</code> helper. After parsing the JSON into the <code>TrackerData</code> struct, the logic calls the <code>totals()</code> method you implemented in <code>src/models.rs</code>. That method iterates through your records to return the raw sums of all income and expenses.</p>
<p>The <code>Total</code> struct contains the opening balance, income total, and expenses total. The net balance is calculated in the output module by adding <code>income_total</code> to the <code>opening_balance</code> and subtracting <code>expenses_total</code>. Finally you return a <code>CliResponse</code> which allows the output module to take these raw numbers and render them in the terminal.</p>
<h2 id="heading-step-15-wire-up-the-main-function">Step 15: Wire Up the Main Function</h2>
<p>This step brings every separate module back to the source. Until now, the models, error handling, and command logic existed as isolated parts. You will now create the <code>main.rs</code> file to establish the central entry point that connects these pieces, allowing the application to function as a unified binary.</p>
<p>First, update <code>src/lib.rs</code> to expose the internal modules:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> commands;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> error;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> models;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> output;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> utils;

<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> error::*;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> models::*;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::command_prelude;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::context::GlobalContext;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> utils::parsers;
</code></pre>
<p>Next, create <code>src/main.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::io;

<span class="hljs-keyword">use</span> clap::Command;
<span class="hljs-keyword">use</span> fintrack::{GlobalContext, commands};

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> exit_code = <span class="hljs-keyword">match</span> run() {
        <span class="hljs-literal">Ok</span>(_) =&gt; <span class="hljs-number">0</span>,
        <span class="hljs-literal">Err</span>(e) =&gt; {
            eprintln!(<span class="hljs-string">"Error: {}"</span>, e);
            <span class="hljs-number">1</span>
        }
    };
    std::process::exit(exit_code);
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">run</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;(), <span class="hljs-built_in">String</span>&gt; {
    <span class="hljs-keyword">let</span> home_dir = dirs::home_dir()
        .ok_or_else(|| <span class="hljs-string">"Failed to determine home directory"</span>.to_string())?;

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> gctx = GlobalContext::new(home_dir);

    <span class="hljs-keyword">let</span> matches = Command::new(<span class="hljs-string">"fintrack"</span>)
        .bin_name(<span class="hljs-string">"fintrack"</span>)
        .about(<span class="hljs-string">"A local-first CLI financial tracker for managing income and expenses"</span>)
        .version(<span class="hljs-built_in">env!</span>(<span class="hljs-string">"CARGO_PKG_VERSION"</span>))
        .subcommand_required(<span class="hljs-literal">true</span>)
        .subcommands(commands::cli())
        .get_matches();

    <span class="hljs-keyword">let</span> (cmd, args) = matches
        .subcommand()
        .expect(<span class="hljs-string">"subcommand required but not found"</span>);

    <span class="hljs-keyword">let</span> exec_fn = commands::build_exec(cmd)
        .ok_or_else(|| <span class="hljs-built_in">format!</span>(<span class="hljs-string">"Unknown command: {}"</span>, cmd))?;

    <span class="hljs-keyword">let</span> exec_result = exec_fn(&amp;<span class="hljs-keyword">mut</span> gctx, args);
    process_result(&amp;exec_result).expect(<span class="hljs-string">"An error occurred displaying response"</span>);

    <span class="hljs-literal">Ok</span>(())
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">process_result</span></span>(result: &amp;fintrack::CliResult) -&gt; io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">match</span> result {
        <span class="hljs-literal">Ok</span>(res) =&gt; res.write_to(&amp;<span class="hljs-keyword">mut</span> std::io::stdout()),
        <span class="hljs-literal">Err</span>(err) =&gt; err.write_to(&amp;<span class="hljs-keyword">mut</span> std::io::stderr()),
    }
}
</code></pre>
<p>The <code>main</code> function serves as the supervisor for the entire process. It triggers the <code>run</code> function and maps the final outcome to a standard system exit code. This informs the terminal whether the operation succeeded or encountered a failure.</p>
<p>The <code>run</code> function initiates a complete roundtrip through the architecture you built in previous steps. It starts by determining the user's home directory and passing it into <code>GlobalContext::new(home_dir)</code>. This instantiation creates the <code>gctx</code> object from Step 5, which determines the cross platform paths for the .fintrack folder and the tracker.json file.</p>
<p>When a user types a command like <code>fintrack add</code> in the terminal, the process begins by calling <code>commands::cli()</code>. This function, which you have defined in your central dispatcher <code>src/commands.rs</code> from Step 5, collects the list of all available subcommands (<code>init</code>, <code>add</code>, <code>list</code>, etc). It pulls the specific configuration for each command into a single clap instance so the terminal can understand the user intent.</p>
<p>If the user provides the correct input and arguments and <code>clap</code>'s validation is passed, it calls <code>commands::build_exec(cmd)</code> which uses the pattern matching logic also defined in Step 5. This function returns a pointer to the specific <code>exec</code> function for that command. For example, if the user typed <code>fintrack add ...</code>, it retrieves the exec function from <code>src/commands/add.rs</code>. The code then executes this function using a mutable reference to the <code>gctx</code> you just instantiated. This grants the command access to the file paths and data it needs.</p>
<p>The final execution phase happens in <code>process_result</code>. This function takes the <code>CliResult</code> returned by the command and calls the <code>write_to</code> method you defined earlier in the Step 6 output logic. Providing mutable references to <code>std::io::stdout()</code> for successes or <code>std::io::stderr()</code> for errors ensures the application prints the result or error message to the terminal.</p>
<h2 id="heading-test-your-application">Test Your Application</h2>
<p>You can build and test your application using cargo run. The double dash <code>--</code> tells Cargo to pass the following flags directly to your fintrack binary rather than interpreting them as Cargo arguments:</p>
<pre><code class="lang-bash">cargo build
cargo run -- init --currency USD --opening 1000
cargo run -- add income 500 --subcategory salary
cargo run -- add expenses 50 --subcategory groceries
cargo run -- list
cargo run -- total
</code></pre>
<h3 id="heading-install-the-binary">Install the Binary</h3>
<p>Running with <code>cargo run</code> is useful during development, but you can install the binary directly to your system to use the <code>fintrack</code> command globally. It will use <code>fintrack</code> because that's the value in the <code>name</code> field in your Cargo.toml file, which you set in the first step when you ran <code>cargo new fintrack</code>.</p>
<p>Run this to install <code>fintack</code> as a command:</p>
<pre><code class="lang-bash">cargo install --path .
</code></pre>
<p>When you run the installation command, Cargo compiles your code in release mode and places the executable in your Cargo bin folder (typically <code>~/.cargo/bin</code>). Once installed, the operating system recognizes <code>fintrack</code> as a standalone command. You can now call your application from any directory without prefixing it with <code>cargo</code>:</p>
<pre><code class="lang-bash">fintrack total
</code></pre>
<h2 id="heading-whats-next-and-advanced-features">What's Next and Advanced Features</h2>
<p>Congratulations! You've built a complete local-first CLI financial tracker. The application you've created includes:</p>
<ul>
<li><p>Data persistence in JSON format</p>
</li>
<li><p>Full CRUD operations for financial records</p>
</li>
<li><p>Subcategory management</p>
</li>
<li><p>Financial calculations</p>
</li>
<li><p>Comprehensive error handling</p>
</li>
<li><p>Type-safe command-line argument parsing</p>
</li>
</ul>
<h3 id="heading-advanced-features-to-explore">Advanced Features to Explore</h3>
<p>The modular architecture you built makes this tool easily extensible. To add new commands, you simply follow the pattern established in previous steps: create a new command module, define its logic, and register it within the <code>cli()</code> and <code>build_exec</code> functions in <code>src/commands.rs</code>.</p>
<p>Consider implementing these features to enhance the tool:</p>
<ul>
<li><p><strong>Export</strong>: Add an <code>export.rs</code> module to convert your JSON data into CSV format for analysis in spreadsheet applications.</p>
</li>
<li><p><strong>Describe</strong>: Create a command that uses terminal plotting libraries to generate visual charts of your spending patterns.</p>
</li>
<li><p><strong>Enhanced Output Formatting</strong>: Update <code>src/output.rs</code> with libraries like <code>colored</code> or <code>tabled</code> to add colors and professional borders to your terminal summaries.</p>
</li>
</ul>
<p>You can find the complete implementation of <code>fintrack</code> with all features, including advanced output formatting, export functionality, and more, in the <a target="_blank" href="https://github.com/steph-crown/fintrack">GitHub repository</a>. The repository also includes installation instructions for downloading the binary or installing via Cargo.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you've learned how to:</p>
<ul>
<li><p>Structure a Rust CLI application with proper error handling</p>
</li>
<li><p>Use traits to extend functionality</p>
</li>
<li><p>Work with JSON serialization</p>
</li>
<li><p>Parse and validate command-line arguments</p>
</li>
<li><p>Manage file I/O operations</p>
</li>
<li><p>Implement a complete data model with relationships</p>
</li>
</ul>
<p>The patterns you've learned here apply to many Rust applications. Traits, error handling with <code>Result</code>, and the ownership system are fundamental to writing idiomatic Rust code. These techniques ensure that as the application grows, the code remains maintainable and safe.</p>
<p>The modular nature of this tracker also means that the source code is now a template for any local-first tool. By swapping out the financial models for other data types, this same architecture can power a task manager, a personal wiki, or a time tracker.</p>
<p>Keep building, and happy tracking!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Voice AI Agent Using Open-Source Tools ]]>
                </title>
                <description>
                    <![CDATA[ Voice is the next frontier of conversational AI. It is the most natural modality for people to chat and interact with another intelligent being. In the past year, frontier AI labs such as OpenAI, xAI, Anthropic, Meta, and Google have all released rea... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-voice-ai-agent-using-open-source-tools/</link>
                <guid isPermaLink="false">68f7d890413573e1d65bb331</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ education ]]>
                    </category>
                
                    <category>
                        <![CDATA[ stem ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Voice ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agentic AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Open Source ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Michael Yuan ]]>
                </dc:creator>
                <pubDate>Tue, 21 Oct 2025 19:01:36 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761073279608/a73ce2cd-c95e-4f8b-b529-8774ce39a43f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Voice is the next frontier of conversational AI. It is the most natural modality for people to chat and interact with another intelligent being.</p>
<p>In the past year, frontier AI labs such as OpenAI, xAI, Anthropic, Meta, and Google have all released real-time voice services. Yet voice apps also have the highest requirements for latency, privacy, and customization. It’s difficult to have a one-size-fits-all voice AI solution.</p>
<p>In this article, we’ll explore how to use open-source technologies to create <a target="_blank" href="https://echokit.dev/">voice AI agents</a> that utilize your custom knowledge base, voice style, actions, fine-tuned AI models, and run on your own computer.</p>
<h2 id="heading-what-well-cover">What We’ll Cover:</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-it-looks-like">What it Looks Like</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-two-voice-ai-approaches">Two Voice AI Approaches</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-voice-ai-orchestrator">The Voice AI Orchestrator</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-configure-an-asr">Configure an ASR</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-run-and-configure-a-vad">Run and configure a VAD</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-configure-an-llm">Configure an LLM</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-configure-a-tts">Configure a TTS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-configure-mcp-and-actions">Configure MCP and actions</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-local-ai-with-llamaedge">Local AI With LlamaEdge</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You’ll need to have and know a few things to most effectively follow along with this tutorial:</p>
<ul>
<li><p>Access to a Linux-like system. Mac or Windows WSL suffice too.</p>
</li>
<li><p>Be comfortable with command line (CLI) tools.</p>
</li>
<li><p>Be able to run server applications on the Linux system.</p>
</li>
<li><p>Have/get free API keys from <a target="_blank" href="https://console.groq.com/keys">Groq</a> and <a target="_blank" href="https://elevenlabs.io/app/sign-in?redirect=%2Fapp%2Fdevelopers%2Fapi-keys">ElevenLabs</a>.</p>
</li>
<li><p>Optional: be able to compile and build Rust source code.</p>
</li>
<li><p>Optional: have/get an <a target="_blank" href="https://echokit.dev/echokit_diy.html">EchoKit device</a> or assemble your own.</p>
</li>
</ul>
<h2 id="heading-what-it-looks-like">What it Looks Like</h2>
<p>The key software component we will cover is the <a target="_blank" href="https://github.com/second-state/echokit_server">echokit_server</a> project. It is an open-source agent orchestrator for voice AI applications. That means it coordinates services such as LLMs, ASR, TTS, VAD, MCP, search, knowledge/vector databases, and others to generate intelligent voice responses from user prompts.</p>
<p>The EchoKit server provides a WebSocket interface that allows compatible clients to send and receive voice data to and from it. The <a target="_blank" href="https://github.com/second-state/echokit_box">echokit_box</a> project provides an ESP32-based firmware that can act as a client to collect audio from the user and play TTS-generated voice from the EchoKit server. You can see a couple of demos here. You can assemble your own EchoKit device or <a target="_blank" href="https://echokit.dev/echokit_diy.html">purchase one</a>.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/XroT7a0DLkw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/Zy-rLT4EgZQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>Of course, you can also use a pure software client that conforms to the <a target="_blank" href="https://github.com/second-state/echokit_server">echokit_server</a> WebSocket interface. The project publishes a <a target="_blank" href="https://echokit.dev/chat/">JavaScript web page</a> that you can run locally to connect to your own EchoKit server as a reference.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/Eyd9ToflccY" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>In the rest of the article, I will discuss how it’s implemented and how to deploy the system for your own voice AI applications.</p>
<h2 id="heading-two-voice-ai-approaches">Two Voice AI Approaches</h2>
<p>When OpenAI released its “realtime voice” services in October 2024, the consensus was that voice AI required “end-to-end” AI models. Traditional LLMs take text as input and then respond in text. The voice end-to-end models take voice audio data as input and respond in voice audio data as well. The end-to-end models could reduce latency since the voice processing, understanding, and generation are done in a single step.</p>
<p>But an end-to-end model is very difficult to customize. For example, it’s impossible to add your own prompt and knowledge to the context for each LLM request, or to act on the LLM's thinking or tool-call responses, or to clone your own voice for the response.</p>
<p>The second approach is to use an “agent orchestration” service to tie together multiple AI models, using one model’s output as the input for the next model. This allows us to customize or select each model and manipulate or supplement the model input at every step.</p>
<ul>
<li><p>The VAD model is used to detect conversation turns in the user's speech. It determines when the user is finished speaking and is now expecting a response.</p>
</li>
<li><p>The ASR/STT model turns user speech into text.</p>
</li>
<li><p>The LLM model generates a text response, including MCP tool calls.</p>
</li>
<li><p>The TTS model turns the response text into voice.</p>
</li>
</ul>
<p>The issue with multi-model and multi-step orchestration is that it can be slow. A lot of optimizations are needed for this approach to work well. For example, a useful technique is to utilize streaming input and output wherever possible. This way, each model doesn’t have to wait for the complete response from the upstream model.</p>
<p>The <a target="_blank" href="https://github.com/second-state/echokit_server">EchoKit server</a> is a stream-everything, highly efficient AI model orchestrator. It is entirely written in Rust for stability, safety, and speed.</p>
<h2 id="heading-the-voice-ai-orchestrator">The Voice AI Orchestrator</h2>
<p>The EchoKit server project is an open-source AI service orchestrator focused on real-time voice use cases. It starts up a WebSocket server that listens for streaming audio input and returns streaming audio responses.</p>
<p>You can build the <a target="_blank" href="https://github.com/second-state/echokit_server">echokit_server</a> project yourself using the Rust toolchain. Or, you can simply download the pre-built binary for your computer.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># for x86 / AMD64 CPUs</span>
curl -LO https://github.com/second-state/echokit_server/releases/download/v0.1.0/echokit_server-v0.1.0-x86_64-unknown-linux-gnu.tar.gz
unzip echokit_server-v0.1.0-x86_64-unknown-linux-gnu.tar.gz

<span class="hljs-comment"># for arm64 CPUs</span>
curl -LO https://github.com/second-state/echokit_server/releases/download/v0.1.0/echokit_server-v0.1.0-aarch64-unknown-linux-gnu.tar.gz
unzip echokit_server-v0.1.0-aarch64-unknown-linux-gnu.tar.gz
</code></pre>
<p>Then, run it as follows:</p>
<pre><code class="lang-bash">nohup ./echokit_server &amp;
</code></pre>
<p>It reads the <code>config.toml</code> file from the current directory. At the top of the file, you can configure the port on which the WebSocket server listens. You can also specify a WAV file that is downloaded to the connected <a target="_blank" href="https://echokit.dev/echokit_diy.html">EchoKit client device</a> as a welcome message.</p>
<pre><code class="lang-ini"><span class="hljs-attr">addr</span> = <span class="hljs-string">"0.0.0.0:8000"</span>
<span class="hljs-attr">hello_wav</span> = <span class="hljs-string">"hello.wav"</span>
</code></pre>
<h3 id="heading-configure-an-asr">Configure an ASR</h3>
<p>When the EchoKit server receives the user's voice data, it first sends the data to an ASR service to convert it into text.</p>
<p>There are many compelling ASR models available today. The EchoKit server can work with any OpenAI-compatible API providers, such as OpenAI itself, x.ai, OpenRouter, and Groq.</p>
<p>In our example, we use Groq’s Whisper ASR service. Whisper is a state-of-the-art ASR model released by OpenAI. Groq provides specialized hardware chips to run it very fast. You will first get <a target="_blank" href="https://console.groq.com/keys">a free API key from Groq</a>. Then, configure the ASR service as follows. Notice the “prompt” for the Whisper model. It is a tried-and-true prompt to reduce hallucination of the Whisper model.</p>
<pre><code class="lang-ini"><span class="hljs-section">[asr]</span>
<span class="hljs-attr">url</span> = <span class="hljs-string">"https://api.groq.com/openai/v1/audio/transcriptions"</span>
<span class="hljs-attr">api_key</span> = <span class="hljs-string">"gsk_XYZ"</span>
<span class="hljs-attr">model</span> = <span class="hljs-string">"whisper-large-v3"</span>
<span class="hljs-attr">lang</span> = <span class="hljs-string">"en"</span>
<span class="hljs-attr">prompt</span> = <span class="hljs-string">"Hello\n你好\n(noise)\n(bgm)\n(silence)\n"</span>
</code></pre>
<h3 id="heading-run-and-configure-a-vad">Run and configure a VAD</h3>
<p>In order to carry out a voice conversation, participants must detect each other's intentions and speak only when a turn arises. VAD (Voice Activity Detection) is a specialized AI model used to detect activities and, in particular, when the speaker has finished and expects an answer.</p>
<p>In EchoKit, we have VAD detection on both the device and the server.</p>
<ul>
<li><p>Device-side VAD: It detects human language. The device ignores background noise, music, keyboard sounds, and dog barking. It only sends human voice to the server.</p>
</li>
<li><p>Server-side VAD: It processes the audio stream in 100ms (0.1s) chunks. Once it detects that the speaker has finished, it sends all transcribed text to the LLM and starts waiting for the LLM’s response stream.</p>
</li>
</ul>
<p>The server-side VAD is optional, since the device-side VAD can also generate “conversation turn” signals. But due to the limited computing resources on the device, adding the server-side VAD can dramatically improve the overall VAD performance.</p>
<p>We’re porting the popular <a target="_blank" href="https://github.com/snakers4/silero-vad">Silero VAD</a> project from Python to Rust, and creating the <a target="_blank" href="https://github.com/second-state/silero_vad_server">silero_vad_server</a> project. Build the project <a target="_blank" href="https://github.com/second-state/silero_vad_server?tab=readme-ov-file#build-the-api-server">as instructed</a>. You can start the VAD server on your EchoKit server’s port 9094 as follows:</p>
<pre><code class="lang-bash">VAD_LISTEN=0.0.0.0:9094 nohup target/release/silero_vad_server &amp;
</code></pre>
<p>You might be wondering: why port to Rust? While many AI projects are written in Python for ease of development, Rust applications are often much lighter, faster, and safer at deployment. So, we’ll leverage AI tools like <a target="_blank" href="https://github.com/cardea-mcp/RustCoder">RustCoder</a> to port as much Python code as possible to Rust. The EchoKit software stack is largely written in Rust.</p>
<p>The VAD server is a WebSocket service that listens on port 9094. As we discussed, the EchoKit server will stream audio to this WebSocket and stop the ASR when a conversation turn is detected. Therefore, we’ll add the VAD service to the EchoKit server’s ASR config section in <code>config.toml</code>.</p>
<pre><code class="lang-ini"><span class="hljs-section">[asr]</span>
<span class="hljs-attr">url</span> = <span class="hljs-string">"https://api.groq.com/openai/v1/audio/transcriptions"</span>
<span class="hljs-attr">api_key</span> = <span class="hljs-string">"gsk_XYZ"</span>
<span class="hljs-attr">model</span> = <span class="hljs-string">"whisper-large-v3"</span>
<span class="hljs-attr">lang</span> = <span class="hljs-string">"en"</span>
<span class="hljs-attr">prompt</span> = <span class="hljs-string">"Hello\n你好\n(noise)\n(bgm)\n(silence)\n"</span>
<span class="hljs-attr">vad_realtime_url</span> = <span class="hljs-string">"ws://localhost:9094/v1/audio/realtime_vad"</span>
</code></pre>
<h3 id="heading-configure-an-llm">Configure an LLM</h3>
<p>Once the ASR service transcribes the user's voice into text, the next step in the pipeline is the LLM (Large Language Model). It’s the AI service that actually “thinks” and generates an answer in text.</p>
<p>Again, the EchoKit server can work with any OpenAI-compatible API providers for LLMs, such as OpenAI itself, x.ai, OpenRouter, and Groq. Since the voice service is highly sensitive to speed, we’ll choose Groq again. Groq supports a number of open-source LLMs. We’ll choose the <code>gpt-oss-20b</code> model released by OpenAI.</p>
<pre><code class="lang-ini"><span class="hljs-section">[llm]</span>
<span class="hljs-attr">llm_chat_url</span> = <span class="hljs-string">"https://api.groq.com/openai/v1/chat/completions"</span>
<span class="hljs-attr">api_key</span> = <span class="hljs-string">"gsk_XYZ"</span>
<span class="hljs-attr">model</span> = <span class="hljs-string">"openai/gpt-oss-20b"</span>
<span class="hljs-attr">history</span> = <span class="hljs-number">20</span>
</code></pre>
<p>The “history” field indicates how many messages should be kept in the context. Another crucial feature of an LLM application is the “system prompt,” where you instruct the LLM how it should “behave.” You can specify the system prompt in the EchoKit server config as well.</p>
<pre><code class="lang-ini"><span class="hljs-section">[[llm.sys_prompts]]</span>
<span class="hljs-attr">role</span> = <span class="hljs-string">"system"</span>
<span class="hljs-attr">content</span> = <span class="hljs-string">"""
You are a comedian. Engage in lighthearted and humorous conversation with the user. Tell jokes when appropriate.

"""</span>
</code></pre>
<p>Since Groq is very fast, it can process very large system prompts in under one second. You can add a lot more context and instructions to the system prompt. For example, you can give the application “knowledge” about a specific field by putting entire books into the system prompt.</p>
<h3 id="heading-configure-a-tts">Configure a TTS</h3>
<p>Finally, once the LLM generates a text response, the EchoKit server will call a TTS (text to speech) service to convert the text into voice and stream it back to the client device.</p>
<p>While Groq has a TTS service, it’s not particularly compelling. ElevenLabs is a leading TTS provider that offers hundreds of voice characters. It can express emotions and supports easy voice cloning. In the config below, you’ll put in your <a target="_blank" href="https://elevenlabs.io/app/sign-in?redirect=%2Fapp%2Fdevelopers%2Fapi-keys">ElevenLabs API key</a> and select a voice.</p>
<pre><code class="lang-ini"><span class="hljs-section">[tts]</span>
<span class="hljs-attr">platform</span> = <span class="hljs-string">"Elevenlabs"</span>
<span class="hljs-attr">token</span> = <span class="hljs-string">"sk_xyz"</span>
<span class="hljs-attr">voice</span> = <span class="hljs-string">"VOICE-ID-ABCD"</span>
</code></pre>
<p>The ElevenLabs TTS models and API services are all great, but they are not open-source. A very compelling open-source TTS, known as GPT-SoVITS, is also available.</p>
<p>You can port GPT-SoVITS from Python to Rust and create an open-source API server project called <a target="_blank" href="https://github.com/second-state/gsv_tts">gsv_tts</a>. It allows easy cloning of any voice. You can run a <a target="_blank" href="https://github.com/second-state/gsv_tts">gsv_tts</a> API server by following its instructions. Then, you can configure the EchoKit server to stream text to it and receive streaming audio from it.</p>
<pre><code class="lang-ini"><span class="hljs-section">[tts]</span>
<span class="hljs-attr">platform</span> = <span class="hljs-string">"StreamGSV"</span>
<span class="hljs-attr">url</span> = <span class="hljs-string">"http://gsv_tts.server:port/v1/audio/stream_speech"</span>
<span class="hljs-attr">speaker</span> = <span class="hljs-string">"michael"</span>
</code></pre>
<h3 id="heading-configure-mcp-and-actions">Configure MCP and actions</h3>
<p>Of course, an “AI agent” is not just about chatting. It is about performing actions on specific tasks. For example, the <a target="_blank" href="https://www.youtube.com/watch?v=Zy-rLT4EgZQ">“US civics test prep”</a> use case, which I shared as an example video at the beginning of this article, requires the agent to get exam questions from a database, and then generate responses that guide the user toward the official answer. This is accomplished using LLM tools and actions.</p>
<ul>
<li><p>The LLM detects that the user is requesting a new question.</p>
</li>
<li><p>Instead of responding in natural language, it responds with a JSON structure that instructs the agent to "get a new question and answer."</p>
</li>
<li><p>The EchoKit server intercepts this JSON response and retrieves the question and answer from a database.</p>
</li>
<li><p>The EchoKit server sends the question and answer back to the LLM.</p>
</li>
<li><p>The LLM formulates a natural language response based on the question and answer.</p>
</li>
<li><p>The EchoKit server generates a voice response using its TTS service.</p>
</li>
</ul>
<p>As you can see, the EchoKit server needs to perform a few extra steps behind the scenes before it responds in voice. The EchoKit server leverages the MCP protocol for this. The function to look up questions and answers is provided by an open-source MCP server called <a target="_blank" href="https://github.com/cardea-mcp/ExamPrepAgent">ExamPrepAgent</a>.</p>
<p>The MCP protocol standardizes the tools and functions for LLMs to call. There are many MCP servers available for all kinds of different tasks. ExamPrepAgent is just one of them.</p>
<p>We are running this MCP server on port 8003. With the MCP server up and running, you only need to add the following configuration to EchoKit server’s <code>config.toml</code>.</p>
<pre><code class="lang-ini"><span class="hljs-section">[[llm.mcp_server]]</span>
<span class="hljs-attr">server</span> = <span class="hljs-string">"http://localhost:8003/mcp"</span>
<span class="hljs-attr">type</span> = <span class="hljs-string">"http_streamable"</span>
</code></pre>
<p>With MCP integration, the EchoKit AI agent can now perform actions. It can call APIs to send messages, make payments, or even turn electronic devices on or off.</p>
<h2 id="heading-local-ai-with-llamaedge">Local AI With LlamaEdge</h2>
<p>You’ve now seen the open-source EchoKit device working with the open-source EchoKit server to understand and respond to users in voice. But the AI models we use, while also open-source, run on commercial cloud providers. Can we run AI models using open-source technologies at home?</p>
<p><a target="_blank" href="https://github.com/LlamaEdge/LlamaEdge">LlamaEdge</a> is an open-source, cross-platform API server for AI models. It <a target="_blank" href="https://llamaedge.com/docs/ai-models/">supports many mainstream LLM, ASR, and TTS models</a> across Linux, Mac, Windows, and many CPU/GPU architectures. It’s perfect for running AI models on home or office computers. It also provides OpenAI-compatible API endpoints, which makes them very easy to integrate into the EchoKit server.</p>
<p>To install LlamaEdge and its dependencies, run the following shell command. It will detect your hardware and install the appropriate software that can fully take advantage of your GPUs (if any).</p>
<pre><code class="lang-bash">curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install_v2.sh | bash -s
</code></pre>
<p>Then, download an open-source LLM model. I am using Google's Gemma model as an example.</p>
<pre><code class="lang-bash">curl -LO https://huggingface.co/second-state/gemma-3-4b-it-GGUF/resolve/main/gemma-3-4b-it-Q5_K_M.gguf
</code></pre>
<p>Download the cross-platform LlamaEdge API server.</p>
<pre><code class="lang-bash">curl -LO https://github.com/second-state/LlamaEdge/releases/latest/download/llama-api-server.wasm
</code></pre>
<p>Start an LLamaEdge API server with the Google Gemma LLM model. by default, it listens on localhost port 8080.</p>
<pre><code class="lang-bash">wasmedge --dir .:. --nn-preload default:GGML:AUTO:gemma-3-4b-it-Q5_K_M.gguf llama-api-server.wasm -p gemma-3
</code></pre>
<p>Test the OpenAI compatible API on that server.</p>
<pre><code class="lang-bash">curl -X POST http://localhost:8080/v1/chat/completions \
  -H <span class="hljs-string">'accept: application/json'</span> \
  -H <span class="hljs-string">'Content-Type: application/json'</span> \
  -d <span class="hljs-string">'{"messages":[{"role":"system", "content": "You are a helpful assistant. Try to be as brief as possible."}, {"role":"user", "content": "Where is the capital of Texas?"}]}'</span>
</code></pre>
<p>Now, you can add this local LLM service to your EchoKit server configuration.</p>
<pre><code class="lang-ini"><span class="hljs-section">[llm]</span>
<span class="hljs-attr">llm_chat_url</span> = <span class="hljs-string">"http://localhost:8080/v1/chat/completions"</span>
<span class="hljs-attr">api_key</span> = <span class="hljs-string">"NONE"</span>
<span class="hljs-attr">model</span> = <span class="hljs-string">"default"</span>
<span class="hljs-attr">history</span> = <span class="hljs-number">20</span>
</code></pre>
<p>The LlamaEdge project supports more than LLMs. It runs the <a target="_blank" href="https://github.com/LlamaEdge/whisper-api-server">Whisper ASR model</a> and the <a target="_blank" href="https://github.com/LlamaEdge/tts-api-server">Piper TTS model</a> as OpenAI-compatible API servers as well.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The voice AI agent software stack is complex and deep. EchoKit is an open-source platform that ties together and coordinates all those components. It provides a good vantage point for us to learn about the entire stack.</p>
<p>I can’t wait to see what you build!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are Smart Pointers in Rust? Explained with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ Smart pointers are data structures that act like pointers but contain extra information and have functionalities that make them excel over regular pointers in certain situations. So what are regular pointers? Regular pointers (just called “pointers”)... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/smart-pointers-in-rust-with-code-examples/</link>
                <guid isPermaLink="false">6721aeb8d9c3d37db41183a6</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oduah Chigozie ]]>
                </dc:creator>
                <pubDate>Wed, 30 Oct 2024 03:57:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730260779440/3d82425c-fdff-4a17-bb88-8193d964e6ba.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Smart pointers are data structures that act like pointers but contain extra information and have functionalities that make them excel over regular pointers in certain situations.</p>
<p>So what are regular pointers? Regular pointers (just called “pointers”) are variables that hold memory addresses as their values. They allow programs to store, read, and write data to memory locations with their addresses.</p>
<p>Here’s a diagram to give an idea of what they are:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730198558597/cd21ca42-32bb-4b41-98d3-b30956a6a398.png" alt="Diagram showing a table of variables and memory addresses. &quot;Text&quot; and &quot;Name&quot; are pointers that hold addresses 0x80012 and 0x80018 respectively" class="image--center mx-auto" width="2381" height="1632" loading="lazy"></p>
<p>In programming languages like C, C++, and Rust, pointers are useful for accessing manually allocated memory, but they come with these limitations:</p>
<ul>
<li><p>The memory address that a pointer holds can be deallocated while the pointer still references it, making it a dangling pointer.</p>
</li>
<li><p>The pointer doesn’t help with managing the memory allocation, which can cause memory leaks or other types of memory bugs in cases where handling memory allocations are complex.</p>
</li>
</ul>
<p>Rust doesn’t give the same level of control of pointers as with C and C++. However, like C++, Rust provides smart pointers that overcome the limitations of regular pointers while providing extra functionalities.</p>
<p>In Rust, there are four major types of smart pointers: <code>Box</code>, <code>Rc</code>, <code>Arc</code>, and <code>Weak</code>. I’ll be discussing them in this article. I’ll also touch a little on <code>RefCell</code>, because it adds a specific functionality that is missing in other smart pointers.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-box-pointers">Box Pointers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-rc-and-arc-pointers">Rc and Arc Pointers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-weak-pointers">Weak Pointers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-refcell">RefCell</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-box-pointers"><code>Box</code> Pointers</h2>
<p><code>Box</code> is the most straightforward type of a smart pointer. It allows you to manually allocate memory in the heap.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[allow(dead_code)]</span>
<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Point</span></span> {
    x: <span class="hljs-built_in">f32</span>,
    y: <span class="hljs-built_in">f32</span>,
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> point = <span class="hljs-built_in">Box</span>::new(Point { x: <span class="hljs-number">0.0</span>, y: <span class="hljs-number">0.0</span> });
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{:?}"</span>, point);
}
</code></pre>
<p>You can access the contents of a <code>Box</code> pointer like you would with a regular variable:</p>
<pre><code class="lang-rust"><span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, point.x); <span class="hljs-comment">// -&gt; output: 0.0</span>
<span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, point.y); <span class="hljs-comment">// -&gt; output: 0.0</span>
</code></pre>
<p>It works almost identically to <code>malloc</code> in C and <code>new</code> in c++, with the exception that <code>Box</code> automatically gets freed when it goes out of scope, or when the program execution ends, as opposed to manually freeing the allocation in <code>malloc</code> and <code>new</code>.</p>
<h2 id="heading-rc-and-arc-pointers"><code>Rc</code> and <code>Arc</code> Pointers</h2>
<p>I’m putting <code>Rc</code> and <code>Arc</code> together because they’re very similar in what they do and how they work.</p>
<p><code>Rc</code> and <code>Arc</code> are reference counted pointers that allow multiple ownership of a memory allocation. Similar to <code>Box</code>, they allocate memory in the heap, but what differentiates them from <code>Box</code> is that they also include a reference count.</p>
<p><code>Rc</code> and <code>Arc</code> allows you to create multiple clones of a reference to a memory allocation. This allows you to move those references to multiple scopes, and in the case of <code>Arc</code>, multiple threads, without borrowing. For example:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::sync::Arc;
<span class="hljs-keyword">use</span> std::thread;
<span class="hljs-keyword">use</span> std::thread::JoinHandle;

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">GameState</span></span> {
    user_name: <span class="hljs-built_in">String</span>,
}

<span class="hljs-keyword">impl</span> GameState {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        GameState { user_name: <span class="hljs-string">"Chigozie"</span>.to_string() }
    }
}

<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> threads: <span class="hljs-built_in">Vec</span>&lt;JoinHandle&lt;()&gt;&gt; = <span class="hljs-built_in">vec!</span>[];
    <span class="hljs-keyword">let</span> game_state = Arc::new( GameState::new() );

    <span class="hljs-keyword">let</span> g1 = Arc::clone(&amp;game_state); <span class="hljs-comment">// first clone</span>
    threads.push(thread::spawn(<span class="hljs-keyword">move</span> || {
        <span class="hljs-keyword">let</span> username = &amp;g1.user_name;
        <span class="hljs-comment">// ...</span>
    }));

    <span class="hljs-keyword">let</span> g2 = Arc::clone(&amp;game_state); <span class="hljs-comment">// second clone</span>
    threads.push(thread::spawn(<span class="hljs-keyword">move</span> || {
        <span class="hljs-keyword">let</span> username = &amp;g2.user_name;
        <span class="hljs-comment">// ...</span>
    }));

    <span class="hljs-keyword">let</span> g3 = Arc::clone(&amp;game_state); <span class="hljs-comment">// third clone</span>
    threads.push(thread::spawn(<span class="hljs-keyword">move</span> || {
        <span class="hljs-keyword">let</span> username = &amp;g3.user_name;
        <span class="hljs-comment">// ...</span>
    }));

    <span class="hljs-keyword">let</span> g4 = Arc::clone(&amp;game_state); <span class="hljs-comment">// fourth clone</span>
    threads.push(thread::spawn(<span class="hljs-keyword">move</span> || {
        <span class="hljs-keyword">let</span> username = &amp;g4.user_name;
        <span class="hljs-comment">// ...</span>
    }));

    <span class="hljs-keyword">let</span> g5 = Arc::clone(&amp;game_state); <span class="hljs-comment">// fifth clone</span>
    threads.push(thread::spawn(<span class="hljs-keyword">move</span> || {
        <span class="hljs-keyword">let</span> username = &amp;g5.user_name;
        <span class="hljs-comment">// ...</span>
    }));

    <span class="hljs-keyword">for</span> th <span class="hljs-keyword">in</span> threads {
        th.join().unwrap();
    }
}
</code></pre>
<p>In this example, I created an instance of a game struct in an <code>Arc</code> data structure, spawned five threads, then created and passed five more <code>Arc</code> references of the game struct to the five spawned threads.</p>
<p>The difference between <code>Rc</code> and <code>Arc</code> pointers is that references in <code>Arc</code> pointers are counted atomically, while references in <code>Rc</code> pointers are counted using the usual mathematical operations. This means that the operations that go into counting the references in <code>Arc</code> pointers are guaranteed to not be interrupted or overlapped by other threads or processes, making them very useful for multi-threaded environments.</p>
<p>One useful application of <code>Rc</code> and <code>Arc</code> pointers is in reference-based data structures, like linked lists, where each node has its value and a reference to the next node. For example:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::rc::Rc;

<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Node</span></span> {
    value: <span class="hljs-built_in">i32</span>,
    next: <span class="hljs-built_in">Option</span>&lt;Rc&lt;Node&gt;&gt;,
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// A chain of nodes</span>
    <span class="hljs-keyword">let</span> node1 = Rc::new(Node { value: <span class="hljs-number">1</span>, next: <span class="hljs-literal">None</span> });
    <span class="hljs-keyword">let</span> node2 = Rc::new(Node { value: <span class="hljs-number">2</span>, next: <span class="hljs-literal">Some</span>(Rc::clone(&amp;node1)) });
    <span class="hljs-keyword">let</span> node3 = Rc::new(Node { value: <span class="hljs-number">3</span>, next: <span class="hljs-literal">Some</span>(Rc::clone(&amp;node2)) });

    <span class="hljs-comment">// Multiple owners of node2</span>
    <span class="hljs-keyword">let</span> another_ref_to_node2 = Rc::clone(&amp;node2);

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Node 3: {:?}"</span>, node3);
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Another reference to Node 2: {:?}"</span>, another_ref_to_node2);
}
</code></pre>
<p>The memory allocations pointed to by <code>Rc</code> and <code>Arc</code> references are dropped when their reference counts goes to 0. The reference count of <code>Rc</code> and <code>Arc</code> pointers goes to 0 when it and all its clones have gone out of scope, or have been dropped manually.</p>
<h2 id="heading-weak-pointers"><code>Weak</code> Pointers</h2>
<p>Unlike <code>Arc</code> or <code>Rc</code> pointers, <code>Weak</code> pointers are non-owning references to memory allocations. This means that they don’t count towards ownership of the memory allocation and don’t stop memory allocations from being dropped.</p>
<p><code>Weak</code> references are helpful in scenarios where you might prefer a reference to a memory allocation to prevent it from being deallocated. A good example of a scenario like this is a doubly linked list, where each node holds a reference to the next node and the previous node:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729610464614/f2f11dcd-56e9-401d-b35b-f5a29d8d9dc5.png" alt="Diagram of a doubly linked list. Each node in the doubly linked list has a pointer to the node that comes before it and the node that comes after it." class="image--center mx-auto" width="4095" height="1290" loading="lazy"></p>
<p>A scenario like this using <code>Rc</code> or <code>Arc</code> for both the next and previous nodes can cause reference cycles. Reference cycles prevent nodes from being deallocated because for one node to be deallocated all <code>Arc</code> or <code>Rc</code> references to it must be 0. Since the nodes in this case hold references to other nodes that also hold references back to it, both nodes can’t be deallocated automatically and they can end up stopping all other nodes in the data structure from being deallocated, causing a memory leak.</p>
<p>To prevent reference cycles while allowing nodes to both reference previous and next nodes, you can make each node’s reference to its previous node a <code>Weak</code> reference. For example:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::rc::{Rc, Weak};
<span class="hljs-keyword">use</span> std::cell::RefCell;

<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Node</span></span> {
    value: <span class="hljs-built_in">i32</span>,
    next: <span class="hljs-built_in">Option</span>&lt;Rc&lt;RefCell&lt;Node&gt;&gt;&gt;,
    prev: <span class="hljs-built_in">Option</span>&lt;Weak&lt;RefCell&lt;Node&gt;&gt;&gt;, <span class="hljs-comment">// Weak reference to avoid cycles</span>
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> node1 = Rc::new(RefCell::new(Node { value: <span class="hljs-number">1</span>, next: <span class="hljs-literal">None</span>, prev: <span class="hljs-literal">None</span> }));
    <span class="hljs-keyword">let</span> node2 = Rc::new(RefCell::new(Node { value: <span class="hljs-number">2</span>, next: <span class="hljs-literal">None</span>, prev: <span class="hljs-literal">Some</span>(Rc::downgrade(&amp;node1)) }));

    <span class="hljs-comment">// Set node1's next to node2</span>
    node1.borrow_mut().next = <span class="hljs-literal">Some</span>(Rc::clone(&amp;node2));

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Node 1: {:?}"</span>, node1);
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Node 2: {:?}"</span>, node2);
}
</code></pre>
<p>However, since <code>Weak</code> references have non-owning references to memory allocations, they need to be upgraded to <code>Rc</code> or <code>Arc</code> references with <code>.upgrade()</code> to allow access to the memory allocation they point to.</p>
<p>Also, as you can see in code example below (as well as above on line 13), <code>Rc</code> and <code>Arc</code> references can be downgraded to <code>Weak</code> references with <code>Rc::downgrade()</code> or <code>Arc::downgrade()</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::rc::{Rc, Weak};

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> strong = Rc::new(<span class="hljs-number">5</span>);
    <span class="hljs-keyword">let</span> weak = Rc::downgrade(&amp;strong);

    <span class="hljs-comment">// Drop the weak reference</span>
    <span class="hljs-built_in">drop</span>(weak);

    <span class="hljs-comment">// try to upgrade the weak reference</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(shared) = weak.upgrade() {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Data is still alive: {}"</span>, shared);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Data has been dropped"</span>);
    }
}
</code></pre>
<p>Running this results in the following output:</p>
<pre><code class="lang-rust">Data has been dropped
</code></pre>
<p>This shows that only having weak references to a memory allocation doesn’t prevent it from being dropped. If a <code>Weak</code> pointer’s memory allocation is dropped, calling <code>.upgrade()</code> on the <code>Weak</code> pointer would return <code>None</code>.</p>
<h2 id="heading-refcell"><code>RefCell</code></h2>
<p>To ensure memory safety, Rust doesn’t allow you to mutate the data that smart pointers point to. This can prevent hidden mutations, but can become really inconvenient when you need to build something that is dynamically changing (for example the ability to add a new node to anywhere in a linked-list data structure).</p>
<p><code>RefCell</code> allows you to overcome this limitation because it is a data structure that allows interior mutability of immutable variables by enforcing Rust’s borrowing rules at runtime.</p>
<p>You may have noticed it’s usage in the <code>Weak</code> pointer example earlier:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::rc::{Rc, Weak};
<span class="hljs-keyword">use</span> std::cell::RefCell;

<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Node</span></span> {
    value: <span class="hljs-built_in">i32</span>,
    next: <span class="hljs-built_in">Option</span>&lt;Rc&lt;RefCell&lt;Node&gt;&gt;&gt;,
    prev: <span class="hljs-built_in">Option</span>&lt;Weak&lt;RefCell&lt;Node&gt;&gt;&gt;,
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> node1 = Rc::new(RefCell::new(Node { value: <span class="hljs-number">1</span>, next: <span class="hljs-literal">None</span>, prev: <span class="hljs-literal">None</span> }));
    <span class="hljs-keyword">let</span> node2 = Rc::new(RefCell::new(Node { value: <span class="hljs-number">2</span>, next: <span class="hljs-literal">None</span>, prev: <span class="hljs-literal">Some</span>(Rc::downgrade(&amp;node1)) }));

    <span class="hljs-comment">// Set node1's next to node2</span>
    node1.borrow_mut().next = <span class="hljs-literal">Some</span>(Rc::clone(&amp;node2));

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Node 1: {:?}"</span>, node1);
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Node 2: {:?}"</span>, node2);
}
</code></pre>
<p>You can call <code>.borrow()</code> and <code>.borrow_mut()</code> on a <code>RefCell</code> type to borrow references to its internal value at runtime, while keeping its own type as immutable making it useful in cases like this that require immutability.</p>
<p>Mutable and immutable borrows in a <code>RefCell</code> type work just like regular borrows that are checked at compile time, but they allow you to bypass compile time restrictions to be checked instead at runtime.</p>
<p>One major borrowing rule to look out for is the “single mutable ownership and multiple immutable ownership” rule. Borrowing two mutable references to a <code>RefCell</code> would result in a panic, crashing the application. For example:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![allow(unused_variables)]</span>
<span class="hljs-meta">#![allow(dead_code)]</span>
<span class="hljs-meta">#![allow(unused_mut)]</span>
<span class="hljs-keyword">use</span> std::cell::RefCell;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> counter = RefCell::new(<span class="hljs-number">100</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> c1 = counter.borrow_mut();
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> c2 = counter.borrow_mut();

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"I'm done"</span>);
}

<span class="hljs-comment">/**
 * output:
 *  thread 'main' panicked at src/main.rs:9:26:
 *  already borrowed: BorrowMutError
 *  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 */</span>
</code></pre>
<h2 id="heading-summary">Summary</h2>
<p>To give an overview of the points made in this article, there are four common types of smart pointers in Rust:</p>
<ul>
<li><p><code>Box</code> is used for manually allocating memory in the heap (similar to <code>malloc</code> and <code>new</code> in C and C++ respectively)</p>
</li>
<li><p><code>Rc</code> and <code>Arc</code> are used for allowing multiple ownership of a memory allocation. <code>Arc</code> is best for multi-threaded environments, and <code>Rc</code> is best for single-threaded environments.</p>
</li>
<li><p><code>Weak</code> is best used in giving multiple ownership of a memory allocation while preventing reference cycles.</p>
</li>
<li><p><code>RefCell</code> allows mutability in scenarios that require immutability, for example, in smart pointers.</p>
</li>
</ul>
<p>I hope this article has provided clarity on smart pointers in Rust and how they work. Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are Lifetimes in Rust? Explained with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ Lifetimes are fundamental mechanisms in Rust. There's a very high chance you'll need to work with lifetimes in any Rust project that has any sort of complexity. Even though they are important to Rust projects, lifetimes can be quite tricky to wrap yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-lifetimes-in-rust-explained-with-code-examples/</link>
                <guid isPermaLink="false">66db602d7e903d0d43f602aa</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ rust lang ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oduah Chigozie ]]>
                </dc:creator>
                <pubDate>Fri, 06 Sep 2024 20:03:57 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725652969333/ba8a3fb6-3ac8-40e0-91e6-3e32e7f7b4b4.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Lifetimes are fundamental mechanisms in Rust. There's a very high chance you'll need to work with lifetimes in any Rust project that has any sort of complexity.</p>
<p>Even though they are important to Rust projects, lifetimes can be quite tricky to wrap your head around. So I created this guide to provide more clarity on what they are and when you should use them.</p>
<h3 id="heading-prerequisites-for-this-tutorial">Prerequisites for this Tutorial</h3>
<p>To get the most out of this tutorial, you'll need the following:</p>
<ul>
<li><p>At least beginner-level familiarity with Rust: This tutorial doesn't help with learning how to code in Rust. It only helps with understanding lifetimes in Rust and how they work</p>
</li>
<li><p>Familiarity with generics: Generics in Rust work identically to how they do in popular programming languages. Knowledge of how generics work in any language would be helpful.</p>
</li>
<li><p>Knowing how the borrow checker works isn't as much a requirement as the last two above, but it would be helpful. Knowledge of how lifetimes work also helps in understanding how the borrow checker works.</p>
</li>
</ul>
<h2 id="heading-so-what-are-lifetimes-in-rust">So, What are Lifetimes in Rust?</h2>
<p>For Rust's <a target="_blank" href="https://doc.rust-lang.org/rust-by-example/scope/borrow.html">borrow checker</a> to ensure safety throughout your code, it needs to know how long all the data in the program will live during its execution. This becomes difficult to do in certain situations, and those situations are where you need to use explicit lifetime annotations.</p>
<p>Lifetimes in Rust are mechanisms for ensuring that all borrows that occur within your code are valid. A variable's lifetime is how long it lives within the program's execution, starting from when it's initialized and ending when it's destroyed in the program.</p>
<p>The borrow checker can detect the lifetimes of variables in many cases. But in cases where it can't, you have to assist it with explicit lifetime annotations.</p>
<p>The syntax for explicit lifetime annotations is a single quote followed by a set of characters for identification (for example, <code>'static</code>, <code>'a</code>) as in:</p>
<pre><code class="lang-rust">max&lt;<span class="hljs-symbol">'a</span>&gt;
</code></pre>
<p>The lifetime annotation indicates that <code>max</code> should live at most as long as <code>'a</code>.</p>
<p>Using multiple lifetimes follows the same syntax:</p>
<pre><code class="lang-rust">max&lt;<span class="hljs-symbol">'a</span>, <span class="hljs-symbol">'b</span>&gt;
</code></pre>
<p>In this case, the lifetime annotations indicate that <code>max</code> should live at most as long as <code>'a</code> and <code>'b</code>.</p>
<p>Explicit lifetime annotations are handled similarly to how generics are. Let's take a look at an example:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>&lt;<span class="hljs-symbol">'a</span>&gt;(s1: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span> {
    <span class="hljs-comment">// return the longest string out of the two</span>
}
</code></pre>
<p>In the example, the lifetime annotations indicate that <code>max</code> should live at most as long as the lifetimes of <code>s1</code> or <code>s2</code>. It also indicates that <code>max</code> returns a reference that lives as long as <code>s1</code>.</p>
<p>A Rust project has many cases that would require explicit lifetime annotations, and in the next few sections, we'll go over each of them.</p>
<h2 id="heading-lifetime-annotations-in-functions">Lifetime Annotations in Functions</h2>
<p>A function only needs an explicit lifetime annotation when it returns a reference from any of its arguments. Let's take an example:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>&lt;<span class="hljs-symbol">'a</span>&gt;(s1: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span> {
    <span class="hljs-keyword">if</span> s1.len() &gt; s2.len() {
        s1
    } <span class="hljs-keyword">else</span> {
        s2
    }
}
</code></pre>
<p>If you remove the lifetime annotations, you'll get an LSP (Language Server Protocol) warning to include the lifetime annotations. If you ignore LSP's warning message and compile the code, you'll get the same message as a compiler error. For example:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>(s1: &amp;<span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-built_in">str</span>) -&gt; &amp;<span class="hljs-built_in">str</span> {
    <span class="hljs-keyword">if</span> s1.len() &gt; s2.len() {
        s1
    } <span class="hljs-keyword">else</span> {
        s2
    }
}

<span class="hljs-comment">/**
 * Output -&gt;
 *
error[E0106]: missing lifetime specifier
  --&gt; src/main.rs:44:31
   |
44 | fn max(s1: &amp;str, s2: &amp;str) -&gt; &amp;str {
   |            ----      ----     ^ expected named lifetime parameter
   |
   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `s1` or `s2`
help: consider introducing a named lifetime parameter
   |
44 | fn max&lt;'a&gt;(s1: &amp;'a str, s2: &amp;'a str) -&gt; &amp;'a str {
   |       ++++      ++           ++          ++

For more information about this error, try `rustc --explain E0106`.
error: could not compile `lifetime-test` (bin "lifetime-test") due to 1 previous error
 ***********************
 */</span>
</code></pre>
<p>On the other hand, a function doesn't need explicit lifetimes if it isn't returning a reference in its arguments. For example:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">print_longest</span></span>(s1: &amp;<span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-built_in">str</span>) {
    <span class="hljs-keyword">if</span> s1.len() &gt; s2.len() {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{s1} is longer than {s2}"</span>)
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{s2} is longer than {s1}"</span>)
    }
}
</code></pre>
<p>A function returning a different value doesn't need explicit lifetime annotations either:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">join_strs</span></span>(s1: &amp;<span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">String</span> {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> joint_string = <span class="hljs-built_in">String</span>::from(s1);
    joint_string.push_str(s2);
    <span class="hljs-keyword">return</span> joint_string;
}
</code></pre>
<p>You only need to specify lifetimes if a function returns a reference from one of its arguments that is a borrowed reference.</p>
<h2 id="heading-lifetime-annotations-in-structs">Lifetime Annotations in Structs</h2>
<p>Structs require explicit lifetime annotations when any of their fields are references. This allows the borrow checker to ensure that the references in the struct's fields live longer than the struct. For example:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Strs</span></span>&lt;<span class="hljs-symbol">'a</span>, <span class="hljs-symbol">'b</span>&gt; {
    x: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>,
    y: &amp;<span class="hljs-symbol">'b</span> <span class="hljs-built_in">str</span>,
}
</code></pre>
<p>Without the lifetime annotations, you'll get a similar LSP and compiler error message to the one in the previous section:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">OtherStruct</span></span> {
    x: &amp;<span class="hljs-built_in">str</span>,
    y: &amp;<span class="hljs-built_in">str</span>,
}

<span class="hljs-comment">/**
* Output -&gt;
**********************
error[E0106]: missing lifetime specifier
 --&gt; src/main.rs:7:8
  |
7 |     x: &amp;str,
  |        ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
6 ~ struct OtherStruct&lt;'a&gt; {
7 ~     x: &amp;'a str,
  |

error[E0106]: missing lifetime specifier
 --&gt; src/main.rs:8:8
  |
8 |     y: &amp;str,
  |        ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
6 ~ struct OtherStruct&lt;'a&gt; {
7 |     x: &amp;str,
8 ~     y: &amp;'a str,
  |

For more information about this error, try `rustc --explain E0106`.
error: could not compile `lifetime-test` (bin "lifetime-test") due to 2 previous errors
**********************
*/</span>
</code></pre>
<h2 id="heading-lifetime-annotations-in-methods">Lifetime Annotations in Methods</h2>
<p>Lifetime annotations concerning methods can be done as annotations to standalone methods, <code>impl</code> blocks, or traits. Let's look at each of them:</p>
<h3 id="heading-standalone-methods">Standalone Methods:</h3>
<p>Annotating lifetimes on standalone methods is identical to annotating lifetimes in functions:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Struct {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>&lt;<span class="hljs-symbol">'a</span>&gt;(<span class="hljs-keyword">self</span>: &amp;<span class="hljs-keyword">Self</span>, s1: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span> {
        <span class="hljs-keyword">if</span> s1.len() &gt; s2.len() {
            s1
        } <span class="hljs-keyword">else</span> {
            s2
        }
    }
}
</code></pre>
<h3 id="heading-impl-blocks"><code>impl</code> Blocks</h3>
<p>Writing explicit lifetime annotations for <code>impl</code> blocks is required if the struct it is associated with has lifetime annotations in its definition. This is the syntax for writing <code>impl</code> blocks with explicit lifetime annotations:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Struct</span></span>&lt;<span class="hljs-symbol">'a</span>&gt; {
}

<span class="hljs-keyword">impl</span>&lt;<span class="hljs-symbol">'a</span>&gt; Struct&lt;<span class="hljs-symbol">'a</span>&gt; {
}
</code></pre>
<p>This allows any method you write in the <code>impl</code> block to return a reference from <code>Struct</code>. For example:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Strs</span></span>&lt;<span class="hljs-symbol">'a</span>&gt; {
    x: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>,
    y: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>,
}

<span class="hljs-keyword">impl</span>&lt;<span class="hljs-symbol">'a</span>&gt; Strs&lt;<span class="hljs-symbol">'a</span>&gt; {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>(<span class="hljs-keyword">self</span>: &amp;<span class="hljs-keyword">Self</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.y.len() &gt; <span class="hljs-keyword">self</span>.x.len() {
            <span class="hljs-keyword">self</span>.y
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">self</span>.x
        }
    }
}
</code></pre>
<h3 id="heading-traits">Traits</h3>
<p>Lifetime annotations in traits are dependent on the methods that the trait defines.</p>
<p>Let's look at one example. A method inside a trait definition can use explicit lifetime annotations as a standalone method, and the trait definition won't require explicit lifetime annotations. Like so:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Max</span></span> {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">longest_str</span></span>&lt;<span class="hljs-symbol">'a</span>&gt;(s1: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>;
}

<span class="hljs-keyword">impl</span>&lt;<span class="hljs-symbol">'a</span>&gt; Max <span class="hljs-keyword">for</span> Struct&lt;<span class="hljs-symbol">'a</span>&gt; {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">longest_str</span></span>(s1: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>) {
        <span class="hljs-keyword">if</span> s1.len() &gt; s2.len() {
            s1
        } <span class="hljs-keyword">else</span> {
            s2
        }
    }
}
</code></pre>
<p>If a trait method requires references from the struct its associated with, the trait's definition would require explicit lifetime annotations. For example:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Max</span></span>&lt;<span class="hljs-symbol">'a</span>&gt; {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>(<span class="hljs-keyword">self</span>: &amp;<span class="hljs-keyword">Self</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>;
}
</code></pre>
<p>Which can be implemented this way:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Strs</span></span>&lt;<span class="hljs-symbol">'a</span>&gt; {
    x: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>,
    y: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>,
}

<span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Max</span></span>&lt;<span class="hljs-symbol">'a</span>&gt; {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>(<span class="hljs-keyword">self</span>: &amp;<span class="hljs-keyword">Self</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>;
}

<span class="hljs-keyword">impl</span>&lt;<span class="hljs-symbol">'a</span>&gt; Max&lt;<span class="hljs-symbol">'a</span>&gt; <span class="hljs-keyword">for</span> Strs&lt;<span class="hljs-symbol">'a</span>&gt; {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>(<span class="hljs-keyword">self</span>: &amp;<span class="hljs-keyword">Self</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.y.len() &gt; <span class="hljs-keyword">self</span>.x.len() {
            <span class="hljs-keyword">self</span>.y
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">self</span>.x
        }
    }
}
</code></pre>
<h2 id="heading-lifetime-annotations-in-enums">Lifetime Annotations in Enums</h2>
<p>Similar to structs, enums need explicit lifetime annotations if any of their fields are references. For example:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Either</span></span>&lt;<span class="hljs-symbol">'a</span>&gt; {
    Str(<span class="hljs-built_in">String</span>),
    Ref(&amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">String</span>),
}
</code></pre>
<h2 id="heading-the-static-lifetime">The <code>'static</code> Lifetime</h2>
<p>In many Rust projects, you'll likely have encountered variables that are <code>'static</code> in lifetimes. In this section, we'll go over a brief overview of what a <code>'static</code> lifetime is, how it works, and where it is commonly used.</p>
<p><code>'static</code> is a reserved lifetime name in Rust. It signifies that the data that a reference points to lives from where it is initialized to the end of the program. This differs slightly from static variables, which are stored directly in the program's binary file. However, all static variables have a <code>'static</code> lifetime.</p>
<p>Variables with <code>'static</code> lifetimes can be created at runtime. But they can't be dropped, only coerced into shorter lifetimes. For example:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// The lifetime annotation 'a is the shorter lifetime of the</span>
<span class="hljs-comment">// two arguments s1 and s2</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">max</span></span>&lt;<span class="hljs-symbol">'a</span>&gt;(s1: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>, s2: &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span>) -&gt; &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">str</span> {
    <span class="hljs-keyword">if</span> s1.len() &gt; s2.len() {
        s1
    } <span class="hljs-keyword">else</span> {
        s2
    }
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> first = <span class="hljs-string">"First string"</span>; <span class="hljs-comment">// Longer lifetime</span>

    {
        <span class="hljs-keyword">let</span> second = <span class="hljs-string">"Second string"</span>; <span class="hljs-comment">// Shorter lifetime</span>

        <span class="hljs-comment">// In the max function, the lifetime of first is</span>
        <span class="hljs-comment">// coerced into the lifetime of second</span>
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"The biggest of {} and {} is {}"</span>, first, second, max(first, second));
    };
}
</code></pre>
<p>String literals are examples of values with <code>'static</code> lifetimes. They are also stored in the program's binary file and can be created at runtime.</p>
<p>Rust allows you to declare static variables with the <code>static</code> keyword, using this syntax:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">static</span> IDENTIFIER: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span> = <span class="hljs-string">"value"</span>;
</code></pre>
<p>Static variables can be declared in any scope, including the global scope. This means that you can use static variables as global variables. For example:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">static</span> FIRST_NAME: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span> = <span class="hljs-string">"John"</span>;
<span class="hljs-keyword">static</span> LAST_NAME: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span> = <span class="hljs-string">"Doe"</span>;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"First name: {}"</span>, FIRST_NAME);
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Last name: {}"</span>, LAST_NAME);
}
</code></pre>
<p>Static variables can also be mutable or immutable. But working with mutable static variables is only allowed in <code>unsafe</code> blocks because they're unsafe.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">static</span> <span class="hljs-keyword">mut</span> FIRST_NAME: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span> = <span class="hljs-string">"John"</span>;
<span class="hljs-keyword">static</span> LAST_NAME: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span> = <span class="hljs-string">"Doe"</span>;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">unsafe</span> {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"First name: {}"</span>, FIRST_NAME);
    }
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Last name: {}"</span>, LAST_NAME);
    <span class="hljs-keyword">unsafe</span> {
        FIRST_NAME = <span class="hljs-string">"Jane"</span>;
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"First name changed to: {}"</span>, FIRST_NAME);
    }
}
</code></pre>
<h2 id="heading-summary">Summary</h2>
<p>Lifetimes in Rust help the borrow checker ensure that all borrowed references are valid. The borrow checker can detect the lifetimes of variables in many cases, but in cases where it can't you have to assist it with explicit lifetime annotations.</p>
<p>Explicit lifetime annotations are those <code>'a</code>, <code>'b</code>, and <code>'static</code> things you see in many Rust projects. You only need to use them in structures (structs, enums, traits, and impls) that deal with references, and in functions or methods that receive and return references.</p>
<p>In this guide, you learned about explicit lifetime annotations and saw some examples of how to use them. I it gave you some clarity on the topic, and helped you understand lifetimes better.</p>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Speedy Web Compiler? SWC Explained With Examples ]]>
                </title>
                <description>
                    <![CDATA[ In the evolving landscape of JavaScript development, the need for efficient and powerful tooling has become increasingly important. Developers rely on tools like compilers and bundlers to transform their code, optimize performance, and ensure compati... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-speedy-web-compiler/</link>
                <guid isPermaLink="false">66d90463e90270a49f64f4c6</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Preston Mayieka ]]>
                </dc:creator>
                <pubDate>Thu, 05 Sep 2024 01:07:47 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725290113209/260f00cb-5bfe-4260-8e45-0c61a1897cae.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the evolving landscape of JavaScript development, the need for efficient and powerful tooling has become increasingly important.</p>
<p>Developers rely on tools like <a target="_blank" href="https://en.wikipedia.org/wiki/Compiler"><strong>compilers</strong></a> and <a target="_blank" href="https://www.codejourney.net/what-is-a-javascript-bundler/"><strong>bundlers</strong></a> to transform their code, optimize performance, and ensure compatibility across different environments.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287352931/41e13dc3-100e-4f75-87df-98342df4beb2.png" alt="41e13dc3-100e-4f75-87df-98342df4beb2" class="image--center mx-auto" width="901" height="506" loading="lazy"></p>
<p>These tools are essential for modern JavaScript applications, enabling developers to write clean, maintainable code while leveraging the latest language features.</p>
<p>This article will help you understand what Speedy Web Compiler (SWC) is and how it helps optimize the performance of your web apps.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-speedy-web-compiler">Introduction to Speedy Web Compiler</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-background-of-swc">Background of SWC</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-speedy-web-compiler-works">How Speedy Web Compiler Works</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-benefits-of-using-speedy-web-compiler">Benefits of Using Speedy Web Compiler</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-speedy-web-compiler">How to Set Up Speedy Web Compiler in Your Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-swc-integration-in-popular-frameworks">SWC Integration in Popular Frameworks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-speedy-web-compiler">What is Speedy Web Compiler?</h2>
<p>First, let me break it down.</p>
<p>SWC stands for Speedy Web Compiler, and when broken down:</p>
<p><strong>Speedy</strong> - This means it's fast! SWC processes and transforms JavaScript code, making it efficient to use in big projects.</p>
<p><strong>Web</strong> - It’s all about web development. It focuses on improving how JavaScript (the language of the web) handles it.</p>
<p><strong>Compiler</strong> - It takes code written in one form and transforms it into another form that can be better understood or used by computers.</p>
<h2 id="heading-background-of-swc">Background of SWC</h2>
<p><a target="_blank" href="https://github.com/kdy1">kdy1</a>, a South Korean developer and maintainer of <a target="_blank" href="https://nextjs.org/">Next.js</a>, created SWC as a faster tool for handling JavaScript code.</p>
<p>The motivation was the need for speed and efficiency, as web projects grow larger and more complex.</p>
<p>With numerous websites and apps depending on JavaScript, SWC helps developers save time and work more efficiently.</p>
<h2 id="heading-how-speedy-web-compiler-works">How Speedy Web Compiler Works</h2>
<p>SWC uses <a target="_blank" href="https://www.rust-lang.org/">Rust</a>, a programming language known for its speed and safety.</p>
<p>SWC works by taking your JavaScript or TypeScript code and transforming it into a version that can run efficiently in various environments.</p>
<p>Understanding how SWC achieves this involves examining its core steps: parsing, transforming, and generating code.</p>
<h3 id="heading-how-does-swc-parse-code">How Does SWC Parse Code?</h3>
<p>The first step in the compilation process is parsing.</p>
<p>Begins by <strong>reading</strong> and analyzing the code to understand its structure.</p>
<p>This is akin to taking a complex sentence and breaking it down into its grammatical components—subject, verb, object, etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287153049/b7ec431c-24db-4c7a-9fb0-ef3ce0d92921.png" alt="Illustration of Code parsing into forming abstract syntax tree" class="image--center mx-auto" width="891" height="499" loading="lazy"></p>
<p>In technical terms, SWC converts your code into an <a target="_blank" href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"><strong>Abstract Syntax Tree (AST)</strong>.</a></p>
<p>The AST is a tree-like representation of the source code, where each node in the tree corresponds to a construct occurring in the code, such as expressions, statements, and functions.</p>
<p>This tree structure allows SWC to process and understand the code’s logic in a way that is both efficient and scalable.</p>
<h3 id="heading-how-does-swc-transform-code">How Does SWC Transform Code?</h3>
<p>After creating the AST, SWC moves on to the transformation phase.</p>
<p>This is where the magic happens—SWC applies various optimizations and changes to the code based on the target environment.</p>
<p>For instance, if you're targeting older browsers that don't support modern JavaScript features, SWC will transform your ES6+ code into a backward-compatible version.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287185279/371d2ac2-e919-4f25-8caf-01d4157fd290.png" alt="Yellow gear with two circular arrows surrounding it, accompanied by the text &quot;Transformation of AST&quot; on a dark background." class="image--center mx-auto" width="888" height="498" loading="lazy"></p>
<p>During this phase, SWC also handles TypeScript transformations. It strips away TypeScript-specific syntax, such as types and interfaces, converting the code into pure JavaScript that gets executed by any JavaScript engine.</p>
<p>SWC can apply custom transformations based on plugins or specific configurations, making it highly versatile.</p>
<h3 id="heading-how-does-swc-generate-optimized-code">How Does SWC Generate Optimized Code?</h3>
<p>After the transformations are complete, SWC proceeds to the final step: code generation.</p>
<p>In this step, SWC takes the transformed AST and converts it back into executable code.</p>
<p>In contrast, this process is not just a reversal of the parsing process.</p>
<p>SWC takes special care to generate code that is both functionally correct and optimized for performance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287212996/af724e34-6473-4104-8244-e35c1be6a3c0.png" alt="Yellow line drawing of a coding window with a wrench and gear icon, above text that reads &quot;Generation of Optimized Code&quot; on a black background." class="image--center mx-auto" width="886" height="496" loading="lazy"></p>
<p>For instance, SWC might remove dead code (code that will never be executed) or inline certain functions to reduce overhead.</p>
<p>The goal is to produce code that is as clean and efficient as possible, ensuring that it runs quickly and reliably in production environments.</p>
<h2 id="heading-benefits-of-using-speedy-web-compiler">Benefits of Using Speedy Web Compiler</h2>
<h3 id="heading-performance">Performance</h3>
<p>One of the major benefits of using SWC is its outstanding speed. SWC achieves this exceptional speed by using Rust.</p>
<p>Developers can expect a significant performance improvement when compiling their code for large projects or codebases.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287254910/9c4827d9-81db-488d-bdb8-6b0806ddfd67.png" alt="Illustration of a stopwatch inside a web browser window, with motion lines indicating speed. The text below reads &quot;Faster Loading Times.&quot;" class="image--center mx-auto" width="893" height="498" loading="lazy"></p>
<p>This speed greatly reduces build times, enhancing the efficiency and responsiveness of the development process. It is so fast, you might think it’s late for a meeting!</p>
<h3 id="heading-optimized-output">Optimized Output</h3>
<p>SWC compiles your code and guarantees that the output is highly optimized for performance in production environment by removing dead code, in-lining functions, and reducing the size of the output.</p>
<p>This makes using SWC cost-effective, saving you from extra expenses during production.</p>
<p>The result is a leaner, faster, and more efficient code that can enhance loading times and performance in web applications.</p>
<h3 id="heading-compatibility">Compatibility</h3>
<p>SWC is fully compatible with modern JavaScript libraries and frameworks.</p>
<p>You do not have to worry about using ES6+ or TypeScript. This makes SWC a versatile choice for your projects.</p>
<h2 id="heading-how-to-set-up-speedy-web-compiler">How to Set Up Speedy Web Compiler</h2>
<h3 id="heading-installation">Installation</h3>
<p>To install SWC in your JavaScript or TypeScript project, follow these steps:</p>
<ol>
<li><strong>Initialize your project:</strong> If you haven't already, start by initializing a new project. In your terminal, run:</li>
</ol>
<pre><code class="lang-bash">npm init -y
</code></pre>
<ol start="2">
<li><strong>Install SWC with npm:</strong> Run the following command to download the pre-built binaries:</li>
</ol>
<pre><code class="lang-bash">npm install -D @swc/cli @swc/core
</code></pre>
<ol start="3">
<li><strong>Create a JavaScript file:</strong> Create a <code>src/index.js</code> file with some code:</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> greet = <span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">`Hello, <span class="hljs-subst">${name}</span>!`</span>;
};

<span class="hljs-built_in">console</span>.log(greet(<span class="hljs-string">"World"</span>));
</code></pre>
<ol start="4">
<li><strong>Compile with SWC:</strong> Run SWC from the command line to compile your JavaScript file:</li>
</ol>
<pre><code class="lang-bash">npx swc src/index.js -o dist/index.js
</code></pre>
<ol start="5">
<li><strong>Resulting Code:</strong> The resulting JavaScript code in <code>dist/index.js</code> will look like this:</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-meta">"use strict"</span>;
<span class="hljs-keyword">var</span> greet = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>;
};
<span class="hljs-built_in">console</span>.log(greet(<span class="hljs-string">"World"</span>));
</code></pre>
<p>This is the transpiled ES5 code produced by SWC, suitable for environments that require backward compatibility with older JavaScript versions.</p>
<h2 id="heading-swc-integration-in-popular-frameworks">SWC Integration in Popular Frameworks</h2>
<p>If you are using Next.js, Deno, Vite, Remix, Parcel, or Turbopack, SWC is already integrated.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287305286/e0a1e681-4531-402c-ae41-1f8c5f1318c8.png" alt="Logos of various web development frameworks and tools on a black background, which include: Deno, Vite, Next.js, Remix, Turbopack, and an open cardboard box." class="image--center mx-auto" width="896" height="498" loading="lazy"></p>
<blockquote>
<p>Notable improvements were made on Next.js, a popular React framework, since version 12 (Source: <a target="_blank" href="https://nextjs.org/blog/next-12">Next.js 12: The SDK for the Web</a>)</p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the constantly changing realm of JavaScript development, having the correct tools can make a significant difference.</p>
<p>SWC, the <a target="_blank" href="http://swc.rs">Speedy Web Compiler</a>, distinguishes itself as a strong solution for converting and optimizing JavaScript and TypeScript code.</p>
<p>Its impressive speed, owing to its Rust-based implementation, along with its efficient management of code transformations and optimizations, positions it as a powerful tool for modern web development.</p>
<p>If you would like to stay in touch:</p>
<p><a target="_blank" href="https://www.linkedin.com/in/preston-mayieka/">Connect with me on LinkedIn</a></p>
<p><a target="_blank" href="https://mobile.x.com/Preston_Mayieka">Follow me on X</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Blend Images in Rust Using Pixel Math ]]>
                </title>
                <description>
                    <![CDATA[ For anyone looking to learn about image processing as a programming niche, blending images is a very good place to start. It's one of the simplest yet most rewarding techniques when it comes to image processing. To help your intuition, it's best to i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-blend-images-in-rust-using-pixel-math/</link>
                <guid isPermaLink="false">66cda9b4e220ecb31e3a2239</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mathematics ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Anshul Sanghi ]]>
                </dc:creator>
                <pubDate>Tue, 27 Aug 2024 10:25:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724689572465/f03e4b74-1091-4673-af5b-c8827e74caf0.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For anyone looking to learn about image processing as a programming niche, blending images is a very good place to start. It's one of the simplest yet most rewarding techniques when it comes to image processing.</p>
<p>To help your intuition, it's best to imagine an image as a mathematical graph of pixel values plotted along the x and y coordinates. The top right pixel in an image is your origin, which corresponds to an x value of 0 and a y value of 0.</p>
<p>Once you imagine this, any pixel in an image can be read or modified using it's coordinate in this x-y graph. For example, for a square image of size 5px x 5px, the coordinate of the center pixel is 2, 2. You may have expected it to be 3, 3, but image coordinates in this context work similar to array indexes and start from 0 for both axis.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724421916445/8d27ec1d-43f5-4cc3-b706-b9bd2efb05a4.png" alt="mathematical graph with x and y axis" class="image--center mx-auto" width="2786" height="1435" loading="lazy"></p>
<p>Approaching image processing this way also helps you address each pixel individually, making the process much simpler.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>The focus of this article is for you to understand and learn how to blend images using the Rust programming language, without going into the details of the language or it's syntax. So being comfortable writing Rust programs is required.</p>
<p>If you're not familiar with Rust, I highly encourage you to learn the basics. <a target="_blank" href="https://www.freecodecamp.org/news/rust-in-replit/">Here's an interactive Rust course that can get you started.</a></p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-introduction">Introduction</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-image-blending-works">How Image Blending Works</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-project-setup">Project Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-read-pixel-values">How to Read Pixel Values</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-blend-functions">How to Blend Functions</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-average-blend">Average Blend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-multiply-blend">Multiply Blend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lighten-blend">Lighten Blend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-darken-blend">Darken Blend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-screen-blend">Screen Blend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-addition-blend">Addition Blend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-subtraction-blend">Subtraction Blend</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-apply-blend-functions-to-images">How to Apply Blend Functions To Images</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-putting-it-all-together">Putting It All Together</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-glossary">Glossary</a></p>
</li>
</ol>
<h2 id="heading-introduction">Introduction</h2>
<p>Image blending refers to the technique of merging pixels from multiple images to create a single output image that is derived from all of its inputs. Depending on which blending operation is used, the image output can vary widely given the same inputs.</p>
<p>This technique serves as the basis for many complex image processing tools, some of which you may already be familiar with. Things such as removing moving people from images if you have multiple images, merging images of the night sky to create star trails, and merging multiple noise-heavy images to create a noise reduced image are all examples of this technique at play.</p>
<p>To achieve the blending of images in this tutorial, we will make use of "pixel math", which while not being a truly standard term, refers to the technique of performing mathematical operations on a pixel or set of pixels to generate an output pixel.</p>
<p>For example, to blend two images using the "average" blend mode, you will perform the mathematical average operation on all input pixels at a given location, to generate the output at the same location.</p>
<p>Pixel math is not limited to point operations, which are basically operations performed during image processing that generate a given output pixel based on input pixel from single or multiple images from the same location in the x-y coordinate system.</p>
<p>In my experience so far, the entirety of image processing field is 99% mathematics and 1% black magic. Mathematical operations on pixels and it's surrounding pixels is the basis of image manipulation techniques such as compression, resizing, blurring and sharpening, noise reduction, and so on.</p>
<h2 id="heading-how-image-blending-works"><strong>How Image Blending Works</strong></h2>
<p>The technique is technically simple to implement. Let's take the example of a simple average blend. Here's how it works:</p>
<ol>
<li><p>Read the pixel data of both images into memory, usually into an array for each image.</p>
<ul>
<li>The array is usually 2 dimensional. Each entry in array is another array for color images, the secondary array holds the 3 pixel values corresponding to Red, Green, and Blue color channels.</li>
</ul>
</li>
<li><p>For each pixel location:</p>
<ol>
<li><p>For each channel:<br> a. Take the value of the channel from the 2nd image, let's consider it <code>y</code>.<br> b. Perform the averaging operation <code>x/2 + y/2</code>.<br> c. Save the output value of this operation as the value of the output channel</p>
</li>
<li><p>Save the result of previous operation as the value of the output pixel.</p>
</li>
</ol>
</li>
<li><p>Construct the output image with the same dimensions from the computed data.</p>
</li>
</ol>
<p>You'll notice that pixel math is performed on a per-channel basis. This is always true for the blend modes we cover in this tutorial, but many techniques involve applying blends between the channels themselves and many times within the same image.</p>
<h2 id="heading-project-setup"><strong>Project Setup</strong></h2>
<p>Let's get started by setting up a project that gives us a good baseline to work with.</p>
<pre><code class="lang-bash">cargo new --bin image-blender
<span class="hljs-built_in">cd</span> image-blender
</code></pre>
<p>You will also need a single dependency to help you perform these operations:</p>
<pre><code class="lang-bash">cargo add image
</code></pre>
<p><code>image</code> is a Rust library we'll use to work with images of all of the standard formats and encodings. It also helps us convert between various formats, and provides easy access to pixel data as buffers.</p>
<p>For more information on the <code>image</code> crate, you can refer to the <a target="_blank" href="https://docs.rs/image/">official documentation</a>.</p>
<p>To follow along, you can use any two images, the only requirement being that they should be of the same size and in the same format. You can also find the images used in this tutorial, along with complete code, <a target="_blank" href="https://github.com/anshulsanghi-blog/blend-images">in the GitHub repository here</a>.</p>
<h2 id="heading-how-to-read-pixel-values"><strong>How to Read Pixel Values</strong></h2>
<p>The first step is to load the images and read their pixel values into a data structure that facilitates our operation. For this tutorial, we're going to use a <code>Vec</code> of arrays (<code>Vec&lt;[u8; 3]&gt;</code>). Each entry in the outer <code>Vec</code> represents a pixel, and the channel-wise values of each pixel are stored in <code>[u8; 3]</code> array.</p>
<p>Let's start by creating a new file to hold this code called <strong>io.rs</strong>.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/io.rs</span>

<span class="hljs-keyword">use</span> image::GenericImageView;

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SourceData</span></span> {
    <span class="hljs-keyword">pub</span> width: <span class="hljs-built_in">usize</span>,
    <span class="hljs-keyword">pub</span> height: <span class="hljs-built_in">usize</span>,
    <span class="hljs-keyword">pub</span> image1: <span class="hljs-built_in">Vec</span>&lt;[<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]&gt;,
    <span class="hljs-keyword">pub</span> image2: <span class="hljs-built_in">Vec</span>&lt;[<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]&gt;,
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">read_pixel_data</span></span>(image1_path: <span class="hljs-built_in">String</span>, image2_path: <span class="hljs-built_in">String</span>) -&gt; SourceData {
    <span class="hljs-comment">// Open the images</span>
    <span class="hljs-keyword">let</span> image1 = image::open(image1_path).unwrap();
    <span class="hljs-keyword">let</span> image2 = image::open(image2_path).unwrap();

    <span class="hljs-comment">// Compute image dimensions</span>
    <span class="hljs-keyword">let</span> (width, height) = image1.dimensions();
    <span class="hljs-keyword">let</span> (width, height) = (width <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, height <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>);

    <span class="hljs-comment">// Create arrays to hold input pixel data</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> image1_data: <span class="hljs-built_in">Vec</span>&lt;[<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]&gt; = <span class="hljs-built_in">vec!</span>[[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]; width * height];
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> image2_data: <span class="hljs-built_in">Vec</span>&lt;[<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]&gt; = <span class="hljs-built_in">vec!</span>[[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]; width * height];

    <span class="hljs-comment">// Iterate over all pixels in the input image, along with their positions in x &amp; y</span>
    <span class="hljs-comment">// coordinates.</span>
    <span class="hljs-keyword">for</span> (x, y, pixel) <span class="hljs-keyword">in</span> image1.to_rgb8().enumerate_pixels() {
        <span class="hljs-comment">// Compute the raw values for each channel in the RGB pixel.</span>
        <span class="hljs-keyword">let</span> [r, g, b] = pixel.<span class="hljs-number">0</span>;

        <span class="hljs-comment">// Compute linear index based on 2D index. This is basically computing index in</span>
        <span class="hljs-comment">// 1D array based on the row and column index of the pixel in the 2D image.</span>
        <span class="hljs-keyword">let</span> index = (y * (width <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>) + x) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;

        <span class="hljs-comment">// Save the channel-wise values in the correct index in data arrays.</span>
        image1_data[index] = [r, g, b];
    }

    <span class="hljs-comment">// Iterate over all pixels in the input image, along with their positions in x &amp; y</span>
    <span class="hljs-comment">// coordinates.</span>
    <span class="hljs-keyword">for</span> (x, y, pixel) <span class="hljs-keyword">in</span> image2.to_rgb8().enumerate_pixels() {
        <span class="hljs-comment">// Compute the raw values for each channel in the RGB pixel.</span>
        <span class="hljs-keyword">let</span> [r, g, b] = pixel.<span class="hljs-number">0</span>;

        <span class="hljs-comment">// Compute linear index based on 2D index. This is basically computing index in</span>
        <span class="hljs-comment">// 1D array based on the row and column index of the pixel in the 2D image.</span>
        <span class="hljs-keyword">let</span> index = (y * (width <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>) + x) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;

        <span class="hljs-comment">// Save the channel-wise values in the correct index in data arrays.</span>
        image2_data[index] = [r, g, b];
    }

    SourceData {
        width,
        height,
        image1: image1_data,
        image2: image2_data,
    }
}
</code></pre>
<h2 id="heading-how-to-blend-functions">How to Blend Functions</h2>
<p>The next step is to implement the blending functions, which are pure functions that take two pixel values as input and return the output value. This is implemented through the <code>BlendOperation</code> trait defined below. Let's create a new file to host all the operations called <strong>operations.rs</strong>.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">BlendOperation</span></span> {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>];
}
</code></pre>
<p>Next, we need to implement this trait for all of the blending methods we want to support.</p>
<p>For showcasing the result of each of the blending modes, the following two input images are blended together</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236939605/77d32c76-abf6-4d24-bba7-df40729863b8.jpeg" alt="Source image 1: Fireflies in a dark forest area" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724428339241/3cc70fd2-f6da-4704-8606-97c094a2ff35.jpeg" alt="Source image 2: Fireflies in a bright forest area" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h3 id="heading-average-blend">Average Blend</h3>
<p>An average blend involves channel-wise averaging the input pixel values to get the output pixel.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AverageBlend</span></span>;

<span class="hljs-keyword">impl</span> BlendOperation <span class="hljs-keyword">for</span> AverageBlend {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>] {
        [
            pixel1[<span class="hljs-number">0</span>] / <span class="hljs-number">2</span> + pixel2[<span class="hljs-number">0</span>] / <span class="hljs-number">2</span>,
            pixel1[<span class="hljs-number">1</span>] / <span class="hljs-number">2</span> + pixel2[<span class="hljs-number">1</span>] / <span class="hljs-number">2</span>,
            pixel1[<span class="hljs-number">2</span>] / <span class="hljs-number">2</span> + pixel2[<span class="hljs-number">2</span>] / <span class="hljs-number">2</span>,
        ]
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236691772/291f14f4-2019-4771-8cd2-b9f9b3cf3f86.jpeg" alt="Result of average blending source images" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h3 id="heading-multiply-blend">Multiply Blend</h3>
<p>A multiply blend involves channel-wise multiplication of input pixel values after they've been normalized<a class="post-section-overview" href="#heading-glossary">[¹]</a> to get the output pixel. The output pixel is then rescaled back to the original range by multiplying with 255.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MultiplyBlend</span></span>;

<span class="hljs-keyword">impl</span> BlendOperation <span class="hljs-keyword">for</span> MultiplyBlend {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>] {
        [
            ((pixel1[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>. * pixel2[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.) * <span class="hljs-number">255</span>.) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            ((pixel1[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>. * pixel2[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.) * <span class="hljs-number">255</span>.) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            ((pixel1[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>. * pixel2[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.) * <span class="hljs-number">255</span>.) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
        ]
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236703622/9aff3ffd-9a63-4b76-9675-d7db4ccee89b.jpeg" alt="Result of multiply blending source images" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h3 id="heading-lighten-blend">Lighten Blend</h3>
<p>Lighten blend involves channel-wise comparison of input pixel values, selecting the pixel with higher value (intensity) as the output pixel.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">LightenBlend</span></span>;

<span class="hljs-keyword">impl</span> BlendOperation <span class="hljs-keyword">for</span> LightenBlend {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>] {
        [
            pixel1[<span class="hljs-number">0</span>].max(pixel2[<span class="hljs-number">0</span>]),
            pixel1[<span class="hljs-number">1</span>].max(pixel2[<span class="hljs-number">1</span>]),
            pixel1[<span class="hljs-number">2</span>].max(pixel2[<span class="hljs-number">2</span>]),
        ]
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236726111/5d1607fb-2740-46b8-906d-1ffb482a0561.jpeg" alt="Result of lighten blending source images" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h3 id="heading-darken-blend">Darken Blend</h3>
<p>Darken blend is the opposite operation of lighten blend. It involves channel-wise comparison of input pixel values, selecting the pixel with least value (intensity) as the output pixel.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">DarkenBlend</span></span>;

<span class="hljs-keyword">impl</span> BlendOperation <span class="hljs-keyword">for</span> DarkenBlend {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>] {
        [
            pixel1[<span class="hljs-number">0</span>].min(pixel2[<span class="hljs-number">0</span>]),
            pixel1[<span class="hljs-number">1</span>].min(pixel2[<span class="hljs-number">1</span>]),
            pixel1[<span class="hljs-number">2</span>].min(pixel2[<span class="hljs-number">2</span>]),
        ]
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236746972/18307fa1-1a77-4d39-b233-a7a6d87233d0.jpeg" alt="Result of darken blending source images" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h3 id="heading-screen-blend">Screen Blend</h3>
<p>Screen blend refers to multiplying the inverse of two images, and then inverting the result. In our implementation, the pixels first need to be normalized<a class="post-section-overview" href="#heading-glossary">[¹]</a>. The normalized<a class="post-section-overview" href="#heading-glossary">[¹]</a> values are then inverted by subtracting them from 1, then they're multiplied and inverted again.</p>
<p>Finally, the output is multiplied by 255 to de-normalize the output pixel value.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ScreenBlend</span></span>;

<span class="hljs-keyword">impl</span> BlendOperation <span class="hljs-keyword">for</span> ScreenBlend {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>] {
        [
            ((<span class="hljs-number">1</span>. - ((<span class="hljs-number">1</span>. - (pixel1[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.)) * (<span class="hljs-number">1</span>. - (pixel2[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.)))) * <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            ((<span class="hljs-number">1</span>. - ((<span class="hljs-number">1</span>. - (pixel1[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.)) * (<span class="hljs-number">1</span>. - (pixel2[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.)))) * <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            ((<span class="hljs-number">1</span>. - ((<span class="hljs-number">1</span>. - (pixel1[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.)) * (<span class="hljs-number">1</span>. - (pixel2[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-number">255</span>.)))) * <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
        ]
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236758380/fd531b6e-729c-4db4-987e-f503478ff950.jpeg" alt="Result of screen blending source images" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h3 id="heading-addition-blend">Addition Blend</h3>
<p>Addition blend involves adding the input values and then clamping the result to the maximum range of the color depth we're targeting. In this case, that would be 0-255 as we're targeting 8-bit color depth.</p>
<p>We also have to convert the values to u16 in order to avoid loss of value due to overflow. We can also use normalized<a class="post-section-overview" href="#heading-glossary">[¹]</a> values here to achieve the same result.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AdditionBlend</span></span>;

<span class="hljs-keyword">impl</span> BlendOperation <span class="hljs-keyword">for</span> AdditionBlend {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>] {
        [
            (pixel1[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span> + pixel2[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>).clamp(<span class="hljs-number">0</span>, <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            (pixel1[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span> + pixel2[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>).clamp(<span class="hljs-number">0</span>, <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            (pixel1[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span> + pixel2[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>).clamp(<span class="hljs-number">0</span>, <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
        ]
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236766684/05f01177-024d-4196-a9fa-5274bb56a0f4.jpeg" alt="Result of addition blending source images" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h3 id="heading-subtraction-blend">Subtraction Blend</h3>
<p>Addition blend involves subtracting the input values and then clamping the result to the maximum range of the color depth we're targeting. In this case, that would be 0-255 as we're targeting 8-bit color depth.</p>
<p>We also convert the values to i16 in order to avoid loss of value due to overflow and lack of sign. We can also use normalized<a class="post-section-overview" href="#heading-glossary">[¹]</a> values here to achieve the same result.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/operations.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SubtractionBlend</span></span>;

<span class="hljs-keyword">impl</span> BlendOperation <span class="hljs-keyword">for</span> SubtractionBlend {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">perform_operation</span></span>(&amp;<span class="hljs-keyword">self</span>, pixel1: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>], pixel2: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>]) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">3</span>] {
        [
            (pixel1[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span> - pixel2[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>).clamp(<span class="hljs-number">0</span>, <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            (pixel1[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span> - pixel2[<span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>).clamp(<span class="hljs-number">0</span>, <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
            (pixel1[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span> - pixel2[<span class="hljs-number">2</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>).clamp(<span class="hljs-number">0</span>, <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>,
        ]
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724236775603/507ba176-579d-494f-bb56-25a27ed2317f.jpeg" alt="Result of subtraction blending source images" class="image--center mx-auto" width="3000" height="1996" loading="lazy"></p>
<h2 id="heading-how-to-apply-blend-functions-to-images">How to Apply Blend Functions To Images</h2>
<p>The final step is to actually use the blending operations we created previously and apply them to pairs of images.</p>
<p>To achieve this, we need a function that can take the <code>SourceData</code> type we defined previously as input, along with a blending operation as the arguments, and gives us the final output buffer. Let's start by creating a new file for it called <strong>blend.rs</strong>.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/blend.rs</span>

<span class="hljs-keyword">use</span> image::{ImageBuffer, Rgb};
<span class="hljs-keyword">use</span> crate::{operations::BlendOperation, SourceData};

<span class="hljs-keyword">impl</span> SourceData {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">blend_images</span></span>(&amp;<span class="hljs-keyword">self</span>, operation: <span class="hljs-keyword">impl</span> BlendOperation)  -&gt; ImageBuffer&lt;Rgb&lt;<span class="hljs-built_in">u8</span>&gt;, <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;&gt; {
        <span class="hljs-keyword">let</span> SourceData {
            width,
            height,
            image1,
            image2,
        } = <span class="hljs-keyword">self</span>;

        <span class="hljs-comment">// Create a new buffer that has the same size as input images, which will serve as our output data</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = ImageBuffer::new(*width <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>, *height <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>);

        <span class="hljs-comment">// Iterate over all pixels in the output buffer, along with their coordinates</span>
        <span class="hljs-keyword">for</span> (x, y, output_pixel) <span class="hljs-keyword">in</span> buffer.enumerate_pixels_mut() {
            <span class="hljs-comment">// Compute linear index form x &amp; y coordinates. In other words, you have the</span>
            <span class="hljs-comment">// row and column indexes here, and you want to compute the array index based</span>
            <span class="hljs-comment">// on these two positions.</span>
            <span class="hljs-keyword">let</span> index = (y * *width <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span> + x) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;

            <span class="hljs-comment">// Store pixel values in the given position into variables</span>
            <span class="hljs-keyword">let</span> pixel1 = image1[index];
            <span class="hljs-keyword">let</span> pixel2 = image2[index];

            <span class="hljs-comment">// Compute the blended pixel and convert it into the `Rgb` type, which is then</span>
            <span class="hljs-comment">// assigned to the output pixel in the buffer.</span>
            *output_pixel = Rgb::from(operation.perform_operation(pixel1, pixel2));
        }

        buffer
    }
}
</code></pre>
<h3 id="heading-putting-it-all-together">Putting It All Together</h3>
<p>It's now time to make use of all the new things you've learnt so far, and put them together in <strong>main.rs</strong> file.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/main.rs</span>

<span class="hljs-keyword">mod</span> blend;
<span class="hljs-keyword">mod</span> io;
<span class="hljs-keyword">mod</span> operations;

<span class="hljs-keyword">use</span> io::*;
<span class="hljs-keyword">use</span> operations::{
    AdditionBlend, AverageBlend, DarkenBlend, LightenBlend, MultiplyBlend, ScreenBlend,
    SubtractionBlend,
};

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> source_data = read_pixel_data(<span class="hljs-string">"image1.jpg"</span>.to_string(), <span class="hljs-string">"image2.jpg"</span>.to_string());

    <span class="hljs-keyword">let</span> output_buffer = source_data.blend_images(AdditionBlend);
    output_buffer.save(<span class="hljs-string">"addition.jpg"</span>).unwrap();

    <span class="hljs-keyword">let</span> output_buffer = source_data.blend_images(AverageBlend);
    output_buffer.save(<span class="hljs-string">"average.jpg"</span>).unwrap();

    <span class="hljs-keyword">let</span> output_buffer = source_data.blend_images(DarkenBlend);
    output_buffer.save(<span class="hljs-string">"darken.jpg"</span>).unwrap();

    <span class="hljs-keyword">let</span> output_buffer = source_data.blend_images(LightenBlend);
    output_buffer.save(<span class="hljs-string">"lighten.jpg"</span>).unwrap();

    <span class="hljs-keyword">let</span> output_buffer = source_data.blend_images(MultiplyBlend);
    output_buffer.save(<span class="hljs-string">"multiply.jpg"</span>).unwrap();

    <span class="hljs-keyword">let</span> output_buffer = source_data.blend_images(ScreenBlend);
    output_buffer.save(<span class="hljs-string">"screen.jpg"</span>).unwrap();

    <span class="hljs-keyword">let</span> output_buffer = source_data.blend_images(SubtractionBlend);
    output_buffer.save(<span class="hljs-string">"subtraction.jpg"</span>).unwrap();
}
</code></pre>
<p>You can now run the program using the following command, and you should have all the images generated and saved in the project folder:</p>
<pre><code class="lang-bash">cargo run --release
</code></pre>
<p>As you might have guessed already, this implementation only works for 8-bit RGB images. This code, however, can be extended very easily to support the other color formats such as 8-bit Luma (Monochrome), 16-bit RGB (Many RAW camera images), and so on.</p>
<p>I highly encourage you to try that out. You can also reach out to me for help with anything in this tutorial or with extending the code in this tutorial. I'd be happy to answer all your queries. Email is the best way to reach me, you can email me at <a target="_blank" href="mailto:anshul@anshulsanghi.tech">anshul@anshulsanghi.tech</a>.</p>
<h3 id="heading-glossary">Glossary</h3>
<p>Normalization refers to the process of rescaling the pixel values so that the values are in floating point format and are in the range of 0-1. For example, for an 8 bit image, the color black is represented by 0 (0 in de-normalized value) and the color white is represented by 1 (255 in de-normalized value). Intermediary decimal values between 0 &amp; 1 represent different intensities of the pixel between black and white. Normalization is done for many different reasons such as:</p>
<ul>
<li><p>Preventing overflows during calculations.</p>
</li>
<li><p>Re-scaling images to the same range irrespective of their individual color depth.</p>
</li>
<li><p>Expanding possible dynamic range of the image.</p>
</li>
</ul>
<h3 id="heading-enjoying-my-work"><strong>Enjoying my work?</strong></h3>
<p>Consider buying me a coffee to support my work!</p>
<p><a target="_blank" href="https://www.buymeacoffee.com/anshulsanghi"><img src="https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20coffee&amp;emoji=%E2%98%95&amp;slug=anshulsanghi&amp;button_colour=FFDD00&amp;font_colour=000000&amp;font_family=Cookie&amp;outline_colour=000000&amp;coffee_colour=ffffff" alt="?text=Buy%20me%20a%20coffee&amp;emoji=%E2%98%95&amp;slug=anshulsanghi&amp;button_colour=FFDD00&amp;font_colour=000000&amp;font_family=Cookie&amp;outline_colour=000000&amp;coffee_colour=ffffff" width="235" height="50" loading="lazy"></a></p>
<p>Till next time, happy coding and wishing you clear skies!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Asynchronous Programming Works in Rust – Futures and Async/Await Explained with Examples ]]>
                </title>
                <description>
                    <![CDATA[ If you're familiar with languages like JavaScript and Python, you may have heard about asynchronous programming. And perhaps you're wondering how it works in Rust. In this article, I'll give you a simple overview of how asynchronous programming works... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-asynchronous-programming-works-in-rust/</link>
                <guid isPermaLink="false">66be1c3ab712ab343b0b9150</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ async/await ]]>
                    </category>
                
                    <category>
                        <![CDATA[ asynchronous ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oduah Chigozie ]]>
                </dc:creator>
                <pubDate>Thu, 15 Aug 2024 15:18:18 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723746256888/b046d857-161c-41be-96d0-1c05b1e448b8.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're familiar with languages like JavaScript and Python, you may have heard about asynchronous programming. And perhaps you're wondering how it works in Rust.</p>
<p>In this article, I'll give you a simple overview of how asynchronous programming works in Rust. You'll learn about futures as well as <code>async</code>/<code>.await</code>.</p>
<p>This article isn't a beginner's guide to Rust or asynchronous programming, so you'll need to have some experience with programming in Rust and familiarity with asynchronous programming to get the most out of this guide.</p>
<p>With that said, let's begin!</p>
<h2 id="heading-when-should-you-use-asynchronous-programming">When Should You Use Asynchronous Programming?</h2>
<p>Asynchronous tasks work like a more integrated version of threads. You can use them in a lot of the same scenarios where you can use multiple threads. The benefits async programming provides over multiple threads is that multi-threaded applications have a larger overhead to work on multiple tasks compared to asynchronous applications.</p>
<p>But this doesn’t make asynchronous applications better than multithreaded applications. Multi-threaded programs can run multiple computing-intensive tasks simultaneously – and multiple times faster than if you ran all the tasks in a single thread.</p>
<p>With asynchronous coding, trying to run multiple computing-intensive applications simultaneously will be much slower than just running every task on a single thread.</p>
<p>Asynchronous programming is very good for building applications that make many network requests or many IO operations like file reading and writing.</p>
<p>I can’t cover every case when you’ll want to use asynchronous techniques. But I can say that it’s most beneficial for tasks that have a lot of idle time (for example, waiting for a server to respond to a network request).</p>
<p>During the idle time of an asynchronous task, instead of blocking the thread, the event handler works on other tasks in the program until the asynchronous task is ready to make progress.</p>
<h2 id="heading-overview-of-asynchronous-rust-futures">Overview of Asynchronous Rust – Futures</h2>
<p>The basics of asynchronous Rust are Futures. Futures are similar to promises in JavaScript. They are Rust's way of saying "hey, I'm going to give you the result later, but just hold on to this (the future instance) to keep track of if the result is ready."</p>
<p>Futures are traits, with a <code>poll</code> state that is either <code>Poll::Pending</code> to signify that the future is in the process of executing its task, or <code>Poll::Ready</code> to signify that the future is done with its task.</p>
<p>Futures are lazy. They run when you <code>.await</code> them (we'll look into how to <code>.await</code> them in the next section). <code>.await</code>ing a future pauses the execution of an asynchronous thread, and begins running its task. At this point the result of the <code>poll</code> method is <code>Poll::Pending</code>. When the future is done with its task, <code>poll</code>'s state will become <code>Poll::Ready</code>, and the future will allow it's thread to proceed.</p>
<p>If you want to get more into the technical details about Futures, you can check out <a target="_blank" href="https://rust-lang.github.io/async-book/02_execution/01_chapter.html">the documentation</a>.</p>
<h2 id="heading-asyncawait-in-rust">async/.await in Rust</h2>
<p><code>async</code> and <code>.await</code> are the primary ways you'll be working with asynchronous code in Rust. <code>async</code> is a keyword for declaring asynchronous functions. Within those functions, the <code>.await</code> keyword pauses its execution until the result of the future is ready.</p>
<p>Let's take a look at an example:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">add</span></span>(a: <span class="hljs-built_in">u8</span>, b: <span class="hljs-built_in">u8</span>) -&gt; <span class="hljs-built_in">u8</span> {
    a + b
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">secondFunc</span></span>() -&gt; <span class="hljs-built_in">u8</span> {
    <span class="hljs-keyword">let</span> a = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">let</span> b = <span class="hljs-number">20</span>;
    <span class="hljs-keyword">let</span> result = add(a, b).<span class="hljs-keyword">await</span>;
    <span class="hljs-keyword">return</span> result;
}
</code></pre>
<p>Any asynchronous function declared with <code>async fn</code> wraps its return value in a future. On the third line of <code>secondFunc</code>, we <code>.await</code> the future from <code>add(a, b)</code> to get its result before proceeding to return it.</p>
<h2 id="heading-how-to-work-with-asynchronous-operations-in-main">How to Work with Asynchronous Operations in <code>main</code></h2>
<p>Rust doesn’t allow you to <code>async fn</code> main functions. Running asynchronous operations from a non-asynchronous function may lead to some operations not fully concluding before the main thread is exited.</p>
<p>In this section, we’ll look at two ways solve this issue. The two ways to do this are with <code>futures</code> and <code>tokio</code>. Let's look at both.</p>
<h3 id="heading-tokio"><code>tokio</code></h3>
<p><code>tokio</code> is a platform that provides tools and APIs for performing asynchronous applications. <code>tokio</code> also allows you to easily declare an asynchronous main function, which will help with the issue I described earlier.</p>
<p>To install <code>tokio</code> in your project, add this line to its <code>Cargo.toml</code>:</p>
<pre><code class="lang-ini"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">tokio</span> = { version = <span class="hljs-string">"1"</span>, features = [<span class="hljs-string">"full"</span>] }
</code></pre>
<p>After adding the line, you can write your <code>main</code> functions like this:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">add</span></span>(a: <span class="hljs-built_in">u8</span>, b: <span class="hljs-built_in">u8</span>) -&gt; <span class="hljs-built_in">u8</span> {
    a + b
}

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> a = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">let</span> b = <span class="hljs-number">20</span>;
    <span class="hljs-keyword">let</span> result = add(a, b).<span class="hljs-keyword">await</span>;
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{result}"</span>);
}
</code></pre>
<h3 id="heading-the-futures-library">The <code>futures</code> library</h3>
<p><code>futures</code> is a library that provides methods for working with asynchronous Rust. For our use case, <code>futures</code> provides <code>futures::executor::block_on()</code>. This method works similar to <code>.await</code> in asynchronous functions. It blocks the main thread, until the result of future is ready. <code>futures::executor::block_on()</code> also returns the result of the completed future.</p>
<p>To install <code>futures</code> in your project, add this line to its <code>Cargo.toml</code>:</p>
<pre><code class="lang-ini"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">futures</span> = <span class="hljs-string">"0.3"</span>
</code></pre>
<p>After installing the library, you can do something like this:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> futures::executor::block_on;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">add</span></span>(a: <span class="hljs-built_in">u8</span>, b: <span class="hljs-built_in">u8</span>) -&gt; <span class="hljs-built_in">u8</span> {
    a + b
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> a = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">let</span> b = <span class="hljs-number">20</span>;
    <span class="hljs-keyword">let</span> result = block_on(add(a, b));
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{result}"</span>); 
}
</code></pre>
<p>First, we import the <code>block_on</code> method on the first line and use the method to block the main thread until the result of the <code>add(a, b)</code> function was ready. We also didn’t have to make the <code>main</code> function asynchronous like we did with <code>tokio</code>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Asynchronous programming allows you to run operations in parallel and with less overhead and complexity compared to traditional multi-threading. In Rust, it allows you to build I/O and network applications more efficiently.</p>
<p>While this article should help you become familiar with the basics asynchronous programming in Rust, it’s still just an overview. There are some cases where you'll need to use other constructs in Rust like Pinning, Arcs, and so on.</p>
<p>If you have any questions or thoughts, feel free to reach out to me. Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build and Deploy a Smart Contract With Rust and the Gear Protocol ]]>
                </title>
                <description>
                    <![CDATA[ Smart contracts are like digital agreements that run on blockchain technology, making transactions automatic and secure. While many people use Ethereum and Solidity to create these contracts, there are other options that can be just as powerful.  One... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-and-deploy-smart-contract-rust-gear-protocol/</link>
                <guid isPermaLink="false">66bb89c32108ff2ab9af1673</guid>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rocky Essel ]]>
                </dc:creator>
                <pubDate>Tue, 04 Jun 2024 10:36:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/How-to-Build-and-Deploy-a-Smart-Contract-With-Rust-and-the-Gear-Protocol-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Smart contracts are like digital agreements that run on blockchain technology, making transactions automatic and secure. While many people use Ethereum and Solidity to create these contracts, there are other options that can be just as powerful. </p>
<p>One great combination is using Rust with the Gear Protocol. In this guide, I'll show you how to build and deploy a smart contract using Rust and the Gear Protocol. Whether you're new to this or have some experience, this article will help you get started with clear and easy-to-follow steps.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ol>
<li>Have basic Rust knowledge.</li>
<li>Having a basic understanding of decentralization. </li>
</ol>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-introduction-to-vara-network-amp-gear-protocol">Introduction to Vara Network &amp; Gear Protocol.</a></li>
<li><a class="post-section-overview" href="#heading-why-use-the-web2-analogy">Why Use the Web2 Analogy</a>? </li>
<li><a class="post-section-overview" href="#heading-message-based-communication">Message-based Communication</a>.</li>
<li><a class="post-section-overview" href="#heading-illustration">Illustration</a></li>
<li><a class="post-section-overview" href="#heading-vara-networks-role">Vara Network's Role</a>.</li>
<li><a class="post-section-overview" href="#heading-first-project-reading-a-joke">First Project – Reading a Joke</a></li>
<li><a class="post-section-overview" href="#heading-next-project-input-msg">Next Project – <code>input-msg</code></a></li>
<li><a class="post-section-overview" href="#heading-metadata-amp-state">Metadata &amp; State</a></li>
<li><a class="post-section-overview" href="#heading-third-project-building-messages">Third Project – Building Messages</a></li>
<li><a class="post-section-overview" href="#heading-final-project">Final Project – Battle Showdown</a></li>
<li><a class="post-section-overview" href="#conclusion-1">Conclusion.</a></li>
</ol>
<h2 id="heading-introduction-to-vara-network-amp-gear-protocol">Introduction to Vara Network &amp; Gear Protocol.</h2>
<h3 id="heading-vara-network">Vara Network</h3>
<p>Think of Vara as the sturdy foundation of blockchain technology. It's a layer-1 blockchain, meaning that it's at the core of transactions, ensuring that they are secure and decentralized. Vara uses Nominated Proof-of-Stake (NPoS) for agreement, making it reliable and efficient.</p>
<p>Furthermore, Vara Network distinguishes itself through its novel Actor Model, an architecture characterized by isolation and asynchronous messaging. This paradigm shift in smart contract execution imbues Vara Network with unparalleled security and scalability, setting it apart from conventional blockchain platforms.</p>
<h3 id="heading-gear-protocol">Gear Protocol</h3>
<p>Gear Protocol is like a toolbox for developers. It's a smart contract engine that makes building decentralized apps (dApps) faster, safer, and cheaper. By using substrate technology and WebAssembly (Wasm), Gear makes it easy for developers to create dApps that run smoothly and securely.</p>
<p>Gear's utilization of the Wasm virtual machine serves as a cornerstone of its efficiency. By harnessing the power of Wasm, developers can transcend language barriers, seamlessly integrating existing codebases and accelerating the development lifecycle. This fusion of familiarity and performance paves the way for a new era of dApp creation, where speed, security, and scalability converge harmoniously.</p>
<p>In simpler terms, Vara Network and Gear Protocol work together to make blockchain technology more user-friendly and secure for building and using decentralized apps.</p>
<h2 id="heading-why-use-the-web2-analogy">Why Use the Web2 Analogy?</h2>
<p>Understanding message-based communication, particularly within the context of Gear Protocol, can be quite challenging. To gain a clearer understanding, I delved into the documentation and conducted additional research. Eventually, I stumbled upon an analogy that made it all click: the analogy of web HTTP requests, specifically the POST method.</p>
<p>Let's dissect this analogy step by step. Consider the familiar scenario of a user visiting a website like google.com and interacting with the search bar. When the user enters a search query and hits enter, what's happening behind the scenes is akin to a POST HTTP request being sent.</p>
<h3 id="heading-heres-how-it-unfolds">Here's how it unfolds:</h3>
<ol>
<li><strong>User Interaction:</strong> The user initiates the action by typing a search query into the search bar and hitting enter. This action triggers a request for information.</li>
<li><strong>Client Acknowledgment:</strong> Google's website, acting as the client-side user interface (UI), acknowledges the user's input and prepares to send a request to the server for processing.</li>
<li><strong>Request Sent:</strong> Just like when you hit enter after typing a query, Google's website sends a POST request to its server, conveying the user's search query.</li>
<li><strong>Server Processing:</strong> Upon receiving the POST request, Google's server processes the query, searching its vast index for relevant information.</li>
<li><strong>Response Generation:</strong> After processing the query, Google's server generates a response containing the search results.</li>
<li><strong>Response Sent:</strong> Finally, Google's server sends the response back to the client (the user's web browser), completing the communication cycle.</li>
</ol>
<p>In this analogy, the user represents the initiator of the communication, the client (UI) serves as the intermediary between the user and the server, and the server acts as the responder, processing requests and generating responses.</p>
<p>By drawing parallels between message-based communication in Gear Protocol and the familiar concept of web HTTP requests, we can better grasp the dynamics at play. Just as understanding how web requests facilitate communication between users and servers is essential for navigating the internet, comprehending message-based communication in Gear Protocol is crucial for building and interacting with decentralized applications effectively.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-114.png" alt="Image" width="600" height="400" loading="lazy">
<em>how the POST method works</em></p>
<h2 id="heading-message-based-communication">Message-based Communication</h2>
<p>Similarly, the Gear Protocol operates based on user or program interactions.<br><strong>Note</strong>: Programs on Gear can also interact with each other.<br>So here is a detailed explanation to the whole communication flow in Gear.</p>
<h3 id="heading-user-interaction-and-gear-jsapi">User Interaction and @gear-js/api</h3>
<p>When a user (actor) interacts with the dApp's UI elements (like buttons or forms), <code>_@gear-js/api_</code> (which is integrated into the UI) captures these interactions. Based on the interactions, it extracts information and potentially pre-defined message formats, and then contracts a message object containing the user's intent or request.</p>
<h3 id="heading-how-to-send-messages">How to Send Messages</h3>
<p>The constructed message object encapsulates the user's input and becomes the data <code>@gear-js/api</code> transmits across the Vara Network to the Gear crate within the program.</p>
<h3 id="heading-how-the-program-receives-and-processes-messages">How the Program Receives and Processes Messages</h3>
<p>Gear (<code>crate</code>) delivers the message object to the appropriate program deployed on the Vara Network based on the location the user initiated the action. The Gear crate within the program utilizes functions like <code>msg::load()</code> and access the delivered message object, which the program extracts information (such as <code>payload</code>, <code>source</code>, <code>messsageId</code>) from, and process it according to how it's designed by the developer.</p>
<h3 id="heading-how-to-generate-a-reply">How to Generate a Reply</h3>
<p>Based on the processed input, the program creates a new message object containing a reply (<code>response</code> in <code>web2</code>) to the user's action or interaction (called <code>reply</code>) to or for the user. </p>
<p>Note, the program typically doesn't send the original message object back, it generates a new one based message received, which a reply is sent back to be received by <code>@gear-js/api</code> using the <code>gstd</code> crate from the program utilizing functions like the <code>msg::reply</code> or <code>msg::reply_bytes</code>.</p>
<h3 id="heading-ui-update">UI Update</h3>
<p><code>@gear-js/api</code>, within the dApp, receives the reply message object delivered by the <code>gstd</code> crate from the program across the Vara Network and extracts the response data from the reply object, and finally updates the UI reflecting the program's response to the user's interaction.  </p>
<p>And that's pretty much the communication between the Users, Client(dApp), Gear Protocol(<code>gstd</code>), and finally Vara Network.</p>
<h2 id="heading-illustration">Illustration</h2>
<p>Let's discuss more about the diagrams below, and how they each interact with each other.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/image-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>UI Update</em></p>
<p>This illustration above is just a bird's eye view of how communication flows from the user to the program<strong>.</strong> I'll provide a complete illustration for more clarity. But before that, let's break the overview illustration into three stages.</p>
<h3 id="heading-initial-interaction-stage">Initial Interaction Stage</h3>
<p>As said earlier, this is when the user interacts with the program, both <code>@gear-js/api</code> and <code>gstd</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-124.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial Interaction Stage</em></p>
<h3 id="heading-businessprogram-logic">Business/Program Logic</h3>
<p>This section depicts the communication between the program and Gear within Vara Network. The <code>gstd</code> is used by the program to access the transmitted message (<code>msg::load()</code>) from the initial stage to perform business logic.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-126.png" alt="Image" width="600" height="400" loading="lazy">
<em>Business/Program Logic</em></p>
<h3 id="heading-reply-response">Reply (Response)</h3>
<p>This final stage shows how user feedback is delivered to the user or program. <code>@gear-js/api</code> translates it if necessary, and then updates the dApp's UI with the results. This allows the user to see the outcome of their action within the dApp.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-127.png" alt="Image" width="600" height="400" loading="lazy">
<em>Reply(Response)</em></p>
<p>That's great, right? This should help you understand how messages are passed from the client to the program. But what does Vara Network role mean here? Earlier I said that, the message object get transmitted across the Vara Network, but I didn't say how. Let's explain that.</p>
<h2 id="heading-vara-networks-role">Vara Network's Role</h2>
<p>In Vara, all participants, including user interfaces (through <code>@gear-js/api</code>) and smart contracts (programs &amp; <code>gstd</code>), are considered as actors. Another point to know is that, actors don't directly call functions within other actors (as in, programs interacting with other programs or even users). </p>
<p>Instead, they send messages containing data or instructions. So in our explanation of the message-based communication, Vara serves as the underlying decentralized network infrastructure for communication of our system (dApps). It provides a secure and reliable platform for message transmission across distributed network of nodes. And since Vara utilize a consensus mechanism NPoS (Nominated Proof-of-Stake), it ensures network security and transaction validation.</p>
<h2 id="heading-getting-our-hands-dirty">Getting Our Hands Dirty</h2>
<p>In order to build upon the above information I provided, you and I need to get our hands dirty by building and deploying programs with additional explanation for a clearer understanding. </p>
<p>Let's get started.</p>
<h3 id="heading-first-project-reading-a-joke">First Project - Reading a Joke</h3>
<p>In this project, you're going to interact with and deploy your smart contract on Vara Network, and receive a reply message back.</p>
<p>This is just a simple project, and nothing too complex. I chose this example project because it aligns with the analogy I gave earlier.</p>
<p>Currently, this project should be fine when running it on your Windows system. In case you get an error, scroll to the part of this article with a guide for setting up a Windows Subsystem for Linux (WSL), since it would allow you to run a Linux environment, including command-line tools and applications, directly on Windows, without the overhead of a traditional virtual machine or dual boot setup.</p>
<p>To get started, create a directory named <code>freecodecamp-gear-protocol</code>. Since you'll be building about fours projects, and I think it is important on how you can setup your projects for Gear Protocol.</p>
<p>So in your <code>freecodecamp-gear-protocol</code> directory, create a <code>Cargo.toml</code> file with the following code:</p>
<pre><code class="lang-toml"><span class="hljs-section">[workspace]</span>
<span class="hljs-attr">resolver</span> = <span class="hljs-string">"2"</span>
<span class="hljs-attr">members</span> = []


<span class="hljs-section">[workspace.package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"freecodecamp-gear-protocol"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>
<span class="hljs-attr">authors</span> = [<span class="hljs-string">"Rocky Essel"</span>]
<span class="hljs-attr">license</span> = <span class="hljs-string">"MIT"</span>
<span class="hljs-attr">publish</span> = <span class="hljs-literal">false</span>

<span class="hljs-section">[workspace.dependencies]</span>
<span class="hljs-comment"># Internal Crates</span>
<span class="hljs-comment"># External Crates</span>
</code></pre>
<p>For someone new to Rust or used to creating single projects, I'll guide you through understanding and setting up a workspace in Rust, making it easy to grasp.</p>
<h3 id="heading-understanding-your-workspace">Understanding Your Workspace</h3>
<p>A workspace in Rust is a set of packages (crates) that are managed together. Let's break down the key sections: <code>[workspace]</code>, <code>members</code>, <code>[workspace.package]</code>, and <code>[workspace.dependencies]</code>. So think of this like a cabin for your shoes, where each pair of shoes is a crate (package) that you want to keep organized.</p>
<h4 id="heading-workspace-section"><code>[workspace]</code> Section</h4>
<p>The <code>[workspace]</code> section defines the overall workspace. It typically contains multiple members.</p>
<p><strong><code>resolver = "2"</code></strong>: Specifies the version of Cargo's feature resolver to use, improving how dependencies are managed across the workspace.</p>
<p><strong><code>members</code></strong>: Lists the crates that are part of the workspace. When you add a project with <code>cargo new --lib sneakers</code> or <code>boots</code>, the <code>members</code> section of the <code>Cargo.toml</code> is populated with the name of the project you created.</p>
<blockquote>
<p>If not added automatically, you can add them yourself.</p>
</blockquote>
<p>  For example:</p>
<pre><code class="lang-toml"><span class="hljs-attr">members</span> = [<span class="hljs-string">"sneakers"</span>, <span class="hljs-string">"boots"</span>]
</code></pre>
<h4 id="heading-workspacepackage-section"><code>[workspace.package]</code> Section</h4>
<p>This section provides metadata for the entire workspace as if it were a single package.</p>
<ul>
<li><strong><code>name</code></strong>: The name of the workspace package.</li>
<li><strong><code>version</code></strong>: The version of the workspace package.</li>
<li><strong><code>edition</code></strong>: The Rust edition being used (e.g., "2021").</li>
<li><strong><code>authors</code></strong>: List of authors.</li>
<li><strong><code>license</code></strong>: The license for the workspace package.</li>
<li><strong><code>publish</code></strong>: Indicates whether the workspace package should be published to crates.io.</li>
</ul>
<p>Example:</p>
<pre><code class="lang-toml"><span class="hljs-section">[workspace.package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"my-shoe-collection"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>
<span class="hljs-attr">authors</span> = [<span class="hljs-string">"Your Name"</span>]
<span class="hljs-attr">license</span> = <span class="hljs-string">"MIT"</span>
<span class="hljs-attr">publish</span> = <span class="hljs-literal">false</span>
</code></pre>
<h4 id="heading-workspacedependencies-section"><code>[workspace.dependencies]</code> Section</h4>
<p>Lists dependencies that apply to the entire workspace. Meaning that every crate whether external or internal added to the <code>[workspace.dependencies]</code> is accessible to every project you create under project workspace. So below is how both external and internal crate are made accessible to other project.</p>
<p><strong>Note</strong>: For internal crate, you need to add them yourself.</p>
<p><strong><code>Internal Crates</code></strong>: Add internal crates like this:</p>
<pre><code class="lang-toml"><span class="hljs-attr">sneakers</span> = { path = <span class="hljs-string">"sneakers"</span> }
<span class="hljs-attr">boots</span> = { path = <span class="hljs-string">"boots"</span> }
</code></pre>
<p><strong><code>External Crates</code></strong>: Add external crates like this:</p>
<pre><code class="lang-toml"><span class="hljs-attr">polish</span> = <span class="hljs-string">"1.0"</span>
</code></pre>
<h3 id="heading-example-cargotoml">Example <code>Cargo.toml</code></h3>
<p>Here's an example combining these sections:</p>
<pre><code class="lang-toml"><span class="hljs-section">[workspace]</span>
<span class="hljs-attr">resolver</span> = <span class="hljs-string">"2"</span>
<span class="hljs-attr">members</span> = [<span class="hljs-string">"sneakers"</span>, <span class="hljs-string">"boots"</span>]

<span class="hljs-section">[workspace.package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"my-shoe-collection"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>
<span class="hljs-attr">authors</span> = [<span class="hljs-string">"Your Name"</span>]
<span class="hljs-attr">license</span> = <span class="hljs-string">"MIT"</span>
<span class="hljs-attr">publish</span> = <span class="hljs-literal">false</span>

<span class="hljs-section">[workspace.dependencies]</span>
<span class="hljs-comment"># Internal crate</span>
<span class="hljs-attr">sneakers</span> = { path = <span class="hljs-string">"sneakers"</span> } 
<span class="hljs-attr">boots</span> = { path = <span class="hljs-string">"boots"</span> } 

<span class="hljs-comment"># External crate</span>
<span class="hljs-attr">polish</span> = <span class="hljs-string">"1.0"</span>
</code></pre>
<p>So, here's how you set up a workspace for your project to manage multiple crates (sub-projects) and share dependencies and configuration settings across them. I spent quite some time understanding this, so I thought I'd share it with you all to make it easier.</p>
<p>To build your first smart contract, run the command below in your parent directory (<code>freecodecamp-gear-protocol</code>) on your terminal.</p>
<pre><code class="lang-bash">cargo new --lib receive-joke
</code></pre>
<pre><code class="lang-bash">.freecodecamp-gear-protocol
├── Cargo.toml
└── receive-joke
    ├── Cargo.toml
    └── src
        └── lib.rs

2 directories, 3 files
</code></pre>
<p>Head over to your <code>freecodecamp-gear-protocol/receive-joke/Cargo.toml</code>, and this is how you access crates, and configuration from the workspace directory(main) using <code>.workspace=true</code>, like below;</p>
<pre><code class="lang-toml"><span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> =<span class="hljs-string">"receive-joke"</span>
<span class="hljs-attr">version.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">edition.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">authors.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">license.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">publish.workspace</span> = <span class="hljs-literal">true</span>

<span class="hljs-comment"># See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html</span>

<span class="hljs-section">[dependencies]</span>
</code></pre>
<p>Next, create a <code>build</code> file in your <code>receive-joke</code> directory with path like<code>receive-joke/build.rs</code>, and paste the code below. Now, the <code>build.rs</code> helps you to build your project into <code>.wasm</code> file, that is used to deploy your smart contract.</p>
<p><strong>build.rs:</strong></p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    gear_wasm_builder::build();
}
</code></pre>
<p>Currently, you have't install the nesscessary crate to help create your smart contract. Therefore, add the following crate to your workspace dependency.</p>
<p><strong>Cargo.toml:</strong></p>
<pre><code class="lang-toml"><span class="hljs-section">[workspace]</span>
<span class="hljs-attr">resolver</span> = <span class="hljs-string">"2"</span>
<span class="hljs-attr">members</span> = [<span class="hljs-string">"receive-joke"</span>]


<span class="hljs-section">[workspace.package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"freecodecamp-gear-protocol"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>
<span class="hljs-attr">authors</span> = [<span class="hljs-string">"Rocky Essel"</span>]
<span class="hljs-attr">license</span> = <span class="hljs-string">"MIT"</span>
<span class="hljs-attr">publish</span> = <span class="hljs-literal">false</span>

<span class="hljs-section">[workspace.dependencies]</span>
<span class="hljs-comment"># Internal Crates</span>

<span class="hljs-comment"># External Crates</span>
<span class="hljs-attr">gstd</span> = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">gmeta</span> = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">gtest</span>  = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">gear-wasm-builder</span> = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">parity-scale-codec</span> = { version = <span class="hljs-string">"3.6.12"</span>, default-features = <span class="hljs-literal">false</span> }
<span class="hljs-attr">scale-info</span> = { version = <span class="hljs-string">"2.11.3"</span>, default-features = <span class="hljs-literal">false</span> }
</code></pre>
<p>For your first project, only <code>gstd</code> would be used, so like add that external crate to your <code>receive-joke</code>'s <code>Cargo.toml</code>. Like below:</p>
<pre><code class="lang-toml"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">gstd.workspace</span> = <span class="hljs-literal">true</span>


<span class="hljs-section">[build-dependencies]</span>
<span class="hljs-attr">gear-wasm-builder.workspace</span> = <span class="hljs-literal">true</span>
</code></pre>
<p>If you reached here without any errors, well done my friend. Next, is to clear any code in <code>freecodecamp-gear-protocol/receive-joke/src/lib.rs</code>. Let's move on to the next step.</p>
<p>In Gear Protocol, there are entry points. An entry point serves as a gateway or door to your code. Gear has a few entry points, namely:</p>
<pre><code class="lang-rust">state(),
handle(),
handle_reply(),
init(),
handle_signal(),
</code></pre>
<p>Each entry point plays a significant role. For example, <code>init()</code> is called when the smart contract(<code>.wasm</code>) is deployed, allowing you to set certain conditions or variables or even other functions  that need to be executed for smooth sailing of your smart contract or program.</p>
<p>However, it's optional, meaning that you can choose to include or exclude it depending on your project, but it still gets executed, and it is the first message you'll see once you deploy your smart contract.</p>
<p>The <code>handle()</code> method is crucial as it contains most of the business logic. It's mandatory to include your program. More light will be shared on the entry points as you move forward.</p>
<p>Now, paste the following code into your <code>receive-joke/src/lib.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gstd::msg;

<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">handle</span></span>() {
    <span class="hljs-comment">// Send a reply(in HTTP GET Request, you'd use "response").</span>
    msg::reply_bytes(
        <span class="hljs-string">"What did the dirt say to the rain? If you keep this up, my name will be mud!"</span>,
        <span class="hljs-number">0</span>,
    )
    .expect(<span class="hljs-string">"Unable to reply"</span>);
}
</code></pre>
<p>The code above defines a function <code>handle</code> that, when called, sends a message you've defined as a response using the <code>gstd::msg</code> functionality. This <code>gstd</code> is a crate provided by Gear Protocol<strong>,</strong> to send and receive messages, and this is crucial for programs running on Vara Network to communicate with each other and external systems. And the <code>reply_bytes</code> send a new message as a reply to the message that is currently being processed.</p>
<p>Time to deploy and send your first message and recieve your joke reply. In your terminal, run the following command to build your program into <strong><code>.wasm</code></strong>.</p>
<p>Usually, I use <code>cargo check</code> for check for errors first, before using the <code>build</code> command below, either way is fine.</p>
<pre><code class="lang-bash">cargo build --release
</code></pre>
<p>After the build is completed, follow the structure below to locate your <strong><code>.wasm</code></strong> file in the path below:</p>
<pre><code class="lang-bash">.freecodecamp-gear-protocol
├── Cargo.lock
├── Cargo.toml
├── receive-joke
│   └── ...
└── target
    ├── ...
    └── wasm32-unknown-unknown
        ├── ...
        └── release
            ├── receive_joke.opt.wasm &lt;--- Optimized <span class="hljs-keyword">for</span> deployment.
            └── receive_joke.wasm
</code></pre>
<h3 id="heading-how-to-deploy-your-smart-contract">How to Deploy Your Smart Contract</h3>
<p>Just like in other blockchain tools, that help you deploy your smart contract from the terminal, IDEA is where you deploy your smart contract and interact with it. We'll be exploring the interface in a bit. So finally, head over to <a target="_blank" href="https://idea.gear-tech.io/">IDEA</a> so start familiarizing yourself with your deployment environment. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-30-135927.png" alt="Image" width="600" height="400" loading="lazy">
<em>Smart Contract Deplyment Web App- IDEA</em></p>
<ol>
<li>Step one, click on <strong>Upload program</strong>, then select or drag your <strong><code>.opt.wasm</code></strong> inside the modal. This takes you to the upload page, where you can change names, enter values for the payload, or change the payload type. For now, let's leave everything as it is, and click on the <strong>Calculate,</strong> which will enter a <code>0.00015</code> gas fee value for uploading your program.</li>
</ol>
<p><strong>Note</strong>: You can either set the gas limit yourself, or click on <strong>Calculate</strong> to allow the program to generate one for you.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-30-144729.png" alt="Image" width="600" height="400" loading="lazy">
<em>Upload Page Details</em></p>
<p>At this point, click on the <strong>Upload Program</strong>, and click on the <strong>Submit</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-30-144825.png" alt="Image" width="600" height="400" loading="lazy">
<em>Transaction Details- PopUp</em></p>
<p>When you submit, you'll be prompted you sign into a your wallet, and approve.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-128.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wallet - SubWallet</em></p>
<p>After the approval, a toast message should be displayed at the right-hand corner your computer/laptop screen for you to see the status of your program, whether it failed or succeeded.</p>
<p>Assuming it's a success, click on the <strong>Programs</strong> on the sidebar, then BOOM!, there's your program. Click on it, and let's explore.</p>
<p>Upon deploying, the first thing you see is the program ID, but after a few seconds, the name of your program would be shown.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-30-150230.png" alt="Image" width="600" height="400" loading="lazy">
<em>Smart Contract Block - Page</em></p>
<p>Earlier, I said that when you deploy a program, the <code>init()</code> function is executed regardless of whether you defined it in your project or not, and that's what you see in the <strong>Messages</strong> section. Below is a simple illustration for you to familiarize and understand the information about your program.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-129.png" alt="Image" width="600" height="400" loading="lazy">
<em>Page Illustration</em></p>
<p>Now, it's time to send a message to your program and receive a reply back, which is our joke. Remember, you're not inputting any values, you're just performing a simple action to receive a reply from the program. So click on <strong>Calculate</strong> and press the <strong>Send Message</strong> (that's the action or interaction) button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-30-152529.png" alt="Image" width="600" height="400" loading="lazy">
<em>Performing an action - Initial Stage</em></p>
<p>After the message has been sent, a <code>success</code> toast will popup. Then head back to your program by clicking on the <strong>Cancel</strong> button, and you'll see two additional messages. </p>
<p>Remember, the blue color with the arrow represent the message you sent, and the green represents the reply you've received. So click on the replied message to see the joke, which says: <code>What did the dirt say to the rain? If you keep this up, my name will be mud!</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-130.png" alt="Image" width="600" height="400" loading="lazy">
<em>Receiving Reply &amp; More Illustration</em></p>
<p>Now, you're finally done with this project. In the next project, you'll be sending data or information to your program, and having it return a reply with your entered value attached to it. <a target="_blank" href="https://idea.gear-tech.io/programs/0x79e6c86aa1ab2026ef3bbc0ccbe801ce085ca2614b36f9e5be04d2354ad56396">Here is the program deployed on the <strong>Vara Network</strong></a>.</p>
<h3 id="heading-important-information">Important Information</h3>
<p>Though I've provided some context to the picture above, I want to expand on it. Both the <code>Source</code> and <code>Destination</code> takes an address that can be either a user (actor) and a program (actor), or even a message object.</p>
<h2 id="heading-next-project-input-msg">Next Project – <code>input-msg</code></h2>
<p>Just like the illustration earlier, you're going to interact with your program by sending an input value to your smart contract deployed on <strong><code>[IDEA](https://idea.gear-tech.io/programs?node=wss%3A%2F%2Ftestnet.vara.network)</code></strong>. <a target="_blank" href="https://idea.gear-tech.io/programs?node=wss%3A%2F%2Ftestnet.vara.network"><strong>IDEA</strong> </a> is your deployment environment where you deploy your smart contract on the Vara Network.<br> The point here is for you to load input values from your user, and process it by concatenating a string to the user's input value: "We've received your query. {user's-input}".</p>
<p>This is the reply you'll send back to the user that sends a message (input value).</p>
<p>So in your <code>freecodecamp-gear-protocol</code> directory, run the command below to add another member to your <code>freecodecamp-gear-protocol/Cargo.toml</code>.</p>
<pre><code class="lang-bash">cargo new --lib input-msg
</code></pre>
<p>After adding another member or project in the <code>freecodecamp-gear-protocol</code>, your path should be <code>freecodecamp-gear-protocol/input-msg</code>.</p>
<p>Earlier, I made mention of how to access input values into the smart contract or program by using <code>gstd</code>, which has a function or method called <code>load()</code>. For the next step, clear your <code>freecodecamp-gear-protocol/input-msg/src/lib.rs</code>, and paste the following code and run <code>cargo check</code>.</p>
<pre><code class="lang-bash"><span class="hljs-comment">#![no_std]</span>

use gstd::{msg, prelude::*};

<span class="hljs-comment">#[no_mangle]</span>
extern <span class="hljs-string">"C"</span> fn <span class="hljs-function"><span class="hljs-title">handle</span></span>() {
    <span class="hljs-built_in">let</span> new_msg = msg::load().expect(<span class="hljs-string">"Unable to create string"</span>);
    <span class="hljs-built_in">let</span> reply_msg = format!(<span class="hljs-string">"We've received your query {}"</span>, new_msg);
    msg::reply_bytes(reply_msg, 0).expect(<span class="hljs-string">"Unable to reply."</span>);
}
</code></pre>
<p>The check fails, but why? Well, the <code>load()</code> function has a type of <code>unknown</code>. And since Rust is a strongly typed language, it has to always know the type before hand, which wasn't the case, so it failed to build the project.</p>
<p>This should tell you that the <code>load()</code> doesn't have a type, and it is up to you to set the right data type, and failure to do so would result in some frustrating errors like below.</p>
<h3 id="heading-debugging">Debugging</h3>
<p>Now if you were to use a single project and not a workspace, then debugging the error might have easy like below.</p>
<pre><code class="lang-bash">
  error[E0282]: <span class="hljs-built_in">type</span> annotations needed
   --&gt; C:\Users\user\Desktop\2024\web3\re-gear\input-msg\src\lib.rs:7:9
    |
  7 |     <span class="hljs-built_in">let</span> new_msg = msg::load().expect(<span class="hljs-string">"Unable to create string"</span>);
    |         ^^^^^^^
    |
  <span class="hljs-built_in">help</span>: consider giving `new_msg` an explicit <span class="hljs-built_in">type</span>
    |
  7 |     <span class="hljs-built_in">let</span> new_msg: /* Type */ = msg::load().expect(<span class="hljs-string">"Unable to create string"</span>);
    |                ++++++++++++
</code></pre>
<p>But since you and I are using a workspace, it makes debugging a little difficult. This is my error message i got, when dubgging this error.</p>
<pre><code class="lang-bash">  error[E0275]: overflow evaluating the requirement `gstd::parity_scale_codec::Compact&lt;_&gt;: gstd::Decode`
    |
    = <span class="hljs-built_in">help</span>: consider increasing the recursion <span class="hljs-built_in">limit</span> by adding a `<span class="hljs-comment">#![recursion_limit = "256"]` attribute to your crate (`input_msg`)</span>
    = note: required <span class="hljs-keyword">for</span> `gstd::parity_scale_codec::Compact&lt;_&gt;` to implement `gstd::Decode`
    = note: 125 redundant requirements hidden
    = note: required <span class="hljs-keyword">for</span> `gstd::parity_scale_codec::Compact&lt;&lt;_ as CompactAs&gt;::As&gt;` to implement `gstd::Decode`

  For more information about this error, try `rustc --explain E0275`.
  error: could not compile `input-msg` (lib) due to 1 previous error
  warning: build failed, waiting <span class="hljs-keyword">for</span> other <span class="hljs-built_in">jobs</span> to finish...
  error: cargo <span class="hljs-built_in">command</span> run failed: <span class="hljs-built_in">exit</span> status: 101
warning: build failed, waiting <span class="hljs-keyword">for</span> other <span class="hljs-built_in">jobs</span> to finish...
</code></pre>
<p>And  if you look closely, you can tell that the <code>input-msg</code> is what creating the error. In this case, run <code>rustc --explain E0275</code>, which output an suggestion like this</p>
<pre><code class="lang-bash">An evaluation of a trait requirement overflowed.

Erroneous code example:

trait Foo {}

struct Bar&lt;T&gt;(T);

impl&lt;T&gt; Foo <span class="hljs-keyword">for</span> T <span class="hljs-built_in">where</span> Bar&lt;T&gt;: Foo {}

This error occurs when there was a recursive trait requirement that overflowed before it could be
evaluated. This often means that there is an unbounded recursion <span class="hljs-keyword">in</span> resolving some <span class="hljs-built_in">type</span> bounds.

To determine <span class="hljs-keyword">if</span> a T is Foo, we need to check <span class="hljs-keyword">if</span> Bar&lt;T&gt; is Foo. However, to <span class="hljs-keyword">do</span> this check, we need to
determine that Bar&lt;Bar&lt;T&gt;&gt; is Foo. To determine this, we check <span class="hljs-keyword">if</span> Bar&lt;Bar&lt;Bar&lt;T&gt;&gt;&gt; is Foo, and so on. This
is clearly a recursive requirement that can<span class="hljs-string">'t be resolved directly.

Consider changing your trait bounds so that they'</span>re less self-referential.
</code></pre>
<p>Now, though, compared to the first error message, this message doesn't provide a direct solution, it does tells you that, there's a type error in your code. And the reason is that, the <code>load()</code> can load any data type, so you should always defined a type for it.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gstd::{msg, prelude::*};

<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">handle</span></span>() {
    <span class="hljs-keyword">let</span> new_msg: <span class="hljs-built_in">String</span> = msg::load().expect(<span class="hljs-string">"Unable to create string"</span>);
    <span class="hljs-keyword">let</span> reply_msg = <span class="hljs-built_in">format!</span>(<span class="hljs-string">"We've received your query {}"</span>, new_msg);
    msg::reply_bytes(reply_msg, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Unable to reply."</span>);
}
</code></pre>
<p>In the above code, you've added a type <code>String</code> to the <code>new_msg</code> because that's the <code>type</code> you're expecting. Now run the build command, and deploy the file <strong><code>.opt.wasm</code></strong> to <code>IDEA</code>. </p>
<pre><code class="lang-bash">.freecodecamp-gear-protocol
├── receive-joke
├── Cargo.toml
├── input-msg
│   └── ...
└── target
    ├── ...
    └── wasm32-unknown-unknown
        ├── ...
        └── release
            ├── input_msg.opt.wasm &lt;--- Optimized <span class="hljs-keyword">for</span> deployment.         
            ├── input_msg.wasm
            ├── receive_joke.opt.wasm
            └── receive_joke.wasm
</code></pre>
<p>When you're done, go to your program and click on the <strong>Send Messages</strong>. Type any value into the <code>payload</code> field, and it should be a <code>type</code> of <code>String</code>. </p>
<p>Submit and approve and head back to your program, then select your <code>reply_message</code> box and you should see your <code>reply message</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot-2024-04-06-080437.png" alt="Image" width="600" height="400" loading="lazy">
<em>Smart Contract - Reply Message</em></p>
<p><a target="_blank" href="https://idea.gear-tech.io/programs/0x25629eaa3c7a51ec407f89bbaae7ccb4f58c6026283758d0fccb50e3bb042bdd">You can find the program here on the Vara Network</a>.</p>
<h2 id="heading-metadata-amp-state">Metadata &amp; State</h2>
<p>Metadata and state goes hand in hand with each other. In order for your client application to allow users to interact or request data(state) from your smart contract, you need to define both the metadata and state, and even if the state is defined, and the metadata was not provided, you cannot access the any data.</p>
<p>So let's take each step by step.</p>
<h3 id="heading-metadata">Metadata</h3>
<p>In the Gear Protocol world, metadata is like a blueprint for defining how different parts of a decentralized app (dApp) talk to each other. It's similar to how interfaces or types work in TypeScript. These blueprints describe how things like initial data type to expect, handling messages, and swapping data happen in the dApp, whether <code>In</code>, <code>Out</code>, and <code>InOut</code>.</p>
<p>When we make clear blueprints, it helps developers make sure that all the different parts of the dApp understand each other's data formats. This makes it easy for the smart contract (program-actor) and the client side app to share data smoothly.</p>
<p>To create these blueprints for your program, we use the <code>gmeta</code> tool. It helps us define these blueprints by outlining how different interactions work and what kinds of data they involve.</p>
<p>So, think of metadata in your program as similar to how interfaces/types work in TypeScript. They help organize how the different parts of your dApp communicate and understand each other's data.</p>
<h3 id="heading-example-of-a-metadata">Example Of A Metadata</h3>
<pre><code class="lang-bash">use gmeta::{InOut, Metadata, Out};

pub struct ProgramMetadata;

// Be sure to describe all the types.
// But <span class="hljs-keyword">if</span> any of the endpoints is missing <span class="hljs-keyword">in</span> your program, you can use ();
// as indicated <span class="hljs-keyword">in</span> the <span class="hljs-keyword">case</span> of `<span class="hljs-built_in">type</span> Signal`.

impl Metadata <span class="hljs-keyword">for</span> ProgramMetadata {
    <span class="hljs-built_in">type</span> Init = InOut&lt;MessageInitIn, MessageInitOut&gt;;
    <span class="hljs-built_in">type</span> Handle = InOut&lt;MessageIn, MessageOut&gt;;
    <span class="hljs-built_in">type</span> Others = InOut&lt;MessageAsyncIn, Option&lt;u8&gt;&gt;;
    <span class="hljs-built_in">type</span> Reply = String;
    <span class="hljs-built_in">type</span> Signal = ();
    <span class="hljs-built_in">type</span> State = Out&lt;Vec&lt;Wallet&gt;&gt;;
}
</code></pre>
<p>The above is an example of how it is defined. Don't worry if you don't understand it now, I'll cover more into details later. Now let's talk about the state.</p>
<h3 id="heading-state">State</h3>
<p>In Gear Protocol, the <code>state</code> function serves as a dedicated storage space within a program. This storage allows us to store and retrieve data as needed. Since this data is stored in persistent memory, it remains accessible even after the contract stops running. What's fascinating is that anyone with access to the blockchain can view this stored data. The <code>state</code> function doesn't alter or modify the blockchain itself. Instead, it simply provides a way to access stored data within the program.</p>
<p>Here is an example of a <code>state</code> function:</p>
<pre><code class="lang-bash">// Describe state structure
<span class="hljs-comment">#[derive(TypeInfo, Decode, Encode, Clone)]</span>
pub struct Messages {
    pub id: ActorId,
    pub content: String,
}

// Declare and initialize the state
static mut MESSAGES: Vec&lt;Messages&gt; = Vec::new();

<span class="hljs-comment">#[no_mangle]</span>
extern <span class="hljs-string">"C"</span> fn <span class="hljs-function"><span class="hljs-title">state</span></span>() {
    msg::reply(unsafe { MESSAGES.clone() }, 0).expect(<span class="hljs-string">"Failed to share state"</span>);
}
</code></pre>
<p>When the <code>state</code> function is called, it returns a list of <code>wallets</code> data stored within the program. This means that once a program is deployed on the blockchain, anyone can read its state.</p>
<p>Additionally, developers have the flexibility to create custom programs that can read the state. This empowers you and I to tailor our data access methods according to the specific needs for our dApp, even if the primary program undergoes changes.</p>
<p>The key takeaway is that, the <code>state</code> function facilitates access to data stored in smart contracts. It's worth noting that both users and other programs can access the state of a program, providing a versatile means of interacting with stored data.</p>
<h2 id="heading-third-project-building-messages">Third Project - Building Messages</h2>
<p>In our last project <code>input-msg</code>, we didn't keep track of the messages that got sent. So in this project, we'll cover the metadata and state.</p>
<p>Run the command below to create your project in <strong>/freecodecamp-gear-protocol/</strong>:</p>
<pre><code class="lang-bash">cargo new --lib messages
</code></pre>
<p>Next, add your <strong>build.rs</strong> file, and make the workspace dependencies available to the <code>/freecodecamp-gear-protocol/messages</code>.</p>
<h3 id="heading-adding-metadata-to-messages">Adding Metadata to Messages</h3>
<p>To setup a metadata for your project, you need to create an additional crate to manage that, so <code>cd</code> into <strong>messages</strong>, and run the command below.</p>
<pre><code class="lang-bash">cargo new --lib io
</code></pre>
<p>In your <strong>freecodecamp-gear-protocol/messages/io/Cargo.toml</strong>, copy and paste the following code:</p>
<pre><code class="lang-toml"><span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"messages-io"</span>
<span class="hljs-attr">version.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">edition.workspace</span> = <span class="hljs-literal">true</span>


<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">gstd.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">gmeta.workspace</span> = <span class="hljs-literal">true</span>
</code></pre>
<p>Here, I changed the name from <code>io</code> to <code>messages-io</code>, and the reason is for me to identify, and separate it for other <code>io</code>'s in the workspace. And add the dependencies.</p>
<p>In order to use the <code>io</code> in your workspace, you need to go the <strong>freecodecamp-gear-protocol/Cargo.toml</strong>, and add a path from your <code>io</code> to your workspace, which you can then use in any of the projects that need <code>struct</code>, <code>enum</code>, and <code>method</code>.</p>
<p>In <strong>freecodecamp-gear-protocol/Cargo.toml</strong>:</p>
<pre><code class="lang-bash">[workspace]
resolver = <span class="hljs-string">"2"</span>
members = [<span class="hljs-string">"receive-joke"</span>,<span class="hljs-string">"input-msg"</span>]


[workspace.package]
name = <span class="hljs-string">"freecodecamp-gear-protocol"</span>
version = <span class="hljs-string">"0.1.0"</span>
edition = <span class="hljs-string">"2021"</span>
authors = [<span class="hljs-string">"Rocky Essel"</span>]
license = <span class="hljs-string">"MIT"</span>
publish = <span class="hljs-literal">false</span>

[workspace.dependencies]
<span class="hljs-comment"># Internal Crates</span>
messages-io={path = <span class="hljs-string">"messages/io"</span>} &lt; ---- Here

<span class="hljs-comment"># External Crates</span>
gstd = <span class="hljs-string">"1.4.1"</span>
gmeta = <span class="hljs-string">"1.4.1"</span>
gtest  = <span class="hljs-string">"1.4.1"</span>
gear-wasm-builder = <span class="hljs-string">"1.4.1"</span>
parity-scale-codec = { version = <span class="hljs-string">"3.6.12"</span>, default-features = <span class="hljs-literal">false</span> }
scale-info = { version = <span class="hljs-string">"2.11.3"</span>, default-features = <span class="hljs-literal">false</span> }
</code></pre>
<p>And that's the <code>Internal Crate</code> I talked about earlier. Next, you need to include the <code>messages-io</code> in your <code>messages</code> project, like below:</p>
<pre><code class="lang-toml"><span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span>=<span class="hljs-string">"messages"</span>
<span class="hljs-attr">version.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">edition.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">authors.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">license.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">publish.workspace</span> = <span class="hljs-literal">true</span>


<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">gstd.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">messages-io.workspace</span> = <span class="hljs-literal">true</span> &lt;---

<span class="hljs-section">[build-dependencies]</span>
<span class="hljs-attr">gear-wasm-builder.workspace</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">messages-io.workspace</span> = <span class="hljs-literal">true</span> &lt; ---
</code></pre>
<p>The reason for adding <code>messages-io.workspace</code> to both the <code>[dependencies]</code> and <code>[build-dependencies]</code> is to make the <code>struct</code>, <code>enums</code>, <code>pub variables</code> and <code>methods</code> accessible to <code>messages/src/lib.rs</code>, and <code>messages/build.rs</code> using <code>messages-io.workspace</code>.</p>
<h3 id="heading-metadata-in-iosrclibrs">Metadata in <code>io/src/lib.rs</code></h3>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gmeta::{InOut, Metadata, Out};
<span class="hljs-keyword">use</span> gstd::{prelude::*, ActorId, <span class="hljs-built_in">Vec</span>};

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MessageMetadata</span></span>;

<span class="hljs-keyword">pub</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">mut</span> MESSAGES: <span class="hljs-built_in">Vec</span>&lt;User&gt; = <span class="hljs-built_in">Vec</span>::new();

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Message</span></span> {
    <span class="hljs-keyword">pub</span> id: ActorId,
    <span class="hljs-keyword">pub</span> content: <span class="hljs-built_in">String</span>,
}

<span class="hljs-keyword">impl</span> Metadata <span class="hljs-keyword">for</span> MessageMetadata {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Init</span></span> = InOut&lt;Message, <span class="hljs-built_in">String</span>&gt;;
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Handle</span></span> = InOut&lt;Message, <span class="hljs-built_in">String</span>&gt;;
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">State</span></span> = Out&lt;<span class="hljs-built_in">Vec</span>&lt;Message&gt;&gt;;
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Reply</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Others</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Signal</span></span> = ();
}
</code></pre>
<p>To implement the logic of the message-handling system for your program or smart contract, understanding how to set the metadata of your program is crucial.<br>Therefore, much attention is needed here.</p>
<p>The <code>MessageMetadata</code> struct you've defined implements the <code>Metadata</code> trait, which then structures the message metadata for the program. Also, a mutable static variable <code>MESSAGES</code> is declared to store all the messages you and your users send to the program. And since it’s a mutable static variable, unsafe code will be required to modify it due to Rust's safety guarantees around mutable static variables.</p>
<p>The <code>Message</code> struct is defined with two fields: <code>id</code> (sender's identifier) and <code>content</code> (the message text).</p>
<p>The <code>Metadata</code> trait is implemented for <code>MessageMetadata</code>, defining several associated types. The <code>Init</code> type is set to <code>InOut&lt;MessageInit, String&gt;</code>, specifying the input-output types for the initialization phase. \</p>
<p>This means that when the contract is initialized, it will accept a <code>MessageInit</code> type and return a <code>String</code>. The <code>Handle</code> type is set to <code>InOut&lt;Message, String&gt;</code>, specifying the input-output types for handling messages. It accepts a <code>Message</code> type as input and returns a <code>String</code>. </p>
<p>The <code>State</code> type is set to <code>Out&lt;Vec&lt;Message&gt;&gt;</code>, defining the state output type, meaning that the state of the contract will be a vector of <code>Message</code> objects, and it doesn’t accept any input to retrieve this state. The <code>Reply</code>, <code>Others</code>, and <code>Signal</code> types are all set to <code>()</code>, indicating no additional reply, other types, or signals are used in this case.</p>
<h3 id="heading-further-context-of-its-usage">Further Context of its usage.</h3>
<p>In this system, the metadata definition specifies how the smart contract should handle initialization and message handling. During the initialization phase (<code>Init</code>), when the contract is deployed on the Vara Network, it uses the <code>Init</code> type to set up the initial state. The input is expected to be of type <code>MessageInit</code>, and the output will be a <code>String</code>. During deployment, you provide your ID and message content, which the contract processes using the <code>init()</code> method.</p>
<p>After deployment, the contract can handle new messages using the <code>Handle</code> type, which expects a <code>Message</code> type as input and returns a <code>String</code> as a response. This functionality is useful for adding new messages to the <code>MESSAGES</code> vector. For state management (<code>State</code>), the contract’s state is a list of messages (<code>Vec&lt;Message&gt;</code>), and it doesn’t accept any input to retrieve the state but outputs the current state when queried.</p>
<p>So to summarize, the code in <strong>freecodecamp-gear-protocol/messages/io/src/lib.rs</strong> defines the structure and behavior of a message-handling smart contract, specifying how it initializes, handles messages, and manages state.</p>
<h3 id="heading-building-the-metadata">Building the Metadata</h3>
<p>In order to build your project with the metadata, you need to modify the <strong>build.rs</strong>, which initially looks like below:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    gear_wasm_builder::build();
}
</code></pre>
<p>There's nothing wrong with using the above code, but if you plan to build your program and deploy on the blockchain to use it on the client or anywhere else, it would be impossible to interact with your smart contract if the metadata is not defined. Think of it like <code>ABI</code> in other blockchain environment.</p>
<p>So replace the code with:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> messages_io::MessageMetadata;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    gear_wasm_builder::build_with_metadata::&lt;MessageMetadata&gt;();
}
</code></pre>
<p>Finally, you would be handling the logic for your smart contract in the <code>messages/src/lib.rs</code> using the <code>handle()</code> function.</p>
<p>Here is the code for the <code>lib.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gstd::{exec, msg, prelude::*, ActorId};

<span class="hljs-keyword">use</span> messages_io::*;

<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">init</span></span>() {
    <span class="hljs-keyword">let</span> init: Message = msg::load().expect(<span class="hljs-string">"Unable to decode Message"</span>);
    <span class="hljs-keyword">let</span> init_message = Message {
        id: init.id,
        content: init.content,
    };

    <span class="hljs-keyword">unsafe</span> { MESSAGES.push(init_message) };    
    msg::reply_bytes(<span class="hljs-string">"Successfully initialized"</span>, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to initialize successfully."</span>);
}


<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">handle</span></span>() {

    <span class="hljs-keyword">let</span> message_handler: Message = msg::load().expect(<span class="hljs-string">"Unable to decode Message"</span>);
    <span class="hljs-keyword">let</span> message = Message {
        id: message_handler.id,
        content: message_handler.content,
    };
    <span class="hljs-keyword">unsafe</span> { MESSAGES.push(message) };
    msg::reply_bytes(<span class="hljs-string">"Message sent successfully."</span>, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to send  reply message."</span>);
}


<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">state</span></span>() {
    msg::reply(<span class="hljs-keyword">unsafe</span> { MESSAGES.clone() }, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to share state"</span>);
}
</code></pre>
<h3 id="heading-initialization-function-init">Initialization Function (<code>init</code>)</h3>
<pre><code class="lang-rust"><span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">init</span></span>() {
    <span class="hljs-keyword">let</span> init: Message = msg::load().expect(<span class="hljs-string">"Unable to decode Message"</span>);
    <span class="hljs-keyword">let</span> init_message = Message {
        id: init.id,
        content: init.content,
    };

    <span class="hljs-keyword">unsafe</span> { MESSAGES.push(init_message) };
    msg::reply_bytes(<span class="hljs-string">"Successfully initialized"</span>, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to initialize successfully."</span>);
}
</code></pre>
<p>The <code>init</code> function is the entry point for initializing the smart contract. It is marked with <code>#[no_mangle]</code> to prevent Rust from applying name mangling, making the function accessible from the smart contract runtime. </p>
<p>The function begins by loading the initial message from the input payload using <code>msg::load()</code>. This message is expected to be of type <code>Message</code>, and if decoding fails, the function will panic with an error message. Next, a new <code>Message</code> instance is created from the loaded data. This new message is then added to the global <code>MESSAGES</code> vector, which is a mutable static variable marked as unsafe due to potential data races. Finally, the function sends a reply indicating successful initialization using <code>msg::reply_bytes</code>. If this reply fails, the function will panic.</p>
<h3 id="heading-message-handling-function-handle">Message Handling Function (<code>handle</code>)</h3>
<pre><code class="lang-rust"><span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">handle</span></span>() {
    <span class="hljs-keyword">let</span> message_handler: Message = msg::load().expect(<span class="hljs-string">"Unable to decode Message"</span>);
    <span class="hljs-keyword">let</span> message = Message {
        id: message_handler.id,
        content: message_handler.content,
    };
    <span class="hljs-keyword">unsafe</span> { MESSAGES.push(message) };
    msg::reply_bytes(<span class="hljs-string">"Message sent successfully."</span>, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to send  reply message."</span>);
}
</code></pre>
<p>The <code>handle</code> function is designed to handle incoming messages after the contract is deployed. Like the <code>init</code> function, it is marked with <code>#[no_mangle]</code> to ensure it can be called from the smart contract runtime. The function begins by loading the incoming message from the input payload. This message is decoded into a <code>Message</code> struct, and if decoding fails, the function will panic. </p>
<p>A new <code>Message</code> instance is then created from the decoded data and added to the global <code>MESSAGES</code> vector using an unsafe block. The function then sends a reply indicating that the message was sent successfully. If the reply fails, the function will panic.</p>
<h3 id="heading-state-query-function-state">State Query Function (<code>state</code>)</h3>
<pre><code class="lang-rust"><span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">state</span></span>() {
    msg::reply(<span class="hljs-keyword">unsafe</span> { MESSAGES.clone() }, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to share state"</span>);
}
</code></pre>
<p>The <code>state</code> function allows querying the current state of the smart contract. It is also marked with <code>#[no_mangle]</code> for the same reasons as the previous functions. The function replies with a cloned version of the global <code>MESSAGES</code> vector, containing all the messages that have been added so far. This is done within an unsafe block due to the mutable static variable. If the function fails to send the state, it will panic.</p>
<p>So this code simply defines a smart contract with three main functions: <code>init</code> for initialization, <code>handle</code> for processing incoming messages, and <code>state</code> for querying the current state of the contract. Where each function carefully manages the global <code>MESSAGES</code> vector.</p>
<h3 id="heading-deployment-on-the-vara-network">Deployment on the Vara Network</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.loom.com/share/e967ebf211f54f2c9c85fedc593e427e?sid=3ef6709a-8b5a-412b-b80c-93f721ba135b">https://www.loom.com/share/e967ebf211f54f2c9c85fedc593e427e?sid=3ef6709a-8b5a-412b-b80c-93f721ba135b</a></div>
<p>Now you're done with this project, and hope you learned and have understood most of what I've written. In our next project, you'll be building something a bit more complex than this. So let's begin.</p>
<p><a target="_blank" href="https://idea.gear-tech.io/programs/0x58acd467aa011554b0dc167f741e745b336a03943df6f1eba635e9c28ca9824e">Here is the program deployed on Vara Network</a>, and this is the <a target="_blank" href="https://github.com/rockyessel/freecodecamp-gear-protocol">entire repository for the 3 projects</a> we've built so far. The next project is going to be stand-alone project so you won't use the workspace.</p>
<h2 id="heading-final-project">Final Project</h2>
<p>In this final project, you'll build a very simple game: where you (<code>player</code>) fights with the <code>boss</code>. So here is a simple layman's explanation of the game mechanics.</p>
<h3 id="heading-game-description">Game Description</h3>
<p>This game is a one-on-one battle between a player and a boss. To begin, the player selects their character from three options: Warrior, Mage, or Archer. Once the player's character data is stored in the program, the game begins.</p>
<p>In the game, the player immediately faces the boss, who starts with 10 lives (represented as an integer), while the player begins with 10 lives by default. The objective is to defeat the boss using a specific rule: the boss has weaknesses represented by letters (X, Y, Z), each associated with a random number.</p>
<p>During gameplay, if the player enters one of these letters, for example, 'Y' with a value of 4, and the boss starts with 0 lives, the program subtracts 4 lives from the boss, leaving 6. Similarly, when the player makes a move with a letter, the boss also makes a move with the a random letter with an associated value added to it.</p>
<p>The player progresses to the next level upon defeating the boss, continuing the battle with new challenges. I call this game Battle Showdown <strong>🤣😁😂.</strong></p>
<h3 id="heading-battle-showdown-mechanics-summary"><strong>Battle Showdown</strong> Mechanics Summary</h3>
<h4 id="heading-player-and-boss-lives">Player and Boss Lives</h4>
<ul>
<li>Player starts with 10 lives.</li>
<li>Boss starts with 10 lives.</li>
</ul>
<h4 id="heading-weaknesses-and-values">Weaknesses and Values</h4>
<ul>
<li>Boss and the player has weaknesses represented by letters ( <code>X</code>, <code>Y</code>, <code>Z</code>), each associated with a random number.</li>
</ul>
<h4 id="heading-gameplay">Gameplay</h4>
<ul>
<li>Player inputs a letter (for example, <code>'Y'</code>) and the associated value (for example, <code>4</code>) is subtracted from the boss's lives.</li>
<li>Boss retaliates with a letter and the same value is subtracted from the player's lives.</li>
<li>The objective is for the player to reduce the boss's lives to 0 to progress to the next level.</li>
</ul>
<h3 id="heading-match-equation">Match Equation</h3>
<p>Let's define the key variables:</p>
<ul>
<li>(<code>Lp</code>) = Player's current lives.</li>
<li>(<code>Lb</code>) = Boss's current lives.</li>
<li>(<code>V</code>) = Value associated with the letter representing the attack.</li>
</ul>
<p><strong>Initial conditions:</strong></p>
<ul>
<li>( <code>Lp</code> = 10 )</li>
<li>( <code>Lb</code> = 10 )</li>
</ul>
<p><strong>Player's turn:</strong></p>
<ul>
<li>Player selects a letter with an associated value (<code>V</code>).</li>
<li>Boss's lives are reduced: (<code>Lb</code> = <code>Lb</code> - <code>V</code>).</li>
</ul>
<p><strong>Boss's retaliation:</strong></p>
<ul>
<li>Boss selects a letter (same value (<code>V</code>)).</li>
<li>Player's lives are reduced: (<code>Lp</code> = <code>Lp</code> - <code>V</code>).</li>
</ul>
<p>This continues until either ( <code>Lb</code> ) (boss's lives) or ( <code>Lp</code> ) (player's lives) reaches 0.</p>
<h3 id="heading-equations">Equations</h3>
<p>After the player's attack and the Boss's retaliation:<br>[<code>Lb</code> = <code>Lb</code> - <code>V</code>]<br>[<code>Lp</code> = <code>Lp</code> - <code>V</code>]</p>
<p>The game loop continues with the player and boss exchanging moves. Repeat until <code>Lb</code> <code>&lt;= 0</code> or <code>Lp</code> <code>&lt;= 0</code></p>
<h3 id="heading-example">Example</h3>
<p>If the player inputs <code>'Y'</code> with a value of <code>4</code>:</p>
<ul>
<li>Initial: ( <code>Lp</code> = 10 ), ( <code>Lb</code> = 10 )</li>
<li>Player's attack: ( <code>Lb</code> = 10 - 4 = 6 )</li>
<li>Boss's retaliation: ( <code>Lp</code> = 10 - 4 = 6 )</li>
</ul>
<p>Next move:</p>
<ul>
<li>If the player inputs another value, let's say: <code>'X'</code> with a value of <code>5</code>:</li>
<li>Player's attack: ( <code>Lb</code> = 6 - 5 = 1 )</li>
<li>Boss's retaliation: ( <code>Lp</code> = 6 - 5 = 1 )</li>
</ul>
<p>The player wins as the Boss's lives ( <code>Lb</code> ) have reached 0.</p>
<p>The match equation for each round of the game can be summarized as:<br>[<code>Lb</code> = <code>Lb</code> - <code>V</code>]<br>[<code>Lp</code> = <code>Lp</code> - <code>V</code>]<br>This process is repeated until either the player's lives (( <code>Lp</code> )) or the Boss's lives (( <code>Lb</code> )) reach 0, determining the winner of the battle.</p>
<h3 id="heading-windows-error">Windows Error</h3>
<p>If you use Windows, you may encounter an error with the <strong>link.exe</strong>. Honestly, I cannot explain the reason behind the error, but in the Gear docs, it was made clear that Windows users might experience some problems when building their project.</p>
<p>But rest assured, there's a solution, and I'm going to guide you through it. So please follow these steps carefully so you don't have to deal with bugs along the way.</p>
<h3 id="heading-step-1-install-wsl-via-command-prompt">Step 1 - Install WSL via Command Prompt</h3>
<p>Open your CLI with administrative privileges, and run the command below:</p>
<pre><code class="lang-bash">wsl --install
</code></pre>
<p>After excutting the command, run the command below to list other Linux releases. </p>
<pre><code class="lang-bash">wsl -l -o
</code></pre>
<p>This command shows a list of other Linux distros, and you can select anyone you've used before. If you're new to Linux distros, I recommend selecting the <code>Ubuntu-22.04</code>.</p>
<p>These are just lists and are read-only. In order to select your system, run the command below.</p>
<pre><code class="lang-bash">wsl --install -d {Distribtion Name here(Ubuntu-22.04)}
</code></pre>
<p>After you're done with the installation, restart your PC. Wait a little while for the terminal to popup and prompt you for your details such as your username and password. If the terminal doesn't open, go to your start menu, and you will find something similar to this in your <code>Start</code> menu.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/image-6.png" alt="Image" width="600" height="400" loading="lazy">
<em>Ubuntu in start menu</em></p>
<p>After that, the next thing to do is to install Rust on your WSL. </p>
<h3 id="heading-how-to-install-rust-on-your-wsl">How to Install Rust On Your WSL</h3>
<p>To install Rust on your machine, I recommend that whenever you want to install any package, it is best practice to install updates and upgrades to the system before continuing with the installation.</p>
<pre><code class="lang-bash">sudo apt update &amp;&amp; sudo apt upgrade -y
</code></pre>
<p>When you run <code>sudo apt update &amp;&amp; sudo apt upgrade -y</code>, you first update the package lists to get the latest information about available software packages. Then, if the update is successful, it proceeds to upgrade the installed packages to their latest versions, automatically confirming the upgrades to avoid manual intervention. This is a common and recommended practice to keep your Linux system up-to-date and secure.</p>
<h3 id="heading-essential-dependencies">Essential Dependencies.</h3>
<p>The command below installs essential development tools (<code>build-essential</code>, <code>gcc</code>, and <code>make</code>) and the <code>curl</code> utility for making HTTP requests and downloading files. These packages are commonly required for software development, compilation, and system administration tasks.</p>
<pre><code class="lang-bash"> sudo apt install curl build-essential gcc make -y
</code></pre>
<p>After that, run the command in the terminal  </p>
<pre><code class="lang-bash"> curl --proto <span class="hljs-string">'=https'</span> --tlsv1.2 -sSf https://sh.rustup.rs | sh
</code></pre>
<p>In the installation process, you'll be prompted a question: go with the <code>default</code> when it happens.</p>
<pre><code class="lang-bash">1. Proceed with installation (default) --&gt; Enter
2. Customize installation
3. Cancel installation.
</code></pre>
<p>After this prompt, you have successfully installed Rust on the Ubuntu System. Now the next step is to restart your terminal, simply close the current terminal. Open a new one, and run the command below.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">$HOME</span>/.cargo/env"</span>
</code></pre>
<p>What this command source <code>"$HOME/.cargo/env"</code> does is to activate the Rust environment. The reason is that the Rust environment comprises essential variables and configurations required for effective Rust usage. Now, once run, there's no output, so you can verify the installation by running the command below.</p>
<pre><code class="lang-bash"> rustc -V
</code></pre>
<p>Expected output:</p>
<pre><code class="lang-bash">rockyessel@UBUNTU-ROCKY:~$ rustc -V rustc 1.73.0 (cc66ad468 2024-02-07)
</code></pre>
<p>When you're done, there're also additional dependencies we have to install. So here, install them.</p>
<pre><code class="lang-bash">// Install the following.

 --&gt; rustup toolchain add nightly-2023-09-18
 --&gt; rustup target add wasm32-unknown-unknown --toolchain nightly-2023-09-18
</code></pre>
<p>After successfully installing them, head to the next section, which is building a game project.</p>
<p>In your WSL terminal, create your project name <code>battle-showdown</code>, and adding all the necessary <strong>toml</strong> files, and dependences. After that, <code>cd</code> into your project <code>battle-showdown</code> and added another program called <strong>io</strong>, this is where you write your metadate and other complex or simple data-type for your dApp.</p>
<pre><code class="lang-bash">battle-showdown
.
├── Cargo.toml
├── io
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
└── src
    └── lib.rs
</code></pre>
<p>So head-over to to your <strong>./io/src/lib.rs</strong> and paste the follow code:</p>
<pre><code class="lang-bash"><span class="hljs-comment">#![no_std]</span>

use gmeta::Metadata;

pub struct BattleShowdown;

impl Metadata <span class="hljs-keyword">for</span> BattleShowdown {
    <span class="hljs-built_in">type</span> Init = ();
    <span class="hljs-built_in">type</span> Handle = ();
    <span class="hljs-built_in">type</span> State = ();
    <span class="hljs-built_in">type</span> Reply = ();
    <span class="hljs-built_in">type</span> Others = ();
    <span class="hljs-built_in">type</span> Signal = ();
}
</code></pre>
<p>Here, you have defined a new public struct named <code>BattleShowdown</code>. Structs are used to create custom data types by grouping fields of various types together. But in this case, you're providing an implementation for the required types of the <code>Metadata</code> trait for the <code>BattleShowdown</code> struct: <code>impl Metadata for BattleShowdown</code>.</p>
<p><code>type Init = ()</code>, <code>type Handle = ()</code>, <code>type State = ()</code>, <code>type Reply = ()</code>, <code>type Others = ()</code>, and <code>type Signal = ()</code> specifies that the handlers or functions data type for <code>BattleShowdown</code> is of type <code>()</code>, which in Rust's unit type, equivalent to <code>void</code> in other language such as <code>TypeScript</code>.</p>
<p>So for now, we're saying that these handlers do not send or receive data as such. Hence, the code just specifies how <code>BattlwShowdown</code> interacts with the system. However, it is worth mentioning that, the <code>BattleShowdown</code> struct itself doesn't have any specific initialization data, state, handling behavior, replies, signals, or other associated types defined.</p>
<h3 id="heading-building-our-game">Building Our Game</h3>
<p>First off, let's make register the <strong>io</strong> in your parent directory <strong>cargo.toml</strong>. So head over to <code>./cargo.toml</code> and paste the code below:</p>
<pre><code class="lang-toml"><span class="hljs-attr">workspace</span> = { members = [<span class="hljs-string">"io"</span>] }
<span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"battle-showdown"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">gstd</span> = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">battle-showdown-io</span>={path = <span class="hljs-string">"io"</span>}



<span class="hljs-section">[build-dependencies]</span>
<span class="hljs-attr">gear-wasm-builder</span> = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">battle-showdown-io</span>={path = <span class="hljs-string">"io"</span>}
</code></pre>
<p>I've ensured that the "battle-showdown-io" path is included in both the dependencies and build-dependencies sections. This decision was intentional because when it's added solely to build-dependencies, only the structs, enums, and other data types or functions within the build.rs file gain access to them, not the dependencies in your <strong><code>./src/lib.rs</code></strong>. This is important because I'll be utilizing <code>battle-showdown-io</code> in both build-dependencies (<code>build.rs</code>) and dependencies (<code>./src/lib.rs</code>).</p>
<p>This step is crucial because overlooking it can lead to frustrating import errors.</p>
<p>Next, is the file <strong><code>./io/cargo.toml</code></strong>, paste the following code below.</p>
<pre><code class="lang-toml"><span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"battle-showdown-io"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

<span class="hljs-comment"># See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html</span>

<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">gstd</span> = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">gmeta</span> = <span class="hljs-string">"1.4.1"</span>
<span class="hljs-attr">parity-scale-codec</span> = { version = <span class="hljs-string">"3.6.12"</span>, default-features = <span class="hljs-literal">false</span> }
<span class="hljs-attr">scale-info</span> = { version = <span class="hljs-string">"2.11.3"</span>, default-features = <span class="hljs-literal">false</span> }
</code></pre>
<h3 id="heading-explaining-metadata-for-battleshown">Explaining Metadata For BattleShown</h3>
<p>It's crucial to pay closer attention to this section, as I'll shed more light on explaining the metadata types for <code>BattleShown</code> and deploying it on the Vara Network.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gmeta::Metadata;

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BattleShowdown</span></span>;

<span class="hljs-keyword">impl</span> Metadata <span class="hljs-keyword">for</span> BattleShowdown {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Init</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Handle</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">State</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Reply</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Others</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Signal</span></span> = ();
}
</code></pre>
<h3 id="heading-defining-initialization-init">Defining Initialization – <code>Init</code></h3>
<p>To define the types for this purpose, consider whether your program or smart contract needs to store data or perform actions before the user can interact with it. In the case of this game, the answer is yes. </p>
<p>The game assumes that only one person is playing and does not allow users to create their characters or players. This means that you need to store data before proceeding to use this program, and in this scenario, we need information about the person/developer/actor/user deploying the contract or program, which is you.</p>
<p>Here is the information you'll want to store:</p>
<ul>
<li><strong>playerId - Type: ActorId</strong><br>The playerId is actually the address associated with your account, which has the type of <code>ActorId</code>.</li>
<li><strong>playerName - Type: String</strong><br>This has a type of string, pretty much straightforward.</li>
<li><strong>playerCharacterType - Type: Enum</strong><br>The <code>playerCharacterType</code> is an enum that gives the actor an option to select which type they want to be, with options including Mage, Warrior, and Archer.</li>
</ul>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gmeta::Metadata;

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BattleShowdown</span></span>;

<span class="hljs-keyword">impl</span> Metadata <span class="hljs-keyword">for</span> BattleShowdown {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Init</span></span> = InOut&lt;InitBattleShowdown, <span class="hljs-built_in">String</span>&gt;;
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Handle</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">State</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Reply</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Others</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Signal</span></span> = ();
}

<span class="hljs-meta">#[derive(Debug, Clone, Copy, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">CharacterType</span></span> {
    Warrior,
    Mage,
    Archer,
}


<span class="hljs-meta">#[derive(Default, Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">InitBattleShowdown</span></span> {
    <span class="hljs-keyword">pub</span> player_id: ActorId,
    <span class="hljs-keyword">pub</span> player_character_type: CharacterType,
    <span class="hljs-keyword">pub</span> player_name: <span class="hljs-built_in">String</span>,
}
</code></pre>
<p>Although I've previously discussed metadata, you might be curious about what <code>type Init = InOut&lt;InitBattleShowdown, String&gt;;</code> means. Well, it's nothing complex. Here, we're simply stating that the <code>init</code> handle will accept a data type of <code>InitBattleShowdown</code> and will respond with a data type of <code>String</code>.</p>
<p>Before you continue, one more step remains: implementing a <code>default trait</code> for the enum <code>CharacterType</code>. This ensures that if the <code>CharacterType</code> is not explicitly defined, it defaults to <code>Warrior</code>. Simply add the following code to the existing code above:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> <span class="hljs-built_in">Default</span> <span class="hljs-keyword">for</span> CharacterType {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        CharacterType::Warrior
    }
}
</code></pre>
<h3 id="heading-defining-the-handle">Defining the <code>Handle</code></h3>
<p>Defining a type for the <code>handle</code> function mirrors the process for the <code>init</code> function, but the actual implementation is left to the developer, which in this case, is you. After reviewing code and experimenting with different approaches, I discovered a method used by Gear Protocol (which shares similarities with some of their projects) that made more sense.</p>
<h3 id="heading-action-amp-event">Action &amp; Event</h3>
<p>In their implementation, they utilized Actions and Events. Actions represent a set of operations that the program can perform, while Events are the outcomes of these Actions.</p>
<p>For example, in the context of this game, you could have an action named <code>Attack</code> with a corresponding Event named <code>Attacked</code>. These could potentially accept parameters and return results.</p>
<p>Therefore, to define the handle type, include the following code in your existing codebase:</p>
<pre><code class="lang-rust">
<span class="hljs-meta">#[derive(Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">BattleShowdownAction</span></span> {
    Attack {
        character_hit_power_value: PlayerHitPowerValue,
    },
}
</code></pre>
<p>Previously, when describing the game mechanics, I introduced a mechanic involving a letter with a randomly assigned number to inject an element of randomness. In this context, these letters correspond to an <code>ENUM</code> state of <code>X</code>, <code>Z</code>, and <code>Y</code>.</p>
<p>Therefore, to implement this mechanic, add the following code:</p>
<pre><code class="lang-rust">...

<span class="hljs-meta">#[derive(Debug, Clone, Copy, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">PlayerHitPowerValue</span></span> {
    X,
    Y,
    Z,
}
</code></pre>
<p>When an actor or user decides to attack the boss, they can select from the options provided above, each with a random value. Consequently, each attack on the boss will yield different outcomes due to the variability in these values. Similar to how you implemented a default trait for the <code>CharacterType</code>, you should follow suit here.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> <span class="hljs-built_in">Default</span> <span class="hljs-keyword">for</span> PlayerHitPowerValue {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        PlayerHitPowerValue::X
    }
}
</code></pre>
<h3 id="heading-event">Event</h3>
<p>As mentioned earlier, events are the outcomes of actions. Unlike the <code>BattleShowdownAction</code>, which only had one action, the <code>BattleShowdownEvent</code> will encompass more than two actions. Why? Because the game's logic dictates that when the user attacks, the boss also counterattacks. This results in three possible outcomes: either the user loses, the boss is defeated, or the battle continues. </p>
<p>However, the third outcome is contingent upon the first two outcomes.<br>Therefore, for the <code>BattleShowdownEvent</code>, you will need to define:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">BattleShowdownEvent</span></span> {
    Attacked {
        id: ActorId,
        character_type: CharacterType,
        name: <span class="hljs-built_in">String</span>,
        player_lives: <span class="hljs-built_in">u32</span>,
        boss_livesL: <span class="hljs-built_in">u32</span>,
    },

    PlayerLost {
        id: ActorId,
        character_type: CharacterType,
        boss_livesL: <span class="hljs-built_in">u32</span>,
        player_lives: <span class="hljs-built_in">u32</span>,
        message: <span class="hljs-built_in">String</span>,
    },

    BossLost {
        character_type: CharacterType,
        player_lives: <span class="hljs-built_in">u32</span>,
        boss_livesL: <span class="hljs-built_in">u32</span>,
        message: <span class="hljs-built_in">String</span>,
    },
}
</code></pre>
<p>You have one action, but there are three possible events, correct? When the user/actor attacks the boss and the boss counterattacks, if either of them is defeated, the "Attacked" event is returned. However, if the player successfully defeats the boss, the "BossLost" event is returned.<br>Now that you have a solid understanding, let's incorporate both the input and output types for the Handle function: <code>type Handle = InOut&lt;BattleShowdownAction, BattleShowdownEvent&gt;;</code>.</p>
<h3 id="heading-defining-state">Defining <code>State</code></h3>
<p>As previously mentioned, the state stores information within your program. For <code>BattleShowdown</code>, the state you'd want to store includes information about the player, the boss, and the current level.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Default, Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BattleShowdownState</span></span> {
    <span class="hljs-keyword">pub</span> player_id: ActorId,
    <span class="hljs-keyword">pub</span> player_character_type: CharacterType,
    <span class="hljs-keyword">pub</span> current_level: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_name: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> boss_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_hit_power: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> boss_hit_power: <span class="hljs-built_in">u32</span>,
}
</code></pre>
<p>Therefore, whenever you call the state function, you should expect to see the result in this format. Now, add the <code>BattleShowdownState</code> to the state in the metadata, like so: <code>type State = Out&lt;BattleShowdownState&gt;;</code>.</p>
<p>With that, the setup is complete. Here is the entire code for the <strong>./io/src/lib.rs</strong> file.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gmeta::{In, InOut, Metadata, Out};
<span class="hljs-keyword">use</span> gstd::{prelude::*, ActorId};

<span class="hljs-comment">// Define the main struct for the BattleShowdown</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BattleShowdown</span></span>;

<span class="hljs-comment">// Implementing Metadata for BattleShowdown</span>
<span class="hljs-keyword">impl</span> Metadata <span class="hljs-keyword">for</span> BattleShowdown {
    <span class="hljs-comment">// Define the type for initialization messages</span>
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Init</span></span> = InOut&lt;InitBattleShowdown, <span class="hljs-built_in">String</span>&gt;;
    <span class="hljs-comment">// Define the type for handle messages</span>
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Handle</span></span> = InOut&lt;BattleShowdownAction, BattleShowdownEvent&gt;;
    <span class="hljs-comment">// Define the type for state messages</span>
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">State</span></span> = Out&lt;BattleShowdownState&gt;;
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Reply</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Others</span></span> = ();
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Signal</span></span> = ();
}

<span class="hljs-comment">// Struct for initializing the BattleShowdown</span>
<span class="hljs-meta">#[derive(Default, Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">InitBattleShowdown</span></span> {
    <span class="hljs-keyword">pub</span> player_id: ActorId,
    <span class="hljs-keyword">pub</span> player_character_type: CharacterType,
    <span class="hljs-keyword">pub</span> player_name: <span class="hljs-built_in">String</span>,
}

<span class="hljs-comment">// Struct representing the state of the BattleShowdown</span>
<span class="hljs-meta">#[derive(Default, Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BattleShowdownState</span></span> {
    <span class="hljs-keyword">pub</span> player_id: ActorId,
    <span class="hljs-keyword">pub</span> player_character_type: CharacterType,
    <span class="hljs-keyword">pub</span> current_level: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_name: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> boss_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_hit_power: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> boss_hit_power: <span class="hljs-built_in">u32</span>,
}

<span class="hljs-comment">// Enum representing different character types</span>
<span class="hljs-meta">#[derive(Debug, Clone, Copy, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">CharacterType</span></span> {
    Warrior,
    Mage,
    Archer,
}

<span class="hljs-comment">// Enum representing different values for player hit power</span>
<span class="hljs-meta">#[derive(Debug, Clone, Copy, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">PlayerHitPowerValue</span></span> {
    X,
    Y,
    Z,
}

<span class="hljs-comment">// Implementing Default for PlayerHitPowerValue</span>
<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Default</span> <span class="hljs-keyword">for</span> PlayerHitPowerValue {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        PlayerHitPowerValue::X
    }
}

<span class="hljs-comment">// Implementing Default for CharacterType</span>
<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Default</span> <span class="hljs-keyword">for</span> CharacterType {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        CharacterType::Warrior
    }
}

<span class="hljs-comment">// Enum representing different actions in the BattleShowdown</span>
<span class="hljs-meta">#[derive(Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">BattleShowdownAction</span></span> {
    Attack {
        character_hit_power_value: PlayerHitPowerValue,
    },
}

<span class="hljs-comment">// Enum representing different events in the BattleShowdown</span>
<span class="hljs-meta">#[derive(Debug, Encode, Decode, TypeInfo)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">BattleShowdownEvent</span></span> {
    Attacked {
        id: ActorId,
        character_type: CharacterType,
        name: <span class="hljs-built_in">String</span>,
        player_lives: <span class="hljs-built_in">u32</span>,
        boss_lives: <span class="hljs-built_in">u32</span>,
    },
    PlayerLost {
        id: ActorId,
        character_type: CharacterType,
        boss_lives: <span class="hljs-built_in">u32</span>,
        player_lives: <span class="hljs-built_in">u32</span>,
        message: <span class="hljs-built_in">String</span>,
    },
    BossLost {
        character_type: CharacterType,
        player_lives: <span class="hljs-built_in">u32</span>,
        boss_lives: <span class="hljs-built_in">u32</span>,
        message: <span class="hljs-built_in">String</span>,
    },
}
</code></pre>
<h3 id="heading-buildrs"><code>Build.rs</code></h3>
<p>Import <code>BattleShowdown</code> to the <strong>build.rs</strong> from your parent directory at <strong>./src/build.rs</strong>. If you encounter an import error, make sure that in your <strong>./cargo.toml</strong>, you're registering <code>battle-showdown-io={path = "io"}</code> there.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> battle_showdown_io::BattleShowdown;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    gear_wasm_builder::build_with_metadata::&lt;BattleShowdown&gt;();
}
</code></pre>
<p>That's it for the <strong>build.rs</strong>, and what it does is to build your project into <code>wasm</code> and then build the <code>metadata</code> for <code>BattleShown</code> for you.</p>
<h3 id="heading-game-logic-implementation-srclibrs">Game Logic Implementation - <code>./src/lib.rs</code></h3>
<p>For this section, I'll write the code below, then I'll explain this as we go. There's going to be a problem I'd want you to solve, which will be about the state.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![no_std]</span>

<span class="hljs-keyword">use</span> gstd::{exec, msg, prelude::*, ActorId};

<span class="hljs-keyword">use</span> battle_showdown_io::*;

<span class="hljs-comment">// Function to generate random number between 1 and 3</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_random_u32</span></span>() -&gt; <span class="hljs-built_in">u32</span> {
    <span class="hljs-keyword">let</span> salt = msg::id();
    <span class="hljs-keyword">let</span> (hash, _num) = exec::random(salt.into()).expect(<span class="hljs-string">"get_random_u32(): random call failed"</span>);
    (<span class="hljs-built_in">u32</span>::from_le_bytes([hash[<span class="hljs-number">0</span>], hash[<span class="hljs-number">1</span>], hash[<span class="hljs-number">2</span>], hash[<span class="hljs-number">3</span>]]) % <span class="hljs-number">3</span>) + <span class="hljs-number">1</span> <span class="hljs-comment">// Generate random number between 1 and 3</span>
}

<span class="hljs-meta">#[derive(Debug, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BattleShowdown</span></span> {
    <span class="hljs-keyword">pub</span> player_id: ActorId,
    <span class="hljs-keyword">pub</span> player_character_type: CharacterType,
    <span class="hljs-keyword">pub</span> current_level: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_name: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> boss_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> character_hit_power_value: PlayerHitPowerValue,
    <span class="hljs-keyword">pub</span> player_hit_power: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> boss_hit_power: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> game_state: <span class="hljs-built_in">String</span>,
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">mut</span> BATTLESHOWNDOWN: <span class="hljs-built_in">Option</span>&lt;BattleShowdown&gt; = <span class="hljs-literal">None</span>;

<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">unsafe</span> <span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">init</span></span>() {
    <span class="hljs-keyword">let</span> init: InitBattleShowdown = msg::load().expect(<span class="hljs-string">"Unable to decode InitBattleShowdown"</span>);

    <span class="hljs-keyword">let</span> battle_showdown = BattleShowdown {
        player_id: msg::source(),
        player_character_type: init.player_character_type,
        player_name: init.player_name,
        boss_lives: <span class="hljs-number">10</span>,
        player_lives: <span class="hljs-number">10</span>,
        ..<span class="hljs-built_in">Default</span>::default()
    };

    BATTLESHOWNDOWN = <span class="hljs-literal">Some</span>(battle_showdown);

    msg::reply_bytes(<span class="hljs-string">"Successfully initialized"</span>, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to initialize successfully."</span>);
}

<span class="hljs-keyword">impl</span> Encode <span class="hljs-keyword">for</span> BattleShowdown {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">encode</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> encoded = <span class="hljs-built_in">Vec</span>::new();

        <span class="hljs-comment">// Encode each field of BattleShowdown struct</span>
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.player_id.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.player_character_type.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.current_level.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.player_lives.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.player_name.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.boss_lives.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.character_hit_power_value.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.player_hit_power.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.boss_hit_power.encode());
        encoded.extend_from_slice(&amp;<span class="hljs-keyword">self</span>.game_state.encode());

        encoded
    }
}

<span class="hljs-keyword">impl</span> BattleShowdown {
    <span class="hljs-comment">// Placeholder for the `attack` method</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">attack</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, _character_hit_power_value: PlayerHitPowerValue) -&gt; BattleShowdownEvent {
        <span class="hljs-comment">// Implement this method according to your game logic</span>
        <span class="hljs-comment">// For now, just returning an empty event</span>

        <span class="hljs-comment">// Calculate total hit power for player based on character type and random values</span>
        <span class="hljs-keyword">let</span> character_hit_power = <span class="hljs-keyword">match</span> &amp;<span class="hljs-keyword">self</span>.player_character_type {
            CharacterType::Warrior =&gt; <span class="hljs-number">4</span>,
            CharacterType::Mage =&gt; <span class="hljs-number">3</span>,
            CharacterType::Archer =&gt; <span class="hljs-number">2</span>,
        };

        <span class="hljs-keyword">let</span> player_hit_power = <span class="hljs-keyword">match</span> &amp;<span class="hljs-keyword">self</span>.character_hit_power_value {
            PlayerHitPowerValue::X =&gt; character_hit_power + get_random_u32(),
            PlayerHitPowerValue::Y =&gt; character_hit_power + get_random_u32(),
            PlayerHitPowerValue::Z =&gt; character_hit_power + get_random_u32(),
        };

        <span class="hljs-comment">// Placeholder for boss attack logic</span>
        <span class="hljs-comment">// Update boss hit power to a random value for each attack</span>
        <span class="hljs-keyword">self</span>.boss_hit_power = get_random_u32();

        <span class="hljs-keyword">self</span>.player_hit_power = player_hit_power;

        <span class="hljs-comment">// Reduce boss's lives based on player's hit power</span>
        <span class="hljs-keyword">self</span>.boss_lives = <span class="hljs-keyword">self</span>.boss_lives.saturating_sub(<span class="hljs-keyword">self</span>.player_hit_power);
        <span class="hljs-comment">// Reduce player's lives based on boss's hit power</span>
        <span class="hljs-keyword">self</span>.player_lives = <span class="hljs-keyword">self</span>.player_lives.saturating_sub(<span class="hljs-keyword">self</span>.boss_hit_power);

        <span class="hljs-comment">// Check if player or boss has lost</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.player_lives == <span class="hljs-number">0</span> {
            <span class="hljs-comment">// Player lost</span>
            <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"Player lost."</span>.to_string();
            <span class="hljs-keyword">return</span> BattleShowdownEvent::PlayerLost {
                id: <span class="hljs-keyword">self</span>.player_id,
                boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
                character_type: <span class="hljs-keyword">self</span>.player_character_type,
                message: <span class="hljs-string">""</span>.to_string(),
                player_lives: <span class="hljs-keyword">self</span>.player_lives,
            };
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.boss_lives == <span class="hljs-number">0</span> {
            <span class="hljs-comment">// Boss lost</span>
            <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"Boss lost."</span>.to_string();
            <span class="hljs-keyword">return</span> BattleShowdownEvent::BossLost {
                boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
                character_type: <span class="hljs-keyword">self</span>.player_character_type,
                player_lives: <span class="hljs-keyword">self</span>.player_lives,
                message: <span class="hljs-string">"You've defeated the boos"</span>.to_string(),
            };
        }

        <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"The games continues."</span>.to_string();
        BattleShowdownEvent::Attacked {
            boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
            character_type: <span class="hljs-keyword">self</span>.player_character_type,
            id: <span class="hljs-keyword">self</span>.player_id,
            name: <span class="hljs-keyword">self</span>.player_name.clone(),
            player_lives: <span class="hljs-keyword">self</span>.player_lives,
        }
    }
}

<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">handle</span></span>() {
    <span class="hljs-keyword">let</span> battle_showdown_action: BattleShowdownAction =
        msg::load().expect(<span class="hljs-string">"Could not load BattleShowdownAction"</span>);
    <span class="hljs-keyword">let</span> battle_showdown = <span class="hljs-keyword">unsafe</span> {
        BATTLESHOWNDOWN
            .as_mut()
            .expect(<span class="hljs-string">"`BattleShowdown` is not initialized."</span>)
    };
    <span class="hljs-keyword">let</span> result: BattleShowdownEvent = <span class="hljs-keyword">match</span> battle_showdown_action {
        BattleShowdownAction::Attack {
            character_hit_power_value,
        } =&gt; battle_showdown.attack(character_hit_power_value),
    };
    msg::reply_bytes(result.encode(), <span class="hljs-number">0</span>)
        .expect(<span class="hljs-string">"Failed to encode or reply with `BattleShowdownEvent`."</span>);
}

<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">state</span></span>() {
    <span class="hljs-keyword">let</span> battle_showdown = <span class="hljs-keyword">unsafe</span> {
        BATTLESHOWNDOWN
            .take()
            .expect(<span class="hljs-string">"Unexpected error in taking state"</span>)
    };

    msg::reply(battle_showdown, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Unable to share the state"</span>);
}
</code></pre>
<p>At first glance this might seem a lot, but it isn't, so don't get too intimidated. Before you start, make sure you understand the whole logic of the game description I gave earlier since you'll be implementing it here.</p>
<p>Above, we have some important functions, <code>struct</code>, and <code>impl</code>, and here is an overview of what they do.</p>
<ol>
<li>With the <code>get_random_u32</code> function, we generated a random number between 1 and 3.</li>
<li>The <code>BattleShowdown</code> struct in the <code>/src/lib.rs</code> represents the main state of the game. It holds information such as player and boss stats, current game level, and game state. The <code>static mut BATTLESHOWNDOWN: Option&lt;BattleShowdown&gt; = None;</code> is a static mutable variable that holds the current state of the game. It's wrapped in an <code>Option</code> to indicate whether the game has been initialized yet or not, which you'll use later in your implementation.</li>
<li><code>unsafe extern "C" fn init()</code> is responsible for initializing the game state when called after the contract has been uploaded. It loads an initialization message, constructs a <code>BattleShowdown</code> instance based on that message, and sets <code>BATTLESHOWNDOWN</code> to <code>Some</code> with the constructed instance.</li>
<li><code>impl Encode for BattleShowdown</code>: this trait is implemented for <code>BattleShowdown</code>, enabling it to be encoded into a byte representation. This is useful for serialization and sending the game state over the network. And there's a way to also implement the trait without creating an <code>impl</code> for <code>BattleShowdown</code>.</li>
<li><code>impl BattleShowdown</code>: this <code>impl</code> for <code>BattleShowdown</code> is where the entire logic happens, and for now, we've only added an <code>attack</code> method for it. It worth noting that we'll be adding more as we continue this project.</li>
<li>So what does the <code>attack</code> method do? Well, The <code>attack</code> method simulates a combat encounter between the player and the boss character in our game. It calculates the hit power for both entities based on character type and randomness, manages their health points accordingly, and generates game events to reflect the outcome of the encounter.</li>
<li><code>extern "C" fn handle()</code>: In our case, the <code>handle</code> function is used to process incoming messages, specifically <code>BattleShowdownAction</code>. So depending on the action perform by the actor, it dispatches a result of the action to the appropriate methods of <code>BattleShowdown</code>, such as <code>attack</code>, and sends back the resulting game events to the actor. Like disccued in the illustration.</li>
<li>And lastly, <code>extern "C" fn state()</code> simply retrieves the current game state represented by <code>BattleShowdown</code> and sends it as a reply.</li>
</ol>
<p>This is the overall explanation to the code in the file. But leaving with this isn't enough for even me. Let's disccus more below.</p>
<h3 id="heading-understanding-theinit">Understanding the<code>init()</code></h3>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BattleShowdown</span></span> {
    <span class="hljs-keyword">pub</span> player_id: ActorId,
    <span class="hljs-keyword">pub</span> player_character_type: CharacterType,
    <span class="hljs-keyword">pub</span> current_level: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> player_name: <span class="hljs-built_in">String</span>,
    <span class="hljs-keyword">pub</span> boss_lives: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> character_hit_power_value: PlayerHitPowerValue,
    <span class="hljs-keyword">pub</span> player_hit_power: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> boss_hit_power: <span class="hljs-built_in">u32</span>,
    <span class="hljs-keyword">pub</span> game_state: <span class="hljs-built_in">String</span>,
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">mut</span> BATTLESHOWNDOWN: <span class="hljs-built_in">Option</span>&lt;BattleShowdown&gt; = <span class="hljs-literal">None</span>;

<span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">unsafe</span> <span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">init</span></span>() {
    <span class="hljs-comment">// Load initialization data</span>
    <span class="hljs-keyword">let</span> init: InitBattleShowdown = msg::load().expect(<span class="hljs-string">"Unable to decode InitBattleShowdown"</span>);

    <span class="hljs-comment">// Create a BattleShowdown instance with initial values</span>
    <span class="hljs-keyword">let</span> battle_showdown = BattleShowdown {
        player_id: msg::source(),
        player_character_type: init.player_character_type,
        player_name: init.player_name,
        boss_lives: <span class="hljs-number">10</span>,
        player_lives: <span class="hljs-number">10</span>,
        ..<span class="hljs-built_in">Default</span>::default()
    };

    <span class="hljs-comment">// Store the BattleShowdown instance</span>
    BATTLESHOWNDOWN = <span class="hljs-literal">Some</span>(battle_showdown);

    <span class="hljs-comment">// Reply to signal successful initialization</span>
    msg::reply_bytes(<span class="hljs-string">"Successfully initialized"</span>, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Failed to initialize successfully."</span>);
}
</code></pre>
<p>The function loads data from an initialization message (<code>InitBattleShowdown</code>) sent by the developer or player. This data includes the player's chosen <code>character type</code> and <code>name</code>. Based on the initialization data, a <code>BattleShowdown</code> instance is created with initial values, which is stored in <code>battle_showdown</code>. </p>
<p>This instance represents the state of the game, including player and boss stats, current level, and game state. The created <code>BattleShowdown</code> instance is stored in the <code>BATTLESHOWNDOWN</code> static variable, allowing the game logic to access and manipulate the game state throughout the gameplay. Finally, a reply message is sent back to the developer or player to indicate successful initialization of the game contract. </p>
<p>This function sets up the initial state of the game, paving the way for further interactions and gameplay logic.</p>
<h3 id="heading-understanding-the-handle">Understanding the <code>handle()</code></h3>
<pre><code class="lang-rust"><span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">handle</span></span>() {
    <span class="hljs-comment">// Load the action from the message</span>
    <span class="hljs-keyword">let</span> battle_showdown_action: BattleShowdownAction =
        msg::load().expect(<span class="hljs-string">"Could not load BattleShowdownAction"</span>);

    <span class="hljs-comment">// Retrieve the current game state</span>
    <span class="hljs-keyword">let</span> battle_showdown = <span class="hljs-keyword">unsafe</span> {
        BATTLESHOWNDOWN
            .as_mut()
            .expect(<span class="hljs-string">"`BattleShowdown` is not initialized."</span>)
    };

    <span class="hljs-comment">// Execute the appropriate action on the game state and get the result</span>
    <span class="hljs-keyword">let</span> result: BattleShowdownEvent = <span class="hljs-keyword">match</span> battle_showdown_action {
        BattleShowdownAction::Attack {
            character_hit_power_value,
        } =&gt; battle_showdown.attack(character_hit_power_value),
    };

    <span class="hljs-comment">// Send back the result as a reply message</span>
    msg::reply_bytes(result.encode(), <span class="hljs-number">0</span>)
        .expect(<span class="hljs-string">"Failed to encode or reply with `BattleShowdownEvent`."</span>);
}
</code></pre>
<p>The <code>handle()</code> function plays a crucial role in processing incoming messages and orchestrating the game's actions. It serves as the bridge between player interactions and the game's internal logic. When invoked, <code>handle()</code> begins by loading the <code>action</code> sent by the player from the message. </p>
<p>This <code>action</code>, encapsulated as <code>BattleShowdownAction</code>, dictates the player's intended move, such as attacking the boss. Next, the function retrieves the current game state from the <code>BATTLESHOWNDOWN</code> variable. This state holds essential information about the player, the boss, and the overall game environment. </p>
<p>With both the action and the game state at hand, <code>handle()</code> proceeds to execute the appropriate action. For instance, if the player's action is an <code>attack</code>, the function triggers the <code>attack()</code> method on the <code>battle_showdown</code> instance. This method calculates the outcome of the player's attack, considering factors like the player's hit power and the boss's remaining health points.</p>
<p>Crucially, the <code>attack()</code> method requires a parameter: <code>character_hit_power_value</code>. This parameter corresponds to the player's choice between three options: <code>X</code>, <code>Y</code>, and <code>Z</code>, each associated with different hit power values as disccused in earlier sections. </p>
<p>Once the <code>action</code> is executed, <code>handle()</code> generates an event, encapsulated as <code>BattleShowdownEvent</code>, reflecting the outcome of the player's move. This event encapsulates important details, such as changes in player and boss health points. Finally, <code>handle()</code> responds to the player by replying with the result of the action as a byte-encoded message. This message contains the updated game state, allowing the player to understand their current situation, including their health status and that of the boss.</p>
<h3 id="heading-understanding-the-impl-battleshowdown-for-attack">Understanding the <code>impl BattleShowdown for attack</code></h3>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> BattleShowdown {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">attack</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, _character_hit_power_value: PlayerHitPowerValue) -&gt; BattleShowdownEvent {
        <span class="hljs-comment">// Calculate total hit power for player based on character type and random values</span>
        <span class="hljs-keyword">let</span> character_hit_power = <span class="hljs-keyword">match</span> &amp;<span class="hljs-keyword">self</span>.player_character_type {
            CharacterType::Warrior =&gt; <span class="hljs-number">4</span>,
            CharacterType::Mage =&gt; <span class="hljs-number">3</span>,
            CharacterType::Archer =&gt; <span class="hljs-number">2</span>,
        };

        <span class="hljs-keyword">let</span> player_hit_power = <span class="hljs-keyword">match</span> &amp;<span class="hljs-keyword">self</span>.character_hit_power_value {
            PlayerHitPowerValue::X =&gt; character_hit_power + get_random_u32(),
            PlayerHitPowerValue::Y =&gt; character_hit_power + get_random_u32(),
            PlayerHitPowerValue::Z =&gt; character_hit_power + get_random_u32(),
        };

        <span class="hljs-comment">// Placeholder for boss attack logic</span>
        <span class="hljs-comment">// Update boss hit power to a random value for each attack</span>
        <span class="hljs-keyword">self</span>.boss_hit_power = get_random_u32();

        <span class="hljs-keyword">self</span>.player_hit_power = player_hit_power;

        <span class="hljs-comment">// Reduce boss's lives based on player's hit power</span>
        <span class="hljs-keyword">self</span>.boss_lives = <span class="hljs-keyword">self</span>.boss_lives.saturating_sub(<span class="hljs-keyword">self</span>.player_hit_power);
        <span class="hljs-comment">// Reduce player's lives based on boss's hit power</span>
        <span class="hljs-keyword">self</span>.player_lives = <span class="hljs-keyword">self</span>.player_lives.saturating_sub(<span class="hljs-keyword">self</span>.boss_hit_power);

        <span class="hljs-comment">// Check if player or boss has lost</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.player_lives == <span class="hljs-number">0</span> {
            <span class="hljs-comment">// Player lost</span>
            <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"Player lost."</span>.to_string();
            <span class="hljs-keyword">return</span> BattleShowdownEvent::PlayerLost {
                id: <span class="hljs-keyword">self</span>.player_id,
                boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
                character_type: <span class="hljs-keyword">self</span>.player_character_type,
                message: <span class="hljs-string">""</span>.to_string(),
                player_lives: <span class="hljs-keyword">self</span>.player_lives,
            };
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.boss_lives == <span class="hljs-number">0</span> {
            <span class="hljs-comment">// Boss lost</span>
            <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"Boss lost."</span>.to_string();
            <span class="hljs-keyword">return</span> BattleShowdownEvent::BossLost {
                boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
                character_type: <span class="hljs-keyword">self</span>.player_character_type,
                player_lives: <span class="hljs-keyword">self</span>.player_lives,
                message: <span class="hljs-string">"You've defeated the boss"</span>.to_string(),
            };
        }

        <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"The game continues."</span>.to_string();
        <span class="hljs-comment">// Return event indicating attack occurred</span>
        BattleShowdownEvent::Attacked {
            boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
            character_type: <span class="hljs-keyword">self</span>.player_character_type,
            id: <span class="hljs-keyword">self</span>.player_id,
            name: <span class="hljs-keyword">self</span>.player_name.clone(),
            player_lives: <span class="hljs-keyword">self</span>.player_lives,
        }
    }
}
</code></pre>
<p>The <code>attack</code> method within the <code>BattleShowdown</code> implementation simulates a pivotal moment in the game: a combat encounter between the player and the boss character. </p>
<p>Here's how it works:</p>
<p>Firstly, the method calculates the total hit power for the player based on their character type (<code>character_hit_power</code>) and randomness (<code>player_hit_power</code>). Different character types (<code>Warrior</code>, <code>Mage</code>, or <code>Archer</code>) have different base hit powers. </p>
<p>Next, a random hit power value is added to the character's base hit power. This adds an element of unpredictability to each attack. The method then updates the boss's hit power (<code>self.boss_hit_power = get_random_u32();</code>) to a random value, representing the boss's retaliatory strike against the player.</p>
<p>After calculating the hit powers, the method reduces the boss's lives based on the player's hit power and vice versa, updating their respective health points accordingly.</p>
<pre><code class="lang-rust">        <span class="hljs-comment">// Reduce boss's lives based on player's hit power</span>
        <span class="hljs-keyword">self</span>.boss_lives = <span class="hljs-keyword">self</span>.boss_lives.saturating_sub(<span class="hljs-keyword">self</span>.player_hit_power);
        <span class="hljs-comment">// Reduce player's lives based on boss's hit power</span>
        <span class="hljs-keyword">self</span>.player_lives = <span class="hljs-keyword">self</span>.player_lives.saturating_sub(<span class="hljs-keyword">self</span>.boss_hit_power);
</code></pre>
<p>The game state is then checked to determine if either the player or the boss has lost the battle. If the player's health points reaches zero, the game state is updated to indicate that the player has lost. Conversely, if the boss's health points reach zero, the game state reflects the boss's defeat.</p>
<pre><code class="lang-rust">        <span class="hljs-comment">// Check if player or boss has lost</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.player_lives == <span class="hljs-number">0</span> {
            <span class="hljs-comment">// Player lost</span>
            <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"Player lost."</span>.to_string();
            <span class="hljs-keyword">return</span> BattleShowdownEvent::PlayerLost {
                id: <span class="hljs-keyword">self</span>.player_id,
                boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
                character_type: <span class="hljs-keyword">self</span>.player_character_type,
                message: <span class="hljs-string">""</span>.to_string(),
                player_lives: <span class="hljs-keyword">self</span>.player_lives,
            };
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.boss_lives == <span class="hljs-number">0</span> {
            <span class="hljs-comment">// Boss lost</span>
            <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"Boss lost."</span>.to_string();
            <span class="hljs-keyword">return</span> BattleShowdownEvent::BossLost {
                boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
                character_type: <span class="hljs-keyword">self</span>.player_character_type,
                player_lives: <span class="hljs-keyword">self</span>.player_lives,
                message: <span class="hljs-string">"You've defeated the boss"</span>.to_string(),
            };
        }

        <span class="hljs-keyword">self</span>.game_state = <span class="hljs-string">"The game continues."</span>.to_string();
        <span class="hljs-comment">// Return event indicating attack occurred</span>
        BattleShowdownEvent::Attacked {
            boss_lives: <span class="hljs-keyword">self</span>.boss_lives,
            character_type: <span class="hljs-keyword">self</span>.player_character_type,
            id: <span class="hljs-keyword">self</span>.player_id,
            name: <span class="hljs-keyword">self</span>.player_name.clone(),
            player_lives: <span class="hljs-keyword">self</span>.player_lives,
        }
</code></pre>
<p>Finally, if neither the player nor the boss has lost, the game state is updated to indicate that the battle continues.</p>
<h3 id="heading-understanding-the-state">Understanding the <code>State()</code></h3>
<pre><code class="lang-rust"><span class="hljs-meta">#[no_mangle]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">state</span></span>() {
    <span class="hljs-keyword">let</span> battle_showdown = <span class="hljs-keyword">unsafe</span> {
        BATTLESHOWNDOWN
            .take()
            .expect(<span class="hljs-string">"Unexpected error in taking state"</span>)
    };

    msg::reply(battle_showdown, <span class="hljs-number">0</span>).expect(<span class="hljs-string">"Unable to share the state"</span>);
}
</code></pre>
<p>For this instance there's nothing more to share, it retrieves the current state of the game, represented by the <code>BattleShowdown</code> struct, from a static mutable variable <code>BATTLESHOWNDOWN</code>, and sends a reply message containing the game state back to the player. If there is an error sending the reply message, it will panic with an error message indicating the inability to share the state.</p>
<p>And that's that for this project. There are some exciting features you can consider if you want to extend this project. Imagine the possibility of resetting the game state, accommodating multiple players, or even resetting the game for a single player. And for the ambitious, you could even tackle the challenge of resetting the state for the entire game. These additions can offer new dimensions to the project and provide excellent opportunities for you to challenge yourself.</p>
<h3 id="heading-short-recording-of-what-weve-built-demo">Short Recording of what we've built - Demo</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.loom.com/share/590d685f311f46c386943c41816dbf83?sid=e99d4948-f0ab-486d-a5fa-98fbcdfe3fe3">https://www.loom.com/share/590d685f311f46c386943c41816dbf83?sid=e99d4948-f0ab-486d-a5fa-98fbcdfe3fe3</a></div>
<p>In the video you could see I added another method for resetting everything back to it inital state. Though I didn't guide you through the process of doing that, you should know it is easy to implement, and I've added <a target="_blank" href="https://github.com/rockyessel/battle-showdown">a GitHub repository</a> for the entire code.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>As demonstrated, developing a smart contract with Gear Protocol becomes straightforward once you grasp the communication message concepts. By following the steps outlined, you can start building your own projects with confidence.</p>
<p>While this article didn't delve into handling transactions such as token transfers, minting, or NFTs, I will cover these topics in a future article.</p>
<p>For now, you can explore the repository of the project we built together: <a target="_blank" href="https://github.com/rockyessel/battle-showdown">Battle-Showdown</a>, and if you have any question to ask, feel free to reach @rockyessel on X.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Rust Tutorial – Learn Advanced Iterators & Pattern Matching by Building a JSON Parser ]]>
                </title>
                <description>
                    <![CDATA[ Iterators and match patterns are two of the most used language features in Rust. If you have written any real world application, big or small, chances are that you've already used these, whether knowingly or unknowingly. In this tutorial, I aim to he... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rust-tutorial-build-a-json-parser/</link>
                <guid isPermaLink="false">66bb579d7b4b3dfb68522740</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Anshul Sanghi ]]>
                </dc:creator>
                <pubDate>Wed, 29 May 2024 10:45:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/JSON-Parser-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Iterators and match patterns are two of the most used language features in Rust. If you have written any real world application, big or small, chances are that you've already used these, whether knowingly or unknowingly.</p>
<p>In this tutorial, I aim to help you understand how they actually work, the many ways they're usually used, and how powerful they are by writing a JSON parser that heavily uses these features.</p>
<h2 id="heading-disclaimer">Disclaimer</h2>
<p>The goal of this tutorial is to create a real-world library that extensively uses match patterns and iterators. The goal is not to write a performant or fully-compliant JSON parser.</p>
<p>If you're very familiar with JSON, you will notice many things that are missing in this code, the biggest one being error handling when invalid tokens are encountered, and giving feedback to the user or helpful suggestions on what's wrong with the JSON.</p>
<p>This program also doesn't handle escape characters and sequences within string literals, for example. The code, for the most part, assumes that you have a valid JSON.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Although this tutorial can be consumed by Rust programmers of any experience, previous experience or understanding of basic iterators and match patterns in Rust is helpful.</p>
<p>It is also assumed that you're familiar with the most basic Rust concepts such as <code>traits</code>, <code>structs</code>, <code>enums</code>, <code>for</code> loops, <code>impl</code> blocks, and so on. The tutorial does introduce you to <code>iterator</code> and <code>match</code>, so you don't need to be familiar with those to benefit from this tutorial.</p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-are-iterators-in-rust">What are Iterators in Rust?</a><ol>
<li><a class="post-section-overview" href="#heading-how-to-implement-iterators-in-rust">How to implement iterators in Rust</a></li>
<li><a class="post-section-overview" href="#heading-what-are-peekable-iterators-in-rust">What are peekable iterators in Rust?</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-what-is-the-match-statement-in-rust">What is The Match Statement in Rust?</a><ol>
<li><a class="post-section-overview" href="#heading-how-to-use-iterators-in-match-statements-in-rust">How to use iterators in match statements in Rust</a></li>
<li><a class="post-section-overview" href="#heading-what-are-match-guards-in-rust">What are match guards in Rust?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-binding-in-rust">What is binding in Rust?</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-json-parser-stage-1-reader">How to Build a JSON Parser – Stage 1: Reader</a><ol>
<li><a class="post-section-overview" href="#heading-what-is-the-utf-8-byte-encoding">What is the UTF-8 byte encoding?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-read-the-data">How to read the data</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-iterator-for-jsonreader">How to implement the iterator for JsonReader</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-json-parser-stage-2-prepare-intermediate-data-types">How to Build a JSON Parser – Stage 2: Prepare Intermediate Data Types</a><ol>
<li><a class="post-section-overview" href="#heading-the-value-type">The value type</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-helpful-conversion-methods">How to add helpful conversion methods</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-json-parser-stage-3-tokenization">How to Build a JSON Parser – Stage 3: Tokenization</a><ol>
<li><a class="post-section-overview" href="#heading-how-to-define-expected-valid-tokens">How to define expected valid tokens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-tokenizer-struct">How to implement the tokenizer struct</a></li>
<li><a class="post-section-overview" href="#heading-how-to-tokenize-an-iterator-of-characters">How to tokenize an iterator of characters</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-string-tokens">How to parse string tokens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-number-tokens">How to parse number tokens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-boolean-tokens">How to parse boolean tokens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-null-literal">How to parse Null Literal</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-delimiters">How to parse delimiters</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-a-terminating-character">How to parse a terminating character</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-json-parser-stage-4-from-tokens-to-value">How to Build a JSON Parser – Stage 4: From Tokens To Value</a><ol>
<li><a class="post-section-overview" href="#heading-how-to-parse-primitives">How to parse primitives</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-arrays">How to parse arrays</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-objects">How to parse objects</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-json-parser">How to Use the JSON parser</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-what-are-iterators-in-rust">What are Iterators in Rust?</h2>
<p>Iterators are not a new concept, neither are they specific to Rust. It's both a pattern that is also implemented as an object in most programming languages for working with lists (such as arrays or vectors) or collections (such as HashMaps) that allows you to traverse through these data types and act on individual entries in them.</p>
<p>In Rust, iterators are a very powerful feature. The official Rust book describes it as:</p>
<blockquote>
<p>The iterator pattern allows you to perform some task on a sequence of items in turn. An iterator is responsible for the logic of iterating over each item and determining when the sequence has finished. When you use iterators, you don’t have to reimplement that logic yourself.</p>
<p>In Rust, iterators are <em>lazy</em>, meaning they have no effect until you call methods that consume the iterator to use it up.</p>
</blockquote>
<p>An iterator is an object that facilitates sequential access to the elements of a collection, like an array or a vector, without exposing the implementation details.</p>
<h3 id="heading-how-to-implement-iterators-in-rust">How to implement iterators in Rust</h3>
<p>Iterators are implemented in Rust using a collection of traits, the most basic of which is the <code>Iterator</code> trait. It is implemented for all collections in the standard library, and can be implemented for custom types as well. </p>
<blockquote>
<p>It requires the implementation of a single method: <code>next()</code>. This method returns an <code>Option&lt;T&gt;</code>, where <code>T</code> is the type of element the iterator is for. When <code>next()</code> is called (the call is implicit in most cases and you generally use higher level methods), the iterator produces <code>Some(value)</code> for the next element in the sequence or <code>None</code> when the iteration is complete.  In most cases, whether the value is <code>Some</code> or <code>None</code> is also implicit.</p>
</blockquote>
<p>For example, anything that implements the <code>Iterator</code> trait, can be used with a for loop directly, which implicitly handles both calling the <code>next</code> method as well as handling whether the value is <code>Some</code> or <code>None</code>. A <code>None</code> value triggers the loop to end. This is true for the built-in types such as arrays, slices, vectors, and hash-maps as well.</p>
<p>For example, let's implement the iterator trait on a simple custom type. You need to store the current state of the iterator in the type. You can also store any additional information you need. Here, we just need to know the max number after which the iteration should end:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::iter::<span class="hljs-built_in">Iterator</span>;

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">CustomType</span></span> {
    current: <span class="hljs-built_in">usize</span>,
    max: <span class="hljs-built_in">usize</span>,
}

<span class="hljs-keyword">impl</span> CustomType {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(max: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">Self</span> {
            current: <span class="hljs-number">0</span>,
            max,
        }
    }
}

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Iterator</span> <span class="hljs-keyword">for</span> CustomType {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Item</span></span> = <span class="hljs-built_in">usize</span>;

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">next</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;Self::Item&gt; {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.current &gt;= <span class="hljs-keyword">self</span>.max {
            <span class="hljs-literal">None</span>
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">self</span>.current += <span class="hljs-number">1</span>;
            <span class="hljs-literal">Some</span>(<span class="hljs-keyword">self</span>.current)
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> custom = CustomType::new(<span class="hljs-number">10</span>);

    <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> custom {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Item is {item}"</span>);
    }
}
</code></pre>
<pre><code class="lang-shell"># Output

Item is 1
Item is 2
Item is 3
Item is 4
Item is 5
Item is 6
Item is 7
Item is 8
Item is 9
Item is 10
</code></pre>
<p>Rust iterators are also lazily evaluated, meaning they do not do anything unless they're used. This means that until you actually want to get the next value and do something with it, it won't even compute what the next value is.</p>
<p>This also means that if you have a chain of operations, such as a map and a filter, each item will go through the entire pipeline first, before the code processes the next item. This is unlike many other languages which support <code>map</code> and <code>filter</code> as methods, where first the entire map will be processed for all operations, and then the filter will be performed.</p>
<p>If you think about it carefully, iterators allow us to write parallel processing pipelines in a much easier way than the counterpart.</p>
<p>Since <code>Iterator</code> is just a trait, it allows for iterators to be chain-able and transformable to other iterators using various adapter methods (either the ones in standard library, or the ones that you can implement yourself).</p>
<h3 id="heading-what-are-peekable-iterators-in-rust">What are peekable iterators in Rust?</h3>
<p>Many times, you need the ability to know what the next element will be for deciding what to do, without actually modifying the iterator state for it to move to the next element. This is especially necessary when working with an iterator of tokens for parsing, as we'll do later in this tutorial.</p>
<p>This is where the <code>Peekable</code> struct comes in. You can convert any iterator into a peekable iterator by calling the <code>peekable</code> method on it.</p>
<p>Let's take the previous example and see how peekable works in action:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::iter::<span class="hljs-built_in">Iterator</span>;

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">CustomType</span></span> {
    current: <span class="hljs-built_in">usize</span>,
    max: <span class="hljs-built_in">usize</span>,
}

<span class="hljs-keyword">impl</span> CustomType {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(max: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">Self</span> {
            current: <span class="hljs-number">0</span>,
            max,
        }
    }
}

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Iterator</span> <span class="hljs-keyword">for</span> CustomType {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Item</span></span> = <span class="hljs-built_in">usize</span>;

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">next</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;Self::Item&gt; {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.current &gt;= <span class="hljs-keyword">self</span>.max {
            <span class="hljs-literal">None</span>
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">self</span>.current += <span class="hljs-number">1</span>;
            <span class="hljs-literal">Some</span>(<span class="hljs-keyword">self</span>.current)
        }
    }
}

<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> custom = CustomType::new(<span class="hljs-number">2</span>).peekable();

    <span class="hljs-keyword">let</span> first = custom.peek();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{first:?}"</span>);

    <span class="hljs-keyword">let</span> second = custom.next();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{second:?}"</span>);

    <span class="hljs-keyword">let</span> third = custom.next();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{third:?}"</span>);

    <span class="hljs-keyword">let</span> fourth = custom.next();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{fourth:?}"</span>);
}
</code></pre>
<pre><code class="lang-shell"># Output

Some(1)
Some(1)
Some(2)
None
</code></pre>
<p>I also wanted to show you how you can use iterators manually without a for loop, which is why you see all the calls to <code>next</code> method, and also that it returns <code>Option</code> instead of the value directly.</p>
<p>Also notice that the <code>first</code> and <code>second</code> variables are both <code>Some(1)</code>. This is because we called <code>peek</code> the first time which returned the first element but without modifying the state of the iterator.</p>
<h2 id="heading-what-is-the-match-statement-in-rust">What is The Match Statement in Rust?</h2>
<p>The match statement is a pattern-matching syntax in Rust that allows you to conditionally run code based on complex conditions in a concise syntax. You can think of it as a <code>switch</code> statement from other languages, but on steroids.</p>
<p>A very simple example of a match statement is:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> value = <span class="hljs-literal">true</span>;

<span class="hljs-keyword">match</span> value {
    <span class="hljs-literal">true</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value is true"</span>)
    },
    <span class="hljs-literal">false</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value is false"</span>)
    }
}
</code></pre>
<p>The various conditions defined above, namely <code>true</code> and <code>false</code>, are known as branches. Each branch can have a single match, multiple matches separated by the pipe <code>|</code> operator, and ranges. They also can have <code>guards</code> and <code>binding</code> for each arm. Let's see what each of these mean:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Multiple conditions per branch</span>

<span class="hljs-keyword">let</span> value = <span class="hljs-string">"some_string"</span>;

<span class="hljs-keyword">match</span> value {
    <span class="hljs-string">"some_string1"</span> | <span class="hljs-string">"some_string2"</span> | <span class="hljs-string">"some_string3"</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Bad match"</span>);
    }
    <span class="hljs-string">"some_string"</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Good match"</span>);
    }
    _ =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"No match"</span>);
    }
}
</code></pre>
<p>Notice the <code>_</code> branch in the above example. Match statements require you to cover all possible cases. In the first example, since the value was a boolean, there were only two possible values, <code>true</code> and <code>false</code>. This is why in the first case, we  already covered all possible values.</p>
<p>In the 2nd example however, the value we're matching against is a string ( <code>&amp;str</code> to be more precise). A string can be any value. It's impossible to write a match statement that can ever cover all possible cases for this example. Good thing is, Rust has a special matcher <code>_</code> that matches any value. </p>
<p>If you're experienced with JavaScript or C (or many other languages that have the traditional <code>switch</code> syntax), <code>_</code> is equivalent to the <code>default</code> case in <code>switch</code>, but you don't need to use <code>_</code>, you can also bind it to a variable and handle it differently. We'll see how to do this shortly.</p>
<h3 id="heading-how-to-use-iterators-in-match-statements-in-rust">How to use iterators in match statements in Rust</h3>
<p>A match statement allows you to use iterators as branches. A successful match occurs if the value being matched is one of the values in the iterator. For example, say you are matching if a <code>char</code> type is a digit or not. You can write a simple iterator of characters that contains all the digit characters and use that as a branch:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> value: <span class="hljs-built_in">char</span> = <span class="hljs-string">'5'</span>;

<span class="hljs-keyword">match</span> value {
    <span class="hljs-string">'0'</span>..=<span class="hljs-string">'9'</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Character is a digit"</span>);
    }
    _ =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Character is not a digit"</span>);
    }
}
</code></pre>
<p>The above example will print "Character is a digit". If you're not familiar with the <code>..=</code> syntax, it's a shorthand to create iterators over a range. In the example above, the iterator starts at <code>'0'</code> character and ends at <code>'9'</code> character, including all of the characters in between.</p>
<p>You can also use <code>1..5</code> to create a iterator over the range between 1 and 5 but excluding 5, so that the iterator will contain <code>1, 2, 3, 4</code>.</p>
<p>You can also use a variable that holds the iterator as the value, meaning that the iterators do not need to be created inline:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> list = <span class="hljs-built_in">vec!</span>[<span class="hljs-string">"1, 2"</span>, <span class="hljs-string">"3, 4"</span>].iter();
    <span class="hljs-keyword">let</span> value = <span class="hljs-string">"3, 4"</span>;

    <span class="hljs-keyword">match</span> value {
        list =&gt; {
            <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Matched"</span>);
        }
        _ =&gt; {
            <span class="hljs-built_in">println!</span>(<span class="hljs-string">"No matches"</span>);
        }
    }
</code></pre>
<p>Note that the example calls <code>.iter()</code> on the vec to store the iterator in <code>list</code> variable and not the vector. Match arms cannot have method calls, so it's important to convert the value to an iterator outside of the match statement.</p>
<h3 id="heading-what-are-match-guards-in-rust">What are match guards in Rust?</h3>
<p>Guards in match statements are additional conditions for a particular branch that the branch must satisfy to consider a successful match. For example, if you want to match over a range of numbers, but also match on whether they're odd or even, match guards can come in handy.</p>
<p>The syntax is also pretty intuitive. It is of the form <code>&lt;pattern&gt; if &lt;condition&gt; =&gt; {}</code>.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> value: <span class="hljs-built_in">u8</span> = <span class="hljs-number">5</span>;

<span class="hljs-keyword">match</span> value {
    <span class="hljs-number">0</span>..=<span class="hljs-number">9</span> <span class="hljs-keyword">if</span> value % <span class="hljs-number">2</span> == <span class="hljs-number">0</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value is even"</span>);
    }
    <span class="hljs-number">0</span>..=<span class="hljs-number">9</span> <span class="hljs-keyword">if</span> value % <span class="hljs-number">2</span> == <span class="hljs-number">1</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value is odd"</span>);
    }
    _ =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Unexpected value"</span>);
    }
}
</code></pre>
<p>The above code will print "Value is odd".</p>
<h3 id="heading-what-is-binding-in-rust">What is binding in Rust?</h3>
<p>Binding allows you to store values in variables that can be used within the branch where the binding is present. It's basically assigning variables to certain parts of the pattern. </p>
<h4 id="heading-pattern-binding">Pattern Binding</h4>
<p>A very simple example is binding the catch-all pattern to a variable instead of ignoring its value using <code>_</code>.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> value: <span class="hljs-built_in">u8</span> = <span class="hljs-number">5</span>;

<span class="hljs-keyword">match</span> value {
    <span class="hljs-number">0</span>..=<span class="hljs-number">9</span> <span class="hljs-keyword">if</span> value % <span class="hljs-number">2</span> == <span class="hljs-number">0</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value is even"</span>);
    }
    <span class="hljs-number">0</span>..=<span class="hljs-number">9</span> <span class="hljs-keyword">if</span> value % <span class="hljs-number">2</span> == <span class="hljs-number">1</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value is odd"</span>);
    }
    other_value =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Unexpected value: {other_value}"</span>);
    }
}
</code></pre>
<p>Notice that in this example, we used the variable <code>other_value</code> to bind the value of <code>value</code> in the last pattern, which is a catch-all if it doesn't match any of the previous patterns. We can then use the variable in logic for that arm. Here we just print it the console.</p>
<p>Some other examples of binding are:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> value: <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">i32</span>&gt; = <span class="hljs-literal">Some</span>(<span class="hljs-number">43</span>);

<span class="hljs-keyword">match</span> value {
    <span class="hljs-literal">Some</span>(matched_value) =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"The value is {matched_value}"</span>),
    <span class="hljs-literal">None</span> =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"There is no value"</span>)
}
</code></pre>
<p>In this example, we bound the value within the <code>Some</code> pattern for storing the inner value of the option, and use it in our logic.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Person</span></span> {
    name: <span class="hljs-built_in">String</span>,
    age: <span class="hljs-built_in">u32</span>,
}

<span class="hljs-keyword">let</span> value: <span class="hljs-built_in">Option</span>&lt;Person&gt; = <span class="hljs-literal">Some</span>(Person {
    name: <span class="hljs-string">"Name"</span>.to_string(),
    age: <span class="hljs-number">23</span>,
});

<span class="hljs-keyword">match</span> value {
    <span class="hljs-literal">Some</span>(Person { name: person_name, age }) =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{person_name} is {age} years old"</span>);
    },
    <span class="hljs-literal">None</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"The value is empty"</span>);
    }
}
</code></pre>
<p>We see two different types of binding in this example. The first is assigning a different name to a struct field by destructuring it ( <code>name</code> field), and the other is using the same name as the name of the field ( <code>age</code> field).</p>
<h4 id="heading-the-binding">The <code>@</code> Binding</h4>
<p>The official Rust book describes it as:</p>
<blockquote>
<p>The at operator @ lets us create a variable that holds a value at the same time as we’re testing that value for a pattern match.</p>
</blockquote>
<p>In our example of pattern matching against a range of values, or against an iterator, we can bind the matched value to a variable using this syntax to use it within that branch:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> value: <span class="hljs-built_in">u8</span> = <span class="hljs-number">5</span>;

<span class="hljs-keyword">match</span> value {
    digit @ <span class="hljs-number">0</span>..=<span class="hljs-number">9</span> =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"The matched value is {digit}"</span>);
    }
    _ =&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Unexpected value"</span>);
    }
}
</code></pre>
<p>Here we are binding the matched value from the iterator to the <code>digit</code> variable, that we then use within the branch to read the actual value.</p>
<h2 id="heading-how-to-build-a-json-parser-stage-1-reader">How to Build a JSON Parser – Stage 1: Reader</h2>
<p>Before we can parse incoming JSON data, we need to be able to read it in a way which facilitates parsing it. To be able to tokenize the incoming JSON, we need to analyse each character as they come in, and based on whether they represent a literal value, or a delimiter, (or an invalid value), decide what to do with them as well as subsequent characters.</p>
<p>This is a really good use case for using a combination of iterators and Rust's match syntax.</p>
<p>Our reader needs to hold two pieces of data. A buffered reader using which we can iterate over the input, and a <code>character_buffer</code>, which will hold the current character being decoded. </p>
<p>At this point, you may ask why we need to hold the character buffer in the reader and the reason is that JSON is UTF-8 encoded.</p>
<h3 id="heading-what-is-the-utf-8-byte-encoding">What is the UTF-8 byte encoding?</h3>
<p>A UTF-8 character can be anywhere between 1 byte to 4 bytes long. We need to be able to parse all of the valid characters because the JSON spec supports these characters. This means that JSON characters can be either of 1-byte, 2-bytes, 3-bytes or 4-bytes long.</p>
<p>For each iteration, we need to read 4 bytes at a time, decide how many characters the 4 bytes contain (for example, these 4 bytes can contain 4 1-byte characters), finish iterating over them and then move on to the reading next 4 bytes and repeating the process. To store this intermediary piece of information, we need the character buffer.</p>
<p>It is also possible that we only have part of the character in the current 4 byte. For example, if you consider 2 1-byte characters followed by 1 3-byte character like <code>23€</code>, the first 4 bytes will contain 2 valid characters and only part of the next valid character. You also need to be able to handle this, which will involve rewinding the iterator.</p>
<p>It's possible to handle this in a way where we do not need allocations, and for performance reasons it's in fact better to do so. But I will leave that to you as a reader to think about how to implement it in this case, as it is not the focus of this article.</p>
<p>I hope that it's now clear why we iterators are the best tool for the job here.</p>
<h3 id="heading-how-to-read-the-data">How to read the data</h3>
<p>We are going to support two different readers. One is directly from a buffered reader (which is most commonly created from a file), and the other is from a iterator over bytes.</p>
<p>These are going to be pretty straightforward. For reading from a file, you need to create a buffered cursor over the underlying file data:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> file = File::create(<span class="hljs-string">"dummy.json"</span>).unwrap();
<span class="hljs-keyword">let</span> reader = BufReader::new(file);
</code></pre>
<p>Let's start by implementing the JSON Reader struct and these methods on it:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/reader.rs</span>

<span class="hljs-keyword">use</span> std::collections::VecDeque;
<span class="hljs-keyword">use</span> std::io::{BufReader, Cursor, Read, Seek};
<span class="hljs-keyword">use</span> std::<span class="hljs-built_in">str</span>::from_utf8;

<span class="hljs-comment">/// A struct that handles reading input data to be parsed and</span>
<span class="hljs-comment">/// provides an iterator over said data character-by-character.</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">JsonReader</span></span>&lt;T&gt;
<span class="hljs-keyword">where</span>
    T: Read + Seek,
{
    <span class="hljs-comment">/// A reference to the input data, which can be anything</span>
    <span class="hljs-comment">/// that implements [`Read`]</span>
    reader: BufReader&lt;T&gt;,

    <span class="hljs-comment">/// A character buffer that holds queue of characters to</span>
    <span class="hljs-comment">/// be used by the iterator.</span>
    <span class="hljs-comment">///</span>
    <span class="hljs-comment">/// This is necessary because UTF-8 can be 1-4 bytes long.</span>
    <span class="hljs-comment">/// Because of this, the reader always reads 4 bytes at a </span>
    <span class="hljs-comment">/// time. We then iterate over "characters", irrespective of </span>
    <span class="hljs-comment">/// whether they are 1 byte long, or 4.</span>
    <span class="hljs-comment">///</span>
    <span class="hljs-comment">/// A [`VecDeque`] is used instead of a normal vector </span>
    <span class="hljs-comment">/// because characters need to be read out from the start </span>
    <span class="hljs-comment">/// of the buffer.</span>
    character_buffer: VecDeque&lt;<span class="hljs-built_in">char</span>&gt;,
}

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonReader&lt;T&gt;
<span class="hljs-keyword">where</span>
    T: Read + Seek,
{
    <span class="hljs-comment">/// Create a new [`JsonReader`] that reads from a file</span>
    <span class="hljs-comment">///</span>
    <span class="hljs-comment">/// # Examples</span>
    <span class="hljs-comment">///</span>
    <span class="hljs-comment">///</span>
</code></pre>
<p>    /// use std::fs::File;
    /// use std::io::BufReader;
    /// use json_parser::reader::JsonReader;
    ///
    /// let file = File::create("dummy.json").unwrap();
    /// let reader = BufReader::new(file);
    ///
    /// let json_reader = JsonReader::new(reader);
    /// ```
    pub fn new(reader: BufReader) -&gt; Self {
        JsonReader {
            reader,
            character_buffer: VecDeque::with_capacity(4),
        }
    }</p>
<p>    /// Create a new [<code>JsonReader</code>] that reads from a given byte stream
    ///
    /// # Examples
    ///
    /// <code>/// use std::io::{BufReader, Cursor};
    /// use json_parser::reader::JsonReader;
    ///
    /// let input_json_string = r#"{"key1":"value1","key2":"value2"}"#;
    ///
    /// let json_reader = JsonReader::&lt;Cursor&lt;&amp;'static [u8]&gt;&gt;::from_bytes(input_json_string.as_bytes());
    ///</code></p>
<p>    #[must_use]
    pub fn from_bytes(bytes: &amp;[u8]) -&gt; JsonReader&gt; {
        JsonReader {
            reader: BufReader::new(Cursor::new(bytes)),
            character_buffer: VecDeque::with_capacity(4),
        }
    }
}</p>
<pre><code>
### How to implement the iterator <span class="hljs-keyword">for</span> <span class="hljs-string">`JsonReader`</span>

Next, you are going to need to implement the <span class="hljs-string">`Iterator`</span> trait on <span class="hljs-built_in">this</span> <span class="hljs-string">`JSONReader`</span> which will facilitate parsing.

First, <span class="hljs-keyword">if</span> the character buffer isn<span class="hljs-string">'t empty already, you can return the first character in buffer from iterator:

```rust
if !self.character_buffer.is_empty() {
    return self.character_buffer.pop_front();
}</span>
</code></pre><p>If it is empty, you need to create a new buffer and read into that buffer from the reader:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> utf8_buffer = [<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>];
<span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.reader.read(&amp;<span class="hljs-keyword">mut</span> utf8_buffer);
</code></pre>
<p>Here, you are creating a new array of size 4, and you'll be reading 4 bytes into it from the reader. </p>
<p>Next, you need to parse it as UTF-8. Rust provides you with a <code>from_utf8</code> function that will try to parse the given bytes as UTF-8. It returns a string containing parsed characters if it was valid. </p>
<p>It returns an error with number of invalid bytes as part of the error information, which you can use to backtrack the reader to only retain the valid characters, and try the next 4 characters from the point of failure.</p>
<p>If that didn't make too much sense, looking at the code will make things clear:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">match</span> from_utf8(&amp;utf8_buffer) {
    <span class="hljs-literal">Ok</span>(string) =&gt; {
        <span class="hljs-keyword">self</span>.character_buffer = string.chars().collect();
        <span class="hljs-keyword">self</span>.character_buffer.pop_front()
    }
    <span class="hljs-literal">Err</span>(error) =&gt; {
        <span class="hljs-comment">// Read valid bytes, and rewind the buffered reader for </span>
        <span class="hljs-comment">// the remaining bytes so that they can be read again in the</span>
        <span class="hljs-comment">// next iteration.</span>

        <span class="hljs-keyword">let</span> valid_bytes = error.valid_up_to();
        <span class="hljs-keyword">let</span> string = from_utf8(&amp;utf8_buffer[..valid_bytes]).unwrap();

        <span class="hljs-keyword">let</span> remaining_bytes = <span class="hljs-number">4</span> - valid_bytes;

        <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.reader.seek_relative(-(remaining_bytes <span class="hljs-keyword">as</span> <span class="hljs-built_in">i64</span>));

        <span class="hljs-comment">// Collect the valid characters into character_buffer</span>
        <span class="hljs-keyword">self</span>.character_buffer = string.chars().collect();

        <span class="hljs-comment">// Return the first character from character_buffer</span>
        <span class="hljs-keyword">self</span>.character_buffer.pop_front()
    }
}
</code></pre>
<p>Here's the complete implementation of the <code>Iterator</code> trait:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/reader.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; <span class="hljs-built_in">Iterator</span> <span class="hljs-keyword">for</span> JsonReader&lt;T&gt;
<span class="hljs-keyword">where</span>
    T: Read + Seek,
{
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Item</span></span> = <span class="hljs-built_in">char</span>;

    <span class="hljs-meta">#[allow(clippy::cast_possible_wrap)]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">next</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;Self::Item&gt; {
        <span class="hljs-keyword">if</span> !<span class="hljs-keyword">self</span>.character_buffer.is_empty() {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>.character_buffer.pop_front();
        }

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> utf8_buffer = [<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>];
        <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.reader.read(&amp;<span class="hljs-keyword">mut</span> utf8_buffer);

        <span class="hljs-keyword">match</span> from_utf8(&amp;utf8_buffer) {
            <span class="hljs-literal">Ok</span>(string) =&gt; {
                <span class="hljs-keyword">self</span>.character_buffer = string.chars().collect();
                <span class="hljs-keyword">self</span>.character_buffer.pop_front()
            }
            <span class="hljs-literal">Err</span>(error) =&gt; {
                <span class="hljs-comment">// Read valid bytes, and rewind the buffered reader for</span>
                <span class="hljs-comment">// the remaining bytes so that they can be read again in the</span>
                <span class="hljs-comment">// next iteration.</span>

                <span class="hljs-keyword">let</span> valid_bytes = error.valid_up_to();
                <span class="hljs-keyword">let</span> string = from_utf8(&amp;utf8_buffer[..valid_bytes]).unwrap();

                <span class="hljs-keyword">let</span> remaining_bytes = <span class="hljs-number">4</span> - valid_bytes;

                <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.reader.seek_relative(-(remaining_bytes <span class="hljs-keyword">as</span> <span class="hljs-built_in">i64</span>));

                <span class="hljs-comment">// Collect the valid characters into character_buffer</span>
                <span class="hljs-keyword">self</span>.character_buffer = string.chars().collect();

                <span class="hljs-comment">// Return the first character from character_buffer</span>
                <span class="hljs-keyword">self</span>.character_buffer.pop_front()
            }
        }
    }
}
</code></pre>
<p>And that's all you need to do for reading the input data for parsing. It's time to move on to the next stage in the process.</p>
<h2 id="heading-how-to-build-a-json-parser-stage-2-prepare-intermediate-data-types">How to Build a JSON Parser – Stage 2: Prepare Intermediate Data Types</h2>
<p>This isn't really a stage in the parsing pipeline, but it is a prerequisite for the next steps. We need to define Rust types that map to all of the possible types that JSON supports.</p>
<p>JSON supports the following data types:</p>
<ul>
<li>String</li>
<li>Number</li>
<li>Boolean</li>
<li>Array</li>
<li>Object</li>
<li>Null</li>
</ul>
<p>A number can further be either an integer, or a floating-point number. While you can use <code>f64</code> as the Rust type for all JSON numbers, practically it's not feasible without littering your code with type casts everywhere when you try to use it. </p>
<p>So in this tutorial, we're going to indeed make that distinction and record that fact.</p>
<h3 id="heading-the-value-type">The value type</h3>
<p>Enums are the ideal way to store state like this, where each variant needs to have some identifier as metadata (in this case the type of JSON value), and optionally some data attached to it. The data you're going to attach to these variants will be the actual value of that type in JSON.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/value.rs</span>

<span class="hljs-keyword">use</span> std::collections::HashMap;

<span class="hljs-meta">#[derive(Debug, Copy, Clone, PartialEq)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Number</span></span> {
    I64(<span class="hljs-built_in">i64</span>),
    F64(<span class="hljs-built_in">f64</span>),
}

<span class="hljs-meta">#[derive(Debug, PartialEq, Clone)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Value</span></span> {
    <span class="hljs-built_in">String</span>(<span class="hljs-built_in">String</span>),
    Number(Number),
    Boolean(<span class="hljs-built_in">bool</span>),
    Array(<span class="hljs-built_in">Vec</span>&lt;Value&gt;),
    Object(HashMap&lt;<span class="hljs-built_in">String</span>, Value&gt;),
    Null,
}
</code></pre>
<p>The first few variants are pretty straightforward, you define the variant and the data it holds is a corresponding Rust type. The last variant is even simpler, representing the <code>null</code> value which doesn't need further data to be stored.</p>
<p>The <code>Array</code> and <code>Object</code> variants though are a bit more interesting, since they are recursively storing the Enum itself. This makes sense, as arrays in JSON can have any value type that JSON spec supports. And objects in JSON always have string keys and any JSON supported value, including other objects.</p>
<h3 id="heading-how-to-add-helpful-conversion-methods">How to add helpful conversion methods</h3>
<p>You will also need a way to convert the enum type into the underlying types, and throw an error if the underlying data isn't what you expected. This is mostly boilerplate code, so I'm just going to put it all together without further explanation:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/value.rs</span>

<span class="hljs-keyword">impl</span> TryFrom&lt;&amp;Value&gt; <span class="hljs-keyword">for</span> <span class="hljs-built_in">String</span> {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Error</span></span> = ();

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">try_from</span></span>(value: &amp;Value) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>, ()&gt; {
        <span class="hljs-keyword">match</span> value {
            Value::<span class="hljs-built_in">String</span>(value) =&gt; <span class="hljs-literal">Ok</span>(value.clone()),
            _ =&gt; <span class="hljs-literal">Err</span>(()),
        }
    }
}

<span class="hljs-keyword">impl</span> TryFrom&lt;&amp;Value&gt; <span class="hljs-keyword">for</span> <span class="hljs-built_in">i64</span> {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Error</span></span> = ();

    <span class="hljs-meta">#[allow(clippy::cast_possible_truncation)]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">try_from</span></span>(value: &amp;Value) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>, ()&gt; {
        <span class="hljs-keyword">match</span> value {
            Value::Number(value) =&gt; <span class="hljs-keyword">match</span> value {
                Number::I64(value) =&gt; <span class="hljs-literal">Ok</span>(*value),
                Number::F64(value) =&gt; <span class="hljs-literal">Ok</span>(*value <span class="hljs-keyword">as</span> <span class="hljs-built_in">i64</span>),
            },
            _ =&gt; <span class="hljs-literal">Err</span>(()),
        }
    }
}

<span class="hljs-keyword">impl</span> TryFrom&lt;&amp;Value&gt; <span class="hljs-keyword">for</span> <span class="hljs-built_in">f64</span> {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Error</span></span> = ();

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">try_from</span></span>(value: &amp;Value) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>, ()&gt; {
        <span class="hljs-keyword">match</span> value {
            Value::Number(value) =&gt; <span class="hljs-keyword">match</span> value {
                Number::F64(value) =&gt; <span class="hljs-literal">Ok</span>(*value),
                Number::I64(value) =&gt; <span class="hljs-literal">Ok</span>(*value <span class="hljs-keyword">as</span> <span class="hljs-built_in">f64</span>),
            },
            _ =&gt; <span class="hljs-literal">Err</span>(()),
        }
    }
}

<span class="hljs-keyword">impl</span> TryFrom&lt;&amp;Value&gt; <span class="hljs-keyword">for</span> <span class="hljs-built_in">bool</span> {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Error</span></span> = ();

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">try_from</span></span>(value: &amp;Value) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>, ()&gt; {
        <span class="hljs-keyword">match</span> value {
            Value::Boolean(value) =&gt; <span class="hljs-literal">Ok</span>(*value),
            _ =&gt; <span class="hljs-literal">Err</span>(()),
        }
    }
}

<span class="hljs-keyword">impl</span>&lt;<span class="hljs-symbol">'a</span>&gt; TryFrom&lt;&amp;<span class="hljs-symbol">'a</span> Value&gt; <span class="hljs-keyword">for</span> &amp;<span class="hljs-symbol">'a</span> <span class="hljs-built_in">Vec</span>&lt;Value&gt; {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Error</span></span> = ();

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">try_from</span></span>(value: &amp;<span class="hljs-symbol">'a</span> Value) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>, ()&gt; {
        <span class="hljs-keyword">match</span> value {
            Value::Array(value) =&gt; <span class="hljs-literal">Ok</span>(value),
            _ =&gt; <span class="hljs-literal">Err</span>(()),
        }
    }
}

<span class="hljs-meta">#[allow(clippy::implicit_hasher)]</span>
<span class="hljs-keyword">impl</span>&lt;<span class="hljs-symbol">'a</span>&gt; TryFrom&lt;&amp;<span class="hljs-symbol">'a</span> Value&gt; <span class="hljs-keyword">for</span> &amp;<span class="hljs-symbol">'a</span> HashMap&lt;<span class="hljs-built_in">String</span>, Value&gt; {
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Error</span></span> = ();

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">try_from</span></span>(value: &amp;<span class="hljs-symbol">'a</span> Value) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>, ()&gt; {
        <span class="hljs-keyword">match</span> value {
            Value::Object(value) =&gt; <span class="hljs-literal">Ok</span>(value),
            _ =&gt; <span class="hljs-literal">Err</span>(()),
        }
    }
}
</code></pre>
<h2 id="heading-how-to-build-a-json-parser-stage-3-tokenization">How to Build a JSON Parser – Stage 3: Tokenization</h2>
<p>The next step is to take the input data and tokenize it. </p>
<p>Tokenization is the process of splitting a large chunk of input into smaller, more digestible units that can then be analysed independently. This also allows you to work with them much more easily than just byte streams and they help represent the incoming data as a standard form, and allow for mapping tokens to output value types.</p>
<p>The parser can then recursively process all tokens until there's nothing to process, giving us the parsed data once it finishes.</p>
<h3 id="heading-how-to-define-expected-valid-tokens">How to define expected valid tokens</h3>
<p>There is going to be some duplication here compared to the value type you looked at previously, but that's to be expected, since the token representation of any literal value will be that value itself. There's no way to break it down to smaller units in that case.</p>
<p>Once again, Enum is the right data type for this since we need both metadata (as the token type), and optionally data associated with it.</p>
<p>The tokens representing literal values can be defined in this way:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">use</span> std::io::{Read, Seek};
<span class="hljs-keyword">use</span> std::iter::Peekable;
<span class="hljs-keyword">use</span> crate::reader::JsonReader;

<span class="hljs-meta">#[derive(Debug, Copy, Clone, PartialEq)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Number</span></span> {
    I64(<span class="hljs-built_in">i64</span>),
    F64(<span class="hljs-built_in">f64</span>),
}

<span class="hljs-meta">#[derive(Debug, Clone, PartialEq)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Token</span></span> {
    <span class="hljs-built_in">String</span>(<span class="hljs-built_in">String</span>),
    Number(Number),
    Boolean(<span class="hljs-built_in">bool</span>),
    Null,
}
</code></pre>
<p>Apart from these, we also have a lot of other tokens in JSON that form the "grammar" of the JSON format. These are:</p>
<ul>
<li>Curly braces (<code>{</code> or <code>}</code> ) that represent opening and closing of an object respectively.</li>
<li>Square brackets (<code>[</code> or <code>]</code>) that represent opening and closing of an array respectively.</li>
<li>Colon (<code>:</code>) for separating key-value pairs within the object.</li>
<li>Comma (<code>,</code>) for separating values.</li>
<li>Quotes (<code>"</code>) that represent opening/closing of the string literal values.</li>
</ul>
<p>All of these do not need to have any data associated with them, so they're going to be unit variants in the enum. Adding these in, the complete enum will be:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">use</span> std::io::{Read, Seek};
<span class="hljs-keyword">use</span> std::iter::Peekable;
<span class="hljs-keyword">use</span> crate::reader::JsonReader;
<span class="hljs-keyword">use</span> crate::value::Number;

<span class="hljs-meta">#[derive(Debug, Clone, PartialEq)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Token</span></span> {
    CurlyOpen,
    CurlyClose,
    Quotes,
    Colon,
    <span class="hljs-built_in">String</span>(<span class="hljs-built_in">String</span>),
    Number(Number),
    ArrayOpen,
    ArrayClose,
    Comma,
    Boolean(<span class="hljs-built_in">bool</span>),
    Null,
}
</code></pre>
<h3 id="heading-how-to-implement-the-tokenizer-struct">How to implement the tokenizer struct</h3>
<p>You are going to need a <code>JsonTokenizer</code> struct that can facilitate the process while also responsible for holding the state of the tokenizer process:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">JsonTokenizer</span></span>&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    tokens: <span class="hljs-built_in">Vec</span>&lt;Token&gt;,
    iterator: Peekable&lt;JsonReader&lt;T&gt;&gt;,
}

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
<span class="hljs-keyword">where</span>
    T: Read + Seek,
{
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(reader: File) -&gt; JsonTokenizer&lt;File&gt; {
        <span class="hljs-keyword">let</span> json_reader = JsonReader::&lt;File&gt;::new(BufReader::new(reader));

        JsonTokenizer {
            iterator: json_reader.peekable(),
            tokens: <span class="hljs-built_in">vec!</span>[],
        }
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from_bytes</span></span>&lt;<span class="hljs-symbol">'a</span>&gt;(input: &amp;<span class="hljs-symbol">'a</span> [<span class="hljs-built_in">u8</span>]) -&gt; JsonTokenizer&lt;Cursor&lt;&amp;<span class="hljs-symbol">'a</span> [<span class="hljs-built_in">u8</span>]&gt;&gt; {
        <span class="hljs-keyword">let</span> json_reader = JsonReader::&lt;Cursor&lt;&amp;<span class="hljs-symbol">'a</span> [<span class="hljs-built_in">u8</span>]&gt;&gt;::from_bytes(input);

        JsonTokenizer {
            iterator: json_reader.peekable(),
            tokens: <span class="hljs-built_in">Vec</span>::with_capacity(input.len()),
        }
    }
}
</code></pre>
<p>In this case, we've made it generic over where the input comes from. The type T needs to implement <code>Read</code> &amp; <code>Seek</code> traits, the reason for which is explained shortly.</p>
<p>The iterator also needs to be <code>Peekable</code>, which basically means we should be able to read the next item in the iterator without advancing the iterator itself.</p>
<h3 id="heading-how-to-tokenize-an-iterator-of-characters">How to tokenize an iterator of characters</h3>
<p>Once you've defined all of the expected tokens, you need to take your character iterator and convert it into a list of tokens, where each entry is a variant of the <code>Token</code> enum defined in the last section.</p>
<p>We'll start by writing a skeleton function that matches on the incoming character and panics if it encounters an invalid token:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt; <span class="hljs-keyword">where</span>
    T: Read + Seek, {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokenize_json</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;[Token], ()&gt; {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> *character {
                <span class="hljs-comment">// Parse all other tokens here</span>
                <span class="hljs-comment">// ...</span>
                character =&gt; {
                    <span class="hljs-keyword">if</span> character.is_ascii_whitespace() {
                        <span class="hljs-keyword">continue</span>;
                    }

                    <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Unexpected character: ;{character};"</span>)
                }
            }
        }

        <span class="hljs-literal">Ok</span>(&amp;<span class="hljs-keyword">self</span>.tokens)
    }
}
</code></pre>
<p>There are two noteworthy things here, let's start with the easy one. If your match block doesn't encounter any known characters (you will implement this shortly), you need to have a "catch-all" condition that matches any character. </p>
<p>Here, we are going to ignore any whitespace characters and continue to the next iteration if it encounters one. If the character isn't a whitespace, then you need to panic (or return error) here.</p>
<p>The next noteworthy thing here is <code>self.iterator.peek()</code>. To facilitate parsing of different kinds of tokens from delimiters to literal values, it is important that the iterator is not advanced when reading out the next character. This needs to happen so that you can conditionally advance it based on what character is next. </p>
<p>You also need to delegate parsing of certain sets of tokens to different functions, which will have their own logic of advancing the iterator. </p>
<p>A good example is parsing the <code>null</code> literal value. If the match encounters a <code>n</code> character and is not within a string, object, number, and so on, then you need to ensure that the next three characters are <code>u</code>, <code>l</code>, <code>l</code> respectively to form the literal value <code>null</code> and then advance the iterator by four so that the next loop starts parsing after the <code>null</code> character and not in the middle of it.</p>
<h3 id="heading-how-to-parse-string-tokens">How to parse string tokens</h3>
<p>We're going to start by parsing strings. Let's stop for a second and think what needs to happen step-by-step:</p>
<ul>
<li>Check if match encounters a <code>"</code> character. If it does, push <code>Token::Quote</code> to your list of output tokens.</li>
<li>Advance the iterator by one so the next steps start from after the <code>"</code> character.</li>
<li>Parse all characters as part of the string until you encounter another <code>"</code> character which indicates closing of the string value.</li>
<li>Advance the iterator by however many characters are parsed as part of the string, and one addition to also jump over the closing <code>"</code> character.</li>
<li>Push <code>Token::String</code> with the parsed value to your list of output tokens.</li>
<li>Push <code>Token::Quote</code> to your list of output tokens.</li>
</ul>
<p>Hopefully, that isn't too confusing. But the code should help you understand it better:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokenize_json</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;[Token], ()&gt; {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> *character {
                <span class="hljs-string">'"'</span> =&gt; {
                    <span class="hljs-comment">// Pushed opening quote to output tokens list.</span>
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Quotes);

                    <span class="hljs-comment">// Skip quote token since we already added it to the tokens list.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();

                    <span class="hljs-comment">// Delegate parsing string value to a separate function.</span>
                    <span class="hljs-comment">// The function should also take care of advancing the iterator properly.</span>
                    <span class="hljs-keyword">let</span> string = <span class="hljs-keyword">self</span>.parse_string();

                    <span class="hljs-comment">// Push parsed string to output tokens list.</span>
                    <span class="hljs-keyword">self</span>.tokens.push(Token::<span class="hljs-built_in">String</span>(string));

                    <span class="hljs-comment">// Pushed closing quote to output tokens list.</span>
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Quotes);
                }
                <span class="hljs-comment">// ...</span>
            }
        }

        <span class="hljs-literal">Ok</span>(&amp;<span class="hljs-keyword">self</span>.tokens)
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_string</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">String</span> {
        <span class="hljs-comment">// Create new vector to hold parsed characters.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> string_characters = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">char</span>&gt;::new();

        <span class="hljs-comment">// Take each character by reference so that they</span>
        <span class="hljs-comment">// aren't moved out of the iterator, which will</span>
        <span class="hljs-comment">// require you to move the iterator into this</span>
        <span class="hljs-comment">// function.</span>
        <span class="hljs-keyword">for</span> character <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span>.iterator.by_ref() {
            <span class="hljs-comment">// If it encounters a closing `"`, break</span>
            <span class="hljs-comment">// out of the loop as the string has ended.</span>
            <span class="hljs-keyword">if</span> character == <span class="hljs-string">'"'</span> {
                <span class="hljs-keyword">break</span>;
            }

            <span class="hljs-comment">// Continue pushing to the vector to build</span>
            <span class="hljs-comment">// the string.</span>
            string_characters.push(character);
        }

        <span class="hljs-comment">// Create a string out of character iterator and</span>
        <span class="hljs-comment">// return it.</span>
        <span class="hljs-built_in">String</span>::from_iter(string_characters)
    }
}
</code></pre>
<p>As I've previously mentioned, we're not going to look at handling escape characters in this tutorial, as they do not add much value towards learning the topic at hand, but if you're interested, it will be a good exercise for you to add that in on top of the implementation.</p>
<p>That takes care of parsing the string, we can move on to a more interesting value type next.</p>
<h3 id="heading-how-to-parse-number-tokens">How to parse number tokens</h3>
<p>Numbers in JSON spec have a lot of variation. They can either be positive or negative, and integers or decimals. They can also be defined as scientific notation (for example negative exponential <code>3.7e-5</code> or positive exponential <code>3.7e5</code>). And we need to parse all of these variations.</p>
<p>As always, we'll start with the easy bit. If we encounter any character that can be a valid character in number, you need to delegate parsing to a <code>parse_number</code> function. But also, any valid number can only start with either a digit, or a negative sign. A number cannot begin with a decimal character or an epsilon character, so it makes things easier for us.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokenize_json</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;[Token], ()&gt; {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> *character {
                <span class="hljs-comment">// ...</span>

                <span class="hljs-string">'-'</span> | <span class="hljs-string">'0'</span>..=<span class="hljs-string">'9'</span> =&gt; {
                    <span class="hljs-keyword">let</span> number = <span class="hljs-keyword">self</span>.parse_number()?;
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Number(number));
                }

                <span class="hljs-comment">// ...</span>
            }
        }

        <span class="hljs-literal">Ok</span>(&amp;<span class="hljs-keyword">self</span>.tokens)
    }

    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>Next, we'll implement the <code>parse_number</code> method:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_number</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;Number, ()&gt; {
        <span class="hljs-comment">// Store parsed number characters.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> number_characters = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">char</span>&gt;::new();

        <span class="hljs-comment">// Stores whether the digit being parsed is after a `.` character</span>
        <span class="hljs-comment">// making it a decimal.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> is_decimal = <span class="hljs-literal">false</span>;

        <span class="hljs-comment">// Stores the characters after an epsilon character `e` or `E`</span>
        <span class="hljs-comment">// to indicate the exponential value.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> epsilon_characters = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">char</span>&gt;::new();

        <span class="hljs-comment">// Stores whether the digit being parsed is part of the epsilon</span>
        <span class="hljs-comment">// characters.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> is_epsilon_characters = <span class="hljs-literal">false</span>;

        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> character {
                <span class="hljs-comment">// Match the negative sign character that indicates whether number is negative</span>
                <span class="hljs-string">'-'</span> =&gt; {
                    <span class="hljs-keyword">if</span> is_epsilon_characters {
                        <span class="hljs-comment">// If it's parsing epsilon characters, push it to the epsilon</span>
                        <span class="hljs-comment">// character set.</span>
                        epsilon_characters.push(<span class="hljs-string">'-'</span>);
                    } <span class="hljs-keyword">else</span> {
                        <span class="hljs-comment">// Otherwise, push it to normal character set.</span>
                        number_characters.push(<span class="hljs-string">'-'</span>);
                    }

                    <span class="hljs-comment">// Advance the iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-comment">// Match a positive sign, which can be treated as redundant and ignored since</span>
                <span class="hljs-comment">// positive is the default.</span>
                <span class="hljs-string">'+'</span> =&gt; {
                    <span class="hljs-comment">// Advance the iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-comment">// Match any digit between 0 and 9, and store it into the `digit`</span>
                <span class="hljs-comment">// variable.</span>
                digit @ <span class="hljs-string">'0'</span>..=<span class="hljs-string">'9'</span> =&gt; {
                    <span class="hljs-keyword">if</span> is_epsilon_characters {
                        <span class="hljs-comment">// If it's parsing epsilon characters, push it to the epsilon</span>
                        <span class="hljs-comment">// character set.</span>
                        epsilon_characters.push(*digit);
                    } <span class="hljs-keyword">else</span> {
                        <span class="hljs-comment">// Otherwise, push it to normal character set.</span>
                        number_characters.push(*digit);
                    }
                    <span class="hljs-comment">// Advance the iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-comment">// Match the period character which indicates start of the fractional</span>
                <span class="hljs-comment">// part of a decimal number.</span>
                <span class="hljs-string">'.'</span> =&gt; {
                    <span class="hljs-comment">// Push the decimal character to numbers character set.</span>
                    number_characters.push(<span class="hljs-string">'.'</span>);

                    <span class="hljs-comment">// Set the current state of number being decimal to true.</span>
                    is_decimal = <span class="hljs-literal">true</span>;

                    <span class="hljs-comment">// Advance the iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-comment">// Match any of the characters that can signify end of the number</span>
                <span class="hljs-comment">// literal value. This can be a comma which separates key-value pair,</span>
                <span class="hljs-comment">// closing object character, closing array character, or a `:` which</span>
                <span class="hljs-comment">// separates a key from its value.</span>
                <span class="hljs-string">'}'</span> | <span class="hljs-string">','</span> | <span class="hljs-string">']'</span> | <span class="hljs-string">':'</span> =&gt; {
                    <span class="hljs-keyword">break</span>;
                }
                <span class="hljs-comment">// Match the epsilon character which indicates that the number is in</span>
                <span class="hljs-comment">// scientific notation.</span>
                <span class="hljs-string">'e'</span> | <span class="hljs-string">'E'</span> =&gt; {
                    <span class="hljs-comment">// Panic if it's already parsing an exponential number since this would</span>
                    <span class="hljs-comment">// mean there are 2 epsilon characters which is invalid.</span>
                    <span class="hljs-keyword">if</span> is_epsilon_characters {
                        <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Unexpected character while parsing number: {character}. Double epsilon characters encountered"</span>);
                    }

                    <span class="hljs-comment">// Set the current state of number being in scientific notation to true.</span>
                    is_epsilon_characters = <span class="hljs-literal">true</span>;

                    <span class="hljs-comment">// Advance the iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-comment">// Panic if any other character is encountered.</span>
                other =&gt; {
                    <span class="hljs-keyword">if</span> !other.is_ascii_whitespace() {
                        <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Unexpected character while parsing number: {character}"</span>)
                    } <span class="hljs-keyword">else</span> {
                        <span class="hljs-keyword">self</span>.iterator.next();
                    }
                },
            }
        }

        <span class="hljs-keyword">if</span> is_epsilon_characters {
            <span class="hljs-comment">// if the number is an exponential, perform the calculations to convert it</span>
            <span class="hljs-comment">// to a floating point number in rust.</span>

            <span class="hljs-comment">// Parse base as floating point number.</span>
            <span class="hljs-keyword">let</span> base: <span class="hljs-built_in">f64</span> = <span class="hljs-built_in">String</span>::from_iter(number_characters).parse().unwrap();

            <span class="hljs-comment">// Parse exponential as floating point number.</span>
            <span class="hljs-keyword">let</span> exponential: <span class="hljs-built_in">f64</span> = <span class="hljs-built_in">String</span>::from_iter(epsilon_characters).parse().unwrap();

            <span class="hljs-comment">// Return the final computed decimal number.</span>
            <span class="hljs-literal">Ok</span>(Number::F64(base * <span class="hljs-number">10_f64</span>.powf(exponential)))
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> is_decimal {
            <span class="hljs-comment">// if the number is a decimal, parse it as a floating point number in rust.</span>
            <span class="hljs-literal">Ok</span>(Number::F64(
                <span class="hljs-built_in">String</span>::from_iter(number_characters).parse::&lt;<span class="hljs-built_in">f64</span>&gt;().unwrap(),
            ))
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Parse the number as an integer in rust.</span>
            <span class="hljs-literal">Ok</span>(Number::I64(
                <span class="hljs-built_in">String</span>::from_iter(number_characters).parse::&lt;<span class="hljs-built_in">i64</span>&gt;().unwrap(),
            ))
        }
    }
}
</code></pre>
<p>It is advisable for you to go through the code and read the comments to understand this function. You shouldn't encounter any new syntax that is not either covered already or assumed to be known by the reader.</p>
<h3 id="heading-how-to-parse-boolean-tokens">How to parse boolean tokens</h3>
<p>Parsing booleans is going to be the simplest one we look at so far. All we need to do is match <code>t</code> or <code>f</code> as the first character, and then check the next few characters to ensure they form the literal value <code>true</code> or <code>false</code>.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokenize_json</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;[Token], ()&gt; {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> *character {
                <span class="hljs-comment">// ...</span>

                <span class="hljs-comment">// Match `t` character which indicates beginning of a boolean literal.</span>
                <span class="hljs-string">'t'</span> =&gt; {
                    <span class="hljs-comment">// Advance iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();

                    <span class="hljs-comment">// Assert next character is `r` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'r'</span>), <span class="hljs-keyword">self</span>.iterator.next());
                    <span class="hljs-comment">// Assert next character is `u` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'u'</span>), <span class="hljs-keyword">self</span>.iterator.next());
                    <span class="hljs-comment">// Assert next character is `e` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'e'</span>), <span class="hljs-keyword">self</span>.iterator.next());

                    <span class="hljs-comment">// Push the literal value to token list.</span>
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Boolean(<span class="hljs-literal">true</span>));
                }
                <span class="hljs-string">'f'</span> =&gt; {
                    <span class="hljs-comment">// Advance iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();

                    <span class="hljs-comment">// Assert next character is `a` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'a'</span>), <span class="hljs-keyword">self</span>.iterator.next());
                    <span class="hljs-comment">// Assert next character is `l` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'l'</span>), <span class="hljs-keyword">self</span>.iterator.next());
                    <span class="hljs-comment">// Assert next character is `s` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'s'</span>), <span class="hljs-keyword">self</span>.iterator.next());
                    <span class="hljs-comment">// Assert next character is `e` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'e'</span>), <span class="hljs-keyword">self</span>.iterator.next());

                    <span class="hljs-comment">// Push the literal value to token list.</span>
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Boolean(<span class="hljs-literal">false</span>));
                }

                <span class="hljs-comment">// ...</span>
            }
        }

        <span class="hljs-literal">Ok</span>(&amp;<span class="hljs-keyword">self</span>.tokens)
    }
}
</code></pre>
<h3 id="heading-how-to-parse-null-literal">How to parse Null Literal</h3>
<p>This is very similar to how we parsed booleans in the previous step:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokenize_json</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;[Token], ()&gt; {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> *character {
                <span class="hljs-comment">// ...</span>

                <span class="hljs-string">'n'</span> =&gt; {
                    <span class="hljs-comment">// Advance iterator by 1.</span>
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();

                    <span class="hljs-comment">// Assert next character is `u` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'u'</span>), <span class="hljs-keyword">self</span>.iterator.next());
                    <span class="hljs-comment">// Assert next character is `l` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'l'</span>), <span class="hljs-keyword">self</span>.iterator.next());
                    <span class="hljs-comment">// Assert next character is `l` while advancing the iterator by 1.</span>
                    <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">Some</span>(<span class="hljs-string">'l'</span>), <span class="hljs-keyword">self</span>.iterator.next());

                    <span class="hljs-comment">// Push null literal value to output tokens list.</span>
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Null);
                }

                <span class="hljs-comment">// ...</span>
            }
        }

        <span class="hljs-literal">Ok</span>(&amp;<span class="hljs-keyword">self</span>.tokens)
    }
}
</code></pre>
<h3 id="heading-how-to-parse-delimiters">How to parse delimiters</h3>
<p>Parsing delimiters is very simple. All you need to do is to match on them, and push the respective token into the output token list:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokenize_json</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;[Token], ()&gt; {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> *character {
                <span class="hljs-comment">// ...</span>

                <span class="hljs-string">'{'</span> =&gt; {
                    <span class="hljs-keyword">self</span>.tokens.push(Token::CurlyOpen);
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-string">'}'</span> =&gt; {
                    <span class="hljs-keyword">self</span>.tokens.push(Token::CurlyClose);
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-string">'['</span> =&gt; {
                    <span class="hljs-keyword">self</span>.tokens.push(Token::ArrayOpen);
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-string">']'</span> =&gt; {
                    <span class="hljs-keyword">self</span>.tokens.push(Token::ArrayClose);
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-string">','</span> =&gt; {
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Comma);
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }
                <span class="hljs-string">':'</span> =&gt; {
                    <span class="hljs-keyword">self</span>.tokens.push(Token::Colon);
                    <span class="hljs-keyword">let</span> _ = <span class="hljs-keyword">self</span>.iterator.next();
                }

                <span class="hljs-comment">// ...</span>
            }
        }

        <span class="hljs-literal">Ok</span>(&amp;<span class="hljs-keyword">self</span>.tokens)
    }
}
</code></pre>
<h3 id="heading-how-to-parse-a-terminating-character">How to parse a terminating character</h3>
<p>The input can sometimes contain <code>\0</code> as the last character to indicate that the input has ended. This is more commonly known as EOF (End Of File) when dealing with files. It is also referred by other names like "escape sequence" or "null" character.</p>
<p>We need to handle it and break out of our parsing loop if we ever encounter this:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/token.rs</span>

<span class="hljs-keyword">impl</span>&lt;T&gt; JsonTokenizer&lt;T&gt;
    <span class="hljs-keyword">where</span>
        T: Read + Seek,
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokenize_json</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;&amp;[Token], ()&gt; {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(character) = <span class="hljs-keyword">self</span>.iterator.peek() {
            <span class="hljs-keyword">match</span> *character {
                <span class="hljs-comment">// ...</span>

                <span class="hljs-string">'\0'</span> =&gt; <span class="hljs-keyword">break</span>,
                other =&gt; {
                    <span class="hljs-keyword">if</span> !other.is_ascii_whitespace() {
                        <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Unexpected token encountered: {other}"</span>)
                    } <span class="hljs-keyword">else</span> {
                        <span class="hljs-keyword">self</span>.iterator.next();
                    }
                },

                <span class="hljs-comment">// ...</span>
            }
        }

        <span class="hljs-literal">Ok</span>(&amp;<span class="hljs-keyword">self</span>.tokens)
    }
}
</code></pre>
<h2 id="heading-how-to-build-a-json-parser-stage-4-from-tokens-to-value">How to Build a JSON Parser  – Stage 4: From Tokens To Value</h2>
<p>Now that you have all the tokens, it's time to move on to the final stage of the process, converting tokens to real values that you can work with in the Rust code.</p>
<p>Start by creating a unit struct, which can be used as the parser. At this stage, we don't need to hold any state for the entirety of the process:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/parser.rs</span>

<span class="hljs-keyword">use</span> std::collections::HashMap;
<span class="hljs-keyword">use</span> std::fs::File;
<span class="hljs-keyword">use</span> std::io::{BufReader, Cursor};
<span class="hljs-keyword">use</span> std::iter::Peekable;
<span class="hljs-keyword">use</span> std::slice::Iter;
<span class="hljs-keyword">use</span> crate::token::{JsonTokenizer, Token};
<span class="hljs-keyword">use</span> crate::value::Value;

<span class="hljs-comment">/// Main parser which is the entrypoint for parsing JSON.</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">JsonParser</span></span>;
</code></pre>
<p>We are also going to use this as the public interface for the parser. So let's start by implementing those methods first:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/parser.rs</span>

<span class="hljs-keyword">impl</span> JsonParser {
    <span class="hljs-comment">/// Create a new [`JsonParser`] that parses JSON from bytes.</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_from_bytes</span></span>&lt;<span class="hljs-symbol">'a</span>&gt;(input: &amp;<span class="hljs-symbol">'a</span> [<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-built_in">Result</span>&lt;Value, ()&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> json_tokenizer = JsonTokenizer::&lt;BufReader&lt;Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;&gt;&gt;::from_bytes(input);
        <span class="hljs-keyword">let</span> tokens = json_tokenizer.tokenize_json()?;

        <span class="hljs-literal">Ok</span>(Self::tokens_to_value(tokens))
    }

    <span class="hljs-comment">/// Create a new [`JsonParser`] that parses JSON from file.</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(reader: File) -&gt; <span class="hljs-built_in">Result</span>&lt;Value, ()&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> json_tokenizer = JsonTokenizer::&lt;BufReader&lt;File&gt;&gt;::new(reader);
        <span class="hljs-keyword">let</span> tokens = json_tokenizer.tokenize_json()?;

        <span class="hljs-literal">Ok</span>(Self::tokens_to_value(tokens))
    }
}
</code></pre>
<p>With that out of the way, you first need to implement the <code>tokens_to_value</code> method that these public methods are calling. </p>
<h3 id="heading-how-to-parse-primitives">How to parse primitives</h3>
<p>This method will be responsible for taking an iterator of tokens as input and outputting the <code>Value</code> type you defined previously. This is also pretty straightforward, since the object/array parsing is delegated to separate methods, which we'll look at shortly.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/parser.rs</span>

<span class="hljs-keyword">impl</span> JsonParser {
    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tokens_to_value</span></span>(tokens: &amp;[Token]) -&gt; Value {
        <span class="hljs-comment">// Create a peekable iterator over tokens</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> iterator = tokens.iter().peekable();

        <span class="hljs-comment">// Initialize final value to null.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> value = Value::Null;

        <span class="hljs-comment">// Loop while there are tokens in the iterator.</span>
        <span class="hljs-comment">// Note that you do not need to manually handle advancing the</span>
        <span class="hljs-comment">// iterator in this case which is why you can directly call</span>
        <span class="hljs-comment">// `iterator.next()`.</span>
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(token) = iterator.next() {
            <span class="hljs-keyword">match</span> token {
                Token::CurlyOpen =&gt; {
                    value = Value::Object(Self::process_object(&amp;<span class="hljs-keyword">mut</span> iterator));
                }
                Token::<span class="hljs-built_in">String</span>(string) =&gt; {
                    value = Value::<span class="hljs-built_in">String</span>(string.clone());
                }
                Token::Number(number) =&gt; {
                    value = Value::Number(*number);
                }
                Token::ArrayOpen =&gt; {
                    value = Value::Array(Self::process_array(&amp;<span class="hljs-keyword">mut</span> iterator));
                }
                Token::Boolean(boolean) =&gt; value = Value::Boolean(*boolean),
                Token::Null =&gt; value = Value::Null,
                <span class="hljs-comment">// Ignore all delimiters as you don't need to explicitly do anything</span>
                <span class="hljs-comment">// when you encounter them.</span>
                Token::Comma
                | Token::CurlyClose
                | Token::Quotes
                | Token::Colon
                | Token::ArrayClose =&gt; {}
            }
        }

        value
    }
}
</code></pre>
<h3 id="heading-how-to-parse-arrays">How to parse arrays</h3>
<p>Parsing arrays is almost as straightforward as the parsing logic we looked at above. Since arrays are just collection of other JSON values, there's not much logic involved into parsing them, unlike objects.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/parser.rs</span>

<span class="hljs-keyword">impl</span> JsonParser {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">process_array</span></span>(iterator: &amp;<span class="hljs-keyword">mut</span> Peekable&lt;Iter&lt;Token&gt;&gt;) -&gt; <span class="hljs-built_in">Vec</span>&lt;Value&gt; {
        <span class="hljs-comment">// Initialise a vector of JSON Value type to hold the value of</span>
        <span class="hljs-comment">// array that's currently being parsed.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> internal_value = <span class="hljs-built_in">Vec</span>::&lt;Value&gt;::new();

        <span class="hljs-comment">// Iterate over all tokens provided.</span>
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(token) = iterator.next() {
            <span class="hljs-keyword">match</span> token {
                Token::CurlyOpen =&gt; {
                    internal_value.push(Value::Object(Self::process_object(iterator)));
                }
                Token::<span class="hljs-built_in">String</span>(string) =&gt; internal_value.push(Value::<span class="hljs-built_in">String</span>(string.clone())),
                Token::Number(number) =&gt; internal_value.push(Value::Number(*number)),
                Token::ArrayOpen =&gt; {
                    internal_value.push(Value::Array(Self::process_array(iterator)));
                }
                <span class="hljs-comment">// Break loop if array is closed. Due to recursive nature of process_array,</span>
                <span class="hljs-comment">// we don't need to explicitly check if the closing token matches the opening</span>
                <span class="hljs-comment">// one.</span>
                Token::ArrayClose =&gt; {
                    <span class="hljs-keyword">break</span>;
                }
                Token::Boolean(boolean) =&gt; internal_value.push(Value::Boolean(*boolean)),
                Token::Null =&gt; internal_value.push(Value::Null),
                <span class="hljs-comment">// Ignore delimiters</span>
                Token::Comma | Token::CurlyClose | Token::Quotes | Token::Colon =&gt; {}
            }
        }

        internal_value
    }
}
</code></pre>
<h3 id="heading-how-to-parse-objects">How to parse objects</h3>
<p>Parsing objects is a bit more tricky than the previous value types, since objects come with their own syntax. But there should be no surprises for you, which is why I encourage you to read through the code and the comments below to understand how it works.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/parser.rs</span>

<span class="hljs-keyword">impl</span> JsonParser {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">process_object</span></span>(iterator: &amp;<span class="hljs-keyword">mut</span> Peekable&lt;Iter&lt;Token&gt;&gt;) -&gt; HashMap&lt;<span class="hljs-built_in">String</span>, Value&gt; {
        <span class="hljs-comment">// Whether the item being parsed is a key or a value. The first element</span>
        <span class="hljs-comment">// should always be a key so this is initialised to true.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> is_key = <span class="hljs-literal">true</span>;

        <span class="hljs-comment">// The current key for which the value is being parsed.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> current_key: <span class="hljs-built_in">Option</span>&lt;&amp;<span class="hljs-built_in">str</span>&gt; = <span class="hljs-literal">None</span>;

        <span class="hljs-comment">// The current state of parsed object.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> value = HashMap::&lt;<span class="hljs-built_in">String</span>, Value&gt;::new();

        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(token) = iterator.next() {
            <span class="hljs-keyword">match</span> token {
                <span class="hljs-comment">// If it is a nested object, recursively parse it and store</span>
                <span class="hljs-comment">// in the hashmap with current key.</span>
                Token::CurlyOpen =&gt; {
                    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(current_key) = current_key {
                        value.insert(
                            current_key.to_string(),
                            Value::Object(Self::process_object(iterator)),
                        );
                    }
                }
                <span class="hljs-comment">// If this token is encountered, break the loop since it</span>
                <span class="hljs-comment">// indicates end of an object being parsed.</span>
                Token::CurlyClose =&gt; {
                    <span class="hljs-keyword">break</span>;
                }
                Token::Quotes | Token::ArrayClose =&gt; {}
                <span class="hljs-comment">// If the token is a colon, it is the separator between key</span>
                <span class="hljs-comment">// and value pair. So the item being parsed from this point</span>
                <span class="hljs-comment">// ahead will not be a key.</span>
                Token::Colon =&gt; {
                    is_key = <span class="hljs-literal">false</span>;
                }
                Token::<span class="hljs-built_in">String</span>(string) =&gt; {
                    <span class="hljs-keyword">if</span> is_key {
                        <span class="hljs-comment">// If the process is presently parsing key, set the value</span>
                        <span class="hljs-comment">// as current key.</span>
                        current_key = <span class="hljs-literal">Some</span>(string);
                    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(key) = current_key {
                        <span class="hljs-comment">// If the process already has a key set for present item,</span>
                        <span class="hljs-comment">// parse string as value instead, and set the current_key to none</span>
                        <span class="hljs-comment">// once done to prepare for the next key-value pair.</span>
                        value.insert(key.to_string(), Value::<span class="hljs-built_in">String</span>(string.clone()));
                        <span class="hljs-comment">// Set current_key to None to prepare for the next key-value pair.</span>
                        current_key = <span class="hljs-literal">None</span>;
                    }
                }
                Token::Number(number) =&gt; {
                    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(key) = current_key {
                        value.insert(key.to_string(), Value::Number(*number));
                        <span class="hljs-comment">// Set current_key to None to prepare for the next key-value pair.</span>
                        current_key = <span class="hljs-literal">None</span>;
                    }
                }
                Token::ArrayOpen =&gt; {
                    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(key) = current_key {
                        value.insert(key.to_string(), Value::Array(Self::process_array(iterator)));
                        <span class="hljs-comment">// Set current_key to None to prepare for the next key-value pair.</span>
                        current_key = <span class="hljs-literal">None</span>;
                    }
                }
                <span class="hljs-comment">// If the token is a comma, it is the separator between multiple key-value pairs</span>
                <span class="hljs-comment">// in JSON. So the item being parsed from this point ahead will be a key.</span>
                Token::Comma =&gt; is_key = <span class="hljs-literal">true</span>,
                Token::Boolean(boolean) =&gt; {
                    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(key) = current_key {
                        value.insert(key.to_string(), Value::Boolean(*boolean));
                        <span class="hljs-comment">// Set current_key to None to prepare for the next key-value pair.</span>
                        current_key = <span class="hljs-literal">None</span>;
                    }
                }
                Token::Null =&gt; {
                    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(key) = current_key {
                        value.insert(key.to_string(), Value::Null);
                        <span class="hljs-comment">// Set current_key to None to prepare for the next key-value pair.</span>
                        current_key = <span class="hljs-literal">None</span>;
                    }
                }
            }
        }

        value
    }
}
</code></pre>
<p>And that's it. You should now have everything to start using this to parse a valid JSON file into Rust.</p>
<h2 id="heading-how-to-use-the-json-parser">How to Use the JSON parser</h2>
<p>Let's create a new example in the project to run our JSON parser:</p>
<pre><code class="lang-shell">mkdir examples; touch examples/json.rs
</code></pre>
<p>You also need to register it as an example in the <code>Cargo.toml</code> file:</p>
<pre><code class="lang-toml"><span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"json-parser"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

<span class="hljs-section">[dependencies]</span>

<span class="hljs-section">[[example]]</span>
<span class="hljs-attr">path</span> = <span class="hljs-string">"examples/json.rs"</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"json"</span>
</code></pre>
<p>Now let's write the code to run for this example. We start by copying over a sample JSON file to the root of the project, which you can find <a target="_blank" href="https://raw.githubusercontent.com/anshulsanghi-blog/json-parser/master/test.json">here</a>.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// examples/json.rs</span>

<span class="hljs-keyword">use</span> std::fs::File;
<span class="hljs-keyword">use</span> json_parser::parser::JsonParser;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> file = File::open(<span class="hljs-string">"test.json"</span>).unwrap();
    <span class="hljs-keyword">let</span> parser = JsonParser::parse(file).unwrap();

    dbg!(parser);
}
</code></pre>
<p>Running this code using the following command, you should see the same output as below:</p>
<pre><code class="lang-shell">cargo run --example json --release
</code></pre>
<pre><code class="lang-shell">[examples/json.rs:8:5] parser = Object(
    {
        "pairs": Array(
            [
                Object(
                    {
                        "x1": Number(
                            F64(
                                41.844453001935875,
                            ),
                        ),
                        "y0": Number(
                            F64(
                                -33.78221816487377,
                            ),
                        ),
                        "y1": Number(
                            F64(
                                -78.10213222087448,
                            ),
                        ),
                        "x0": Number(
                            F64(
                                95.26235434764715,
                            ),
                        ),
                    },
                ),
                Object(
                    {
                        "x0": Number(
                            F64(
                                115.42029308864215,
                            ),
                        ),
                        "y0": Number(
                            F64(
                                1.2002187300000001e-5,
                            ),
                        ),
                        "x1": Number(
                            F64(
                                83.39640643072113,
                            ),
                        ),
                        "y1": Number(
                            F64(
                                28.643090267505812,
                            ),
                        ),
                    },
                ),
                Object(
                    {
                        "isWorking": Boolean(
                            true,
                        ),
                        "sample": String(
                            "string sample",
                        ),
                        "nullable": Null,
                        "isNotWorking": Boolean(
                            false,
                        ),
                    },
                ),
            ],
        ),
        "utf8": Object(
            {
                "key2": String(
                    "value2",
                ),
                "key1": String(
                    "ࠄࠀࠆࠄࠀࠁࠃ",
                ),
            },
        ),
    },
)
</code></pre>
<p>Congratulations! You've now written your very own JSON parser, while learning some of the advanced use cases of match and iterators in Rust.</p>
<h2 id="heading-wrapping-up"><strong>Wrapping Up</strong></h2>
<p>I hope you can already see interesting ways you can make use of what you've learned today to optimize existing Rust code in your projects, and any future code you write that involves these.</p>
<p>You can find the complete code for everything we looked at in this article in <a target="_blank" href="https://github.com/anshulsanghi-blog/json-parser">this repository</a>.</p>
<p>Also, feel free to <strong><a target="_blank" href="mailto:contact@anshulsanghi.tech">contact me</a></strong> if you have any questions or opinions on this topic.</p>
<h3 id="heading-enjoying-my-work">Enjoying my work?</h3>
<p>Consider buying me a coffee to support my work!</p>
<p><a target="_blank" href="https://buymeacoffee.com/anshulsanghi">☕Buy me a coffee</a>.</p>
<p>'Till next time, happy coding and wishing you clear skies!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Procedural Macros in Rust – A Handbook for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ In this handbook, you'll learn about procedural macros in Rust, and what purposes they serve. You'll also learn how to write your own procedural macros with both hypothetical and real-world examples. This guide assumes that you're familiar with Rust ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/procedural-macros-in-rust/</link>
                <guid isPermaLink="false">66bb579a5a83db22bea98433</guid>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Anshul Sanghi ]]>
                </dc:creator>
                <pubDate>Wed, 24 Apr 2024 17:49:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Procedural-Macros-in-Rust-Cover--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this handbook, you'll learn about procedural macros in Rust, and what purposes they serve. You'll also learn how to write your own procedural macros with both hypothetical and real-world examples.</p>
<p>This guide assumes that you're familiar with Rust and its basic concepts, such as data-types, iterators, and traits. If you need to establish or review your Rust basics, <a target="_blank" href="https://www.freecodecamp.org/news/rust-in-replit/">check out this interactive course</a>.</p>
<p>You don't need any prior knowledge of macros, as this article covers everything from the ground up.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-are-macros-in-rust">What are Macros in Rust?</a><ol>
<li><a class="post-section-overview" href="#heading-types-of-macros-in-rust">Types of Macros in Rust</a></li>
<li><a class="post-section-overview" href="#heading-types-of-procedural-macros">Types of Procedural Macros</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a><ol>
<li><a class="post-section-overview" href="#heading-helpful-dependencies">Helpful Dependencies</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-how-to-write-a-simple-derive-macro">How to Write a Simple Derive Macro</a><ol>
<li><a class="post-section-overview" href="#heading-the-intostringhashmap-derive-macro">The <code>IntoStringHashMap</code> Derive Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-declare-a-derive-macro">How to Declare a Derive Macro</a></li>
<li><a class="post-section-overview" href="#how-to-parse-macro-input">How to Parse Macro Input</a></li>
<li><a class="post-section-overview" href="#how-to-ensure-a-struct-target-for-macro">How to Ensure a Struct Target for the Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-output-code">How to Build the Output Code</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-your-derive-macro">How to Use Your Derive Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-improve-our-implementation">How to Improve Our Implementation</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-a-more-elaborate-derive-macro">A More Elaborate Derive macro</a><ol>
<li><a class="post-section-overview" href="#heading-the-derivecustommodel-macro">The <code>DeriveCustomModel</code> Macro</a></li>
<li><a class="post-section-overview" href="#how-to-separate-implementation-from-declaration">How to Separate Implementation From Declaration</a></li>
<li><a class="post-section-overview" href="#heading-how-to-parse-derive-macro-arguments">How to Parse Derive Macro Arguments</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-derivecustommodel">How to Implement <code>DeriveCustomModel</code></a></li>
<li><a class="post-section-overview" href="#heading-how-to-generate-each-custom-model">How to Generate Each Custom Model</a></li>
<li><a class="post-section-overview" href="#how-to-use-your-derivecustommodal-macro">How to Use Your <code>DeriveCustomModal</code> Macro</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-a-simple-attribute-macro">A Simple Attribute Macro</a><ol>
<li><a class="post-section-overview" href="#heading-the-logduration-attribute">The <code>log_duration</code> Attribute</a></li>
<li><a class="post-section-overview" href="#heading-how-to-declare-an-attribute-macro">How to Declare an Attribute Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-logduration-attribute-macro">How to Implement the <code>log_duration</code> Attribute Macro</a></li>
<li><a class="post-section-overview" href="#how-to-use-your-log-duration-macro">How to Use Your <code>log_duration</code> Macro</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-a-more-elaborate-attribute-macro">A More Elaborate Attribute macro</a><ol>
<li><a class="post-section-overview" href="#heading-the-cachedfn-attribute">The <code>cached_fn</code> Attribute</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-cachedfn-attribute-macro">How to Implement the <code>cached_fn</code> Attribute Macro</a></li>
<li><a class="post-section-overview" href="#heading-cachedfn-attribute-arguments"><code>cached_fn</code> Attribute Arguments</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-cachedfn-macro">How to Use the <code>cached_fn</code> Macro</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-a-simple-function-like-macro">A Simple Function-like Macro</a><ol>
<li><a class="post-section-overview" href="#heading-the-constantstring-macro">The <code>constant_string</code> Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-declare-a-function-like-macro">How to Declare a Function-like Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-constantstring-macro">How to Implement the <code>constant_string</code> Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-constantstring-macro">How to Use the <code>constant_string</code> Macro</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-a-more-elaborate-function-like-macro">A More Elaborate Function-like Macro</a><ol>
<li><a class="post-section-overview" href="#heading-the-hashmapify-macro">The <code>hash_mapify</code> Macro</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-hashmapify-macro">How to Implement the <code>hash_mapify</code> Macro</a></li>
<li><a class="post-section-overview" href="#how-to-parse-hash-mapifys-input">How to Parse <code>hash_mapify</code>'s Input</a></li>
<li><a class="post-section-overview" href="#how-to-generate-output-code">How to Generate Output Code</a></li>
<li><a class="post-section-overview" href="#heading-how-to-convert-custom-data-types-to-output-tokens">How to Convert Custom Data Types To Output Tokens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-hashmapify-macro">How to Use the <code>hash_mapify</code> Macro</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-beyond-writing-macros">Beyond Writing Macros</a><ol>
<li><a class="post-section-overview" href="#heading-helpful-cratestools">Helpful Crates/Tools</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-downsides-of-macros">Downsides of Macros</a><ol>
<li><a class="post-section-overview" href="#heading-debugging-or-lack-thereof">Debugging (or lack thereof)</a></li>
<li><a class="post-section-overview" href="#heading-compile-time-costs">Compile Time Costs</a></li>
<li><a class="post-section-overview" href="#heading-lack-of-auto-complete-and-code-checks">Lack of auto-complete and code checks</a></li>
<li><a class="post-section-overview" href="#heading-where-do-we-draw-the-line">Where do we draw the line?</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a><ol>
<li><a class="post-section-overview" href="#heading-enjoying-my-work">Enjoying my work?</a></li>
</ol>
</li>
</ol>
<h2 id="heading-what-are-macros-in-rust"><strong>What are Macros in Rust?</strong></h2>
<p>Macros are an integral part of the Rust programming language. It doesn’t take long before you start encountering them when first learning the language.</p>
<p>In their simplest form, macros in Rust allow you to execute some code at compile-time. Rust pretty much allows you to do whatever you want when it comes to macros and what you can do with them. The most common use-case of this feature is writing code that generates other code. </p>
<p>Macros are a way to extend functionality of the compiler beyond what's supported as standard. Whether you want to generate code based on existing code, or you want to transform existing code in some form, macros are your go-to tool.</p>
<p>Here's how the official Rust book describes it:</p>
<blockquote>
<p>The term <em>macro</em> refers to a family of features in Rust.  </p>
<p>Fundamentally, macros are a way of writing code that writes other code, which is known as <em>metaprogramming</em>.  </p>
<p>Metaprogramming is useful for reducing the amount of code you have to write and maintain, which is also one of the roles of functions. However, macros have some additional powers that functions don’t.</p>
</blockquote>
<p>Using macros, you can also dynamically add things that are required to be added at compilation time, which is not possible using functions since they get called at runtime. One such feature, for example, is implementing <em>Traits</em> on types, which is required to be implemented at compilation time.</p>
<p>Another advantage of macros is that they can be very flexible, since they can take a dynamic amount of parameters or inputs unlike a function.</p>
<p>Macros do have their own syntax for both writing and using them, which we'll explore in detail in the coming sections.</p>
<p>Some examples of how macros are being used really helps convey just how powerful they are:</p>
<ul>
<li>The <strong>SQLx</strong> project uses macros to verify all your SQL queries and statements (as long as you created them using the provided macro) at compile-time by actually executing them against a running instance of DB (yes, at compile time).</li>
<li><strong>typed_html</strong> implements a complete HTML parser with compile-time validation, all while using the familiar JSX syntax.</li>
</ul>
<h2 id="heading-types-of-macros-in-rust">Types of Macros in Rust</h2>
<p>In Rust, there are 2 different types of macros: declarative and procedural.</p>
<h3 id="heading-declarative-macros">Declarative macros</h3>
<p>Declarative macros work based on syntax parsing. While the official docs define them as allowing you to write syntax extensions, I believe it's more intuitive to consider them as an advanced version of the <code>match</code> keyword for the compiler. </p>
<p>You can define one or more patterns to match, and their body should return the output Rust code you'd like the macro to produce. </p>
<p>We're not going to be talking about them in this article, but if you'd like to learn more, <a target="_blank" href="https://doc.rust-lang.org/reference/macros-by-example.html">this</a> is a good place to start.</p>
<h3 id="heading-procedural-macros">Procedural macros</h3>
<p>These macros, in their most basic use cases, execute any Rust code you want at compile time. The only requirement is that they should take Rust code as input, and return Rust code as output. </p>
<p>There's no special syntax parsing involved for writing these macros (unless you want to do so), which is why they're personally easier for me to understand and write. </p>
<p>Procedural macros are further divided into 3 categories: derive macros, attribute macros, and functional macros.</p>
<h3 id="heading-types-of-procedural-macros">Types of Procedural Macros</h3>
<h4 id="heading-derive-macros">Derive macros</h4>
<p>Derive macros are, generally speaking, applied to data types in Rust. They are a way to extend the type declaration to also automatically "derive" functionality for it. </p>
<p>You can use them to generate "derived" types from a type, or as a way to implement methods on the target data type automatically. This should make sense once you look at the following example below.</p>
<p>Printing non-primitive data types, such as structs, enums or even errors (which are just structs, but let's assume they're not), for debugging purposes is a very common feature for any language, not just Rust. In Rust, only primitives implicitly have the ability to be printed in "debug" contexts. </p>
<p>If you think about how everything in Rust is just traits (even basic operations like add and equals), this makes sense. You want to be able to debug print your custom data types, but Rust has no way of saying "please apply this trait to every single data type in the code out there, ever".</p>
<p>This is where the <code>Debug</code> derive macro comes in. There's a standard way of debug-printing each type of data structure in Rust that it uses for its internal types. The <code>Debug</code> macro allows you to automatically implement the <code>Debug</code> trait for your custom types, while following the same rules and style guide as the implementation for internal data types.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Derive macro examples</span>

<span class="hljs-comment">/// Example for deriving methods on data types</span>
<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">User</span></span> {
    username: <span class="hljs-built_in">String</span>,
    first_name: <span class="hljs-built_in">String</span>,
    last_name: <span class="hljs-built_in">String</span>,
}
</code></pre>
<p>The <code>Debug</code> derive macro will result in the following code (presentational, not exact):</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> core::fmt::<span class="hljs-built_in">Debug</span> <span class="hljs-keyword">for</span> User {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">fmt</span></span>(&amp;<span class="hljs-keyword">self</span>, f: &amp;<span class="hljs-keyword">mut</span> core::fmt::Formatter) -&gt; core::fmt::<span class="hljs-built_in">Result</span> {
        f.debug_struct(
            <span class="hljs-string">"User"</span>
        )
        .field(<span class="hljs-string">"username"</span>, &amp;<span class="hljs-keyword">self</span>.username)
        .field(<span class="hljs-string">"first_name"</span>, &amp;<span class="hljs-keyword">self</span>.first_name)
        .field(<span class="hljs-string">"last_name"</span>, &amp;<span class="hljs-keyword">self</span>.last_name)
        .finish()
    }
}
</code></pre>
<p>As you might be able to tell, nobody wants to write this code for all of their custom structs and enums again and again. This simple macro gives you a sense of both the power of macros in Rust, as well as why they're an essential part of the language itself.</p>
<p>During actual compilation, the same code would give the following as the result:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">User</span></span> {
    username: <span class="hljs-built_in">String</span>,
    first_name: <span class="hljs-built_in">String</span>,
    last_name: <span class="hljs-built_in">String</span>,
}

<span class="hljs-keyword">impl</span> core::fmt::<span class="hljs-built_in">Debug</span> <span class="hljs-keyword">for</span> User {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">fmt</span></span>(&amp;<span class="hljs-keyword">self</span>, f: &amp;<span class="hljs-keyword">mut</span> core::fmt::Formatter) -&gt; ::core::fmt::<span class="hljs-built_in">Result</span> {
        f.debug_struct(
            <span class="hljs-string">"User"</span>
        )
        .field(<span class="hljs-string">"username"</span>, &amp;<span class="hljs-keyword">self</span>.username)
        .field(<span class="hljs-string">"first_name"</span>, &amp;<span class="hljs-keyword">self</span>.first_name)
        .field(<span class="hljs-string">"last_name"</span>, &amp;<span class="hljs-keyword">self</span>.last_name)
        .finish()
    }
}
</code></pre>
<p>Notice how the original type declaration is preserved in the output code. This is one of the main differences between derive macros vs others. Derive macros preserve the input type without modifications. They only add additional code to the output. On the other hand, all the other macros do not behave the same way. They only preserve the target when the output for macro itself includes the target as well.</p>
<h4 id="heading-attribute-macros">Attribute macros</h4>
<p>Attribute macros, in addition to data types, are usually applied to code blocks such as functions, impl blocks, inline blocks, and so on. They're usually used to either transform the target code in some way, or annotate it with additional information. </p>
<p>The most common use case for these is to modify a function to add additional functionality or logic to it. For example, you can easily write an attribute macro that:</p>
<ul>
<li>Logs all input and output parameters</li>
<li>Logs the total runtime of the function</li>
<li>Counts the number of times that function is called</li>
<li>Adds pre-determined additional fields to any struct</li>
</ul>
<p>and so on.</p>
<p>All of the things I mentioned above, and much more, combined form the insanely popular and useful <code>instrumentation</code> macro in Rust provided by the <code>tracing</code> crate. Of course I'm massively simplifying here, but it's good enough as an example.</p>
<p>If you're used to using Clippy, it might have screamed at you a couple of times to add the <code>#[must_use]</code> attribute to your function or method. </p>
<p>That is an example of macros used to annotate the function with additional information. It tells the compiler to warn the user if the return value from this function call isn't used. The <code>Result</code> type is already annotated with <code>#[must_use]</code> by default, which is how you see the warning <code>Unused Result&lt;...&gt; that must be used</code> when you don't use a return value of <code>Result</code> type.</p>
<p>Attribute macros are also what powers <a target="_blank" href="https://doc.rust-lang.org/reference/conditional-compilation.html">conditional compilation</a> in Rust.</p>
<h4 id="heading-functional-macros">Functional macros</h4>
<p>Functional macros are macros disguised as functions. These are the least restrictive type of procedural macros, as they can be used literally anywhere, as long as they output code that's valid in the context that they're used in. </p>
<p>These macros aren't "applied" to anything unlike the 2 others, but rather called just like you'd call a function. As arguments, you can literally pass in anything you want, as long as your macro knows how to parse it. This includes everything all the way from no arguments to valid Rust code to random gibberish that only your macro can make sense of.</p>
<p>They're in a sense the procedural version of declarative macros. If you need to execute Rust code and also be able to parse custom syntax, functional macros are your go-to tool. They're also useful if you need macro-like functionality in places where other macros cannot be used.</p>
<p>After that lengthy description of the basic information regarding macros, it's finally time to dive into actually writing procedural macros.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>There are certain rules around writing your own procedural-macros that you'll need to follow. These rules apply to all 3 types of procedural macros. They are:</p>
<ul>
<li>Procedural macros can only be added to a project that is marked as <code>proc-macro</code> in <code>Cargo.toml</code></li>
<li>Projects marked as such cannot export anything other than procedural macros.</li>
<li>The macros themselves have to all be declared in the <code>lib.rs</code> file.</li>
</ul>
<p>Let’s begin by setting up our project with this code:</p>
<pre><code class="lang-shell">cargo new --bin my-app
cd my-app
cargo new --lib my-app-macros;
</code></pre>
<p>This will create a root project, as well as a sub-project within it that will host our macros. You need some changes in the <code>Cargo.toml</code> files for both these projects.</p>
<p>First, the <code>Cargo.toml</code> file for <code>my-app-macros</code> should have the following contents (notice that you need to declare a lib section that has the <code>proc-macro</code> property):</p>
<pre><code class="lang-toml"><span class="hljs-comment"># my-app/my-app-macros/Cargo.toml</span>

<span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"my-app-macros"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

<span class="hljs-section">[lib]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"my_app_macros"</span>
<span class="hljs-attr">path</span> = <span class="hljs-string">"src/lib.rs"</span>
<span class="hljs-attr">proc-macro</span> = <span class="hljs-literal">true</span>

<span class="hljs-section">[dependencies]</span>
</code></pre>
<p>Next, the <code>Cargo.toml</code> file for <code>my-app</code> should have the following contents:</p>
<pre><code class="lang-toml"><span class="hljs-comment"># my-app/Cargo.toml</span>

<span class="hljs-attr">workspace</span> = { members = [<span class="hljs-string">"my-app-macros"</span>] }

<span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"my-app"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>
<span class="hljs-attr">resolver</span> = <span class="hljs-string">"2"</span>

<span class="hljs-comment"># See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html</span>

<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">my-app-macros</span> = { path = <span class="hljs-string">"./my-app-macros"</span> }
</code></pre>
<p>You need to set the dependency resolver version to “2”, and add your macros project as a dependency of the <code>my-app</code> project.</p>
<h3 id="heading-helpful-dependencies">Helpful dependencies</h3>
<p>From the compiler’s point of view, this is how macros work:</p>
<ul>
<li>They take a stream of tokens as input (and optionally a stream of tokens as arguments to the macro itself).</li>
<li>They return a stream of tokens as output.</li>
</ul>
<p>That’s all that the compiler knows! And as you'll soon see, it's enough for the compiler to know that.</p>
<p>This does create a problem though. You need to be able to make sense of this "stream of tokens" in a way where you correctly understand them, whether as Rust code or custom syntax, are able to modify them, and also output them. Doing so manually is no easy task, and for the purposes of this tutorial, it is out of scope. </p>
<p>We can, however, rely on great open source work done by many developers to ease this for us. You need to add a few dependencies to help with this problem:</p>
<ul>
<li><code>syn</code> — A syntax parser for Rust. This helps you to parse the input token stream as Rust AST. AST is a concept that you mostly run into when trying to write your own interpreter or compiler, but a basic understanding is essential for working with macros. Macros, after all, are just extensions that you write for the compiler in a sense. If you’re interested in learning more about what ASTs are, <a target="_blank" href="https://dev.to/balapriya/abstract-syntax-tree-ast-explained-in-plain-english-1h38">check out this very helpful introduction</a>.</li>
<li><code>quote</code> — quote is, and this is a huge generalisation, a crate that helps us perform the reverse operation of what <code>syn</code> does. It helps us convert Rust source code into a stream of tokens that we can output from our macro.</li>
<li><code>proc-macro2</code> — The standard library provides a <code>proc-macro</code> crate, but the types it provides cannot exist outside of procedural macros. <code>proc-macro2</code> is a wrapper around the standard library that makes all of the internal types usable outside of the context of macros. This, for example, allows both <code>syn</code> and <code>quote</code> to not only be used for procedural macros, but in regular Rust code as well, should you ever have such a need. And we will indeed be using that extensively if we ever want to unit test our macros or their expansions.</li>
<li><code>darling</code>–It facilitates parsing and working with macro arguments, which is otherwise a tedious process due to having to manually parse it from the syntax tree. <code>darling</code> provides us with <code>serde</code>-like ability to automatically parse input argument tree into our arguments struct. It also helps us in error handling around invalid arguments, required arguments, and so on.</li>
</ul>
<p>While these projects are contributed to by many developers, I want to give special thanks to <a target="_blank" href="https://crates.io/users/dtolnay">David Tolnay</a>. He's a legend in the Rust community and is the creator of most of these projects, and many many more open source crates in Rust.</p>
<p>Let’s quickly add these dependencies to our project and start writing our macro:</p>
<pre><code class="lang-shell">// my-app-macros

cargo add syn quote proc-macro2 darling
</code></pre>
<h2 id="heading-how-to-write-a-simple-derive-macro">How to Write a Simple Derive Macro</h2>
<p>You are going to learn how to write a <code>Derive</code> macro in this section. By this time, you should already be aware of the different types of macros and what they entail, as we talked about them in the above sections.</p>
<h3 id="heading-the-intostringhashmap-derive-macro">The <code>IntoStringHashMap</code> Derive Macro</h3>
<p>Let's say you have an app where you need to be able to convert structs into hash maps, that uses the <code>String</code> type for both keys and values. This means that it should work with any struct where all of the fields are convertible to <code>String</code> type using the <code>Into</code> trait.</p>
<h3 id="heading-how-to-declare-a-derive-macro">How to Declare a Derive Macro</h3>
<p>You declare macros by creating a function, and annotating that function using attribute macros that tell the compiler to consider that function as a macro declaration. Since your <code>lib.rs</code> is empty right now, you also need to declare <code>proc-macro2</code> as an extern crate:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/lib.rs</span>
<span class="hljs-keyword">extern</span> <span class="hljs-keyword">crate</span> proc_macro;

<span class="hljs-keyword">use</span> proc_macro::TokenStream;

<span class="hljs-meta">#[proc_macro_derive(IntoStringHashMap)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">derive_into_hash_map</span></span>(item: TokenStream) -&gt; TokenStream {
    todo!()
}
</code></pre>
<p>All we’re doing here is declaring our macro as a derive macro with the identifier <code>IntoStringHashMap</code>. Note that the function name is not important here. What's important is the identifier passed to the <code>proc_macro_derive</code> attribute macro. </p>
<p>Let's immediately see how you can use this – we'll come back and finish the implementation later:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app/src/main.rs</span>

<span class="hljs-keyword">use</span> my_app_macros::IntoStringHashMap;

<span class="hljs-meta">#[derive(IntoStringHashMap)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">User</span></span> {
    username: <span class="hljs-built_in">String</span>,
    first_name: <span class="hljs-built_in">String</span>,
    last_name: <span class="hljs-built_in">String</span>,
    age: <span class="hljs-built_in">u32</span>,
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {

}
</code></pre>
<p>You can just use your macro as any other derive macro, using the identifier you declared for it (in this case it was <code>IntoStringHashMap</code>).</p>
<p>If you try and compile your code at this stage, you should see the following compilation error:</p>
<pre><code class="lang-shell">   Compiling my-app v0.1.0 

error: proc-macro derive panicked
 --&gt; src/main.rs:3:10
  |
3 | #[derive(IntoHashMap)]
  |          ^^^^^^^^^^^
  |
  = help: message: not yet implemented

error: could not compile `my-app` (bin "my-app") due to 1 previous error
</code></pre>
<p>This clearly proves that our macro was executed during the compilation stage, as, if you're not familiar with the <code>todo!()</code> macro, panics with <code>help: message: not yet implemented</code> when executed. </p>
<p>This means that both our macro declaration and its usage works. We can move on to actually implementing this macro now.</p>
<h3 id="heading-how-to-parse-the-macros-input">How to Parse the Macro's Input</h3>
<p>First, you parse the input token stream as a <code>DeriveInput</code> using <code>syn</code>, which is a representation of any target that you can use a derive macro with<em>:</em></p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> input = syn::parse_macro_input!(item <span class="hljs-keyword">as</span> syn::DeriveInput);
</code></pre>
<p><code>syn</code> provides us with the <code>parse_macro_input</code> macro that uses a somewhat custom syntax as its arguments. You provide it the name of your input variable, the <code>as</code> keyword, and the data type in <code>syn</code> that it should parse the input token stream as (in our case, a <code>DeriveInput</code>). </p>
<p>If you jump into the source code for <code>DeriveInput</code>, you'll see that it gives us the following information:</p>
<ul>
<li><code>attrs</code>: Attributes applied to this type, whether other attribute macros declared by us, or the built-in ones such as <code>must_use</code>.</li>
<li><code>vis</code>: The visibility specifier for this type declaration.</li>
<li><code>ident</code>: The identifier (name) of the type.</li>
<li><code>generics</code>: Information about the generic parameters this type takes, including lifetimes.</li>
<li><code>data</code>: An enum that describes whether the target is a struct, an enum, or a union, and also provides us with more information for each of these.</li>
</ul>
<p>These field names and their types (apart from data field) are pretty standard across targets supported by <code>syn</code>, such as functions, enums, and so on.</p>
<p>If you further jump into the declaration of the <code>Data</code> enum, and into <code>DataStruct</code> in particular, you'll see that it provides you with a field called <code>fields</code>. This is a collection of all the fields of this struct and you can use it to iterate over them. This is exactly what we need to build our hash map!</p>
<p>The complete implementation for this macro looks like this:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app/my-app-macros/lib.rs</span>

<span class="hljs-keyword">extern</span> <span class="hljs-keyword">crate</span> proc_macro2;

<span class="hljs-keyword">use</span> proc_macro::TokenStream;
<span class="hljs-keyword">use</span> quote::quote;
<span class="hljs-keyword">use</span> syn::Data;

<span class="hljs-meta">#[proc_macro_derive(IntoHashMap)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">into_hash_map</span></span>(item: TokenStream) -&gt; TokenStream {
    <span class="hljs-keyword">let</span> input = syn::parse_macro_input!(item <span class="hljs-keyword">as</span> syn::DeriveInput);

    <span class="hljs-keyword">let</span> struct_identifier = &amp;input.ident;

    <span class="hljs-keyword">match</span> &amp;input.data {
        Data::Struct(syn::DataStruct { fields, .. }) =&gt; {
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> implementation = quote!{
                <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_map = std::collections::HashMap::&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;::new();
            };

            <span class="hljs-keyword">for</span> field <span class="hljs-keyword">in</span> fields {
                <span class="hljs-keyword">let</span> identifier = field.ident.as_ref().unwrap();
                implementation.extend(quote!{
                    hash_map.insert(<span class="hljs-built_in">stringify!</span>(#identifier).to_string(), <span class="hljs-built_in">String</span>::from(value.#identifier));
                });
            }

            quote! {
                <span class="hljs-meta">#[automatically_derived]</span>
                <span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;#struct_identifier&gt; <span class="hljs-keyword">for</span> std::collections::HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; {
                    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(value: #struct_identifier) -&gt; <span class="hljs-keyword">Self</span> {
                        #implementation

                        hash_map
                    }
                }
            }
        }
        _ =&gt; <span class="hljs-built_in">unimplemented!</span>()
    }.into()
}
</code></pre>
<p>There's a lot going on here, so let's break it down:</p>
<h3 id="heading-how-to-ensure-a-struct-target-for-the-macro">How to Ensure a <code>struct</code> Target for the Macro</h3>
<p><code>let struct_identifier = &amp;input.ident;</code>: You store the struct identifier into a separate variable, so that you can easily use it later.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">match</span> &amp;input.data {
    Data::<span class="hljs-class"><span class="hljs-keyword">struct</span>(<span class="hljs-title">syn</span></span>::DataStruct { fields, .. }) =&gt; { ... },
    _ =&gt; <span class="hljs-built_in">unimplemented!</span>()
}
</code></pre>
<p>You match over the parsed data field from <code>DeriveInput</code>. If it is of type <code>DataStruct</code> (a Rust struct) then continue, else panic, as the macro isn't implemented for other types.</p>
<h3 id="heading-how-to-build-the-output-code">How to Build the Output Code</h3>
<p>Let's take a look at the match arm implementation when you do have a <code>DataStruct</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> implementation = quote!{
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_map = std::collections::HashMap::&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;::new();
};
</code></pre>
<p>Here you created a new <code>TokenStream</code> using <code>quote</code>. This <code>TokenStream</code> is different than the one provided by the standard library, so don't confuse it with that. This needs to be mutable, as we'll be adding more code to this <code>TokenStream</code> soon.</p>
<p><code>TokenStream</code> is basically the inverse representation of an AST. You provide actual Rust code to the <code>quote</code> macro, and it gives us the "stream of tokens" as you've called it previously for that source code. </p>
<p>This <code>TokenStream</code> can either be converted to the macro's output type, or be manipulated using methods provided by <code>quote</code> such as extend.</p>
<p>Moving on,</p>
<pre><code class="lang-rust"><span class="hljs-keyword">for</span> field <span class="hljs-keyword">in</span> fields {
    <span class="hljs-keyword">let</span> identifier = field.ident.as_ref().unwrap();
    implementation.extend(quote!{
        hash_map.insert(
            <span class="hljs-built_in">stringify!</span>(#identifier).to_string(),
            <span class="hljs-built_in">String</span>::from(value.#identifier)
        );
    });
}
</code></pre>
<p>You loop over all of the fields. In each iteration, you first create a variable <code>identifier</code> to hold the name of the field for later use. You then use the <code>extend</code> method on our previously created <code>TokenStream</code> to add additional code to it. </p>
<p>The <code>extend</code> method just takes another <code>TokenStream</code>, which can easily be generated using <code>quote</code> macro. For the extension, you simply write code to insert a new entry into the <code>hash_map</code> that will be created in the macro output. </p>
<p>Let's have a closer look at that:</p>
<pre><code class="lang-rust">hash_map.insert(
    <span class="hljs-built_in">stringify!</span>(#identifier).to_string(),
    <span class="hljs-built_in">String</span>::from(value.#identifier)
);
</code></pre>
<p>As you know, the insert method takes a key and a value. You've told the compiler that both the key and value are of <code>String</code> type. <code>stringify</code> is a built-in macro in the standard library, that converts any <code>Ident</code> type into its <code>&amp;str</code> equivalent. You use it here to convert your field identifiers into actual <code>&amp;str</code>. You then call <code>to_string()</code> method on it to convert it to the <code>String</code> type.</p>
<p>But what does the <code>#identifier</code> represent?</p>
<p><code>quote</code> provides you with the ability to use any variables declared outside of the <code>TokenStream</code> within it using the <code>#</code> prefix. Think of it as <code>{}</code> in format args. <code>#identifier</code> in this case simply gets replaced with the field identifier we declared outside of the <code>extend</code> call. So you basically call the <code>stringify!()</code> macro on the field identifier directly.</p>
<p>Similarly, you can access the value of a field using the familiar <code>struct_variable.field_name</code> syntax, but use the identifier variable instead of the field name instead. This is what you do when you pass the value to your insert statement: <code>String::from(value.#identifier)</code>. </p>
<p>If you've looked at the code closely, you'll realise where the <code>value</code> came from, but if not, it's just what the trait implementation method uses to declare its input argument further down.</p>
<p>Once you've built your implementation using the for loop for each field in the struct, you have a <code>TokenStream</code> which, for representational purposes, contains the following code:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_map = std::collections::HashMap::&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;::new();
hash_map.insert(<span class="hljs-string">"username"</span>.to_string(), <span class="hljs-built_in">String</span>::from(value.username));
hash_map.insert(<span class="hljs-string">"first_name"</span>.to_string(), <span class="hljs-built_in">String</span>::from(value.first_name));
hash_map.insert(<span class="hljs-string">"last_name"</span>.to_string(), <span class="hljs-built_in">String</span>::from(value.last_name));
</code></pre>
<p>Moving on to finally generating the output of our macro, you have:</p>
<pre><code class="lang-rust">quote! {
    <span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;#struct_identifier&gt; <span class="hljs-keyword">for</span> std::collections::HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(value: #struct_identifier) -&gt; <span class="hljs-keyword">Self</span> {
            #implementation

            hash_map
        }
    }
}
</code></pre>
<p>Here you start by creating another <code>TokenStream</code> using <code>quote</code>. You write your <code>From</code> trait implementation in this block.</p>
<p>The following line again uses the <code>#</code> prefix syntax that we just looked at to declare that the trait implementation should be for your target struct, based on the identifier for the struct. In this case, this identifier will be replaced with <code>User</code> if you apply the derive macro to <code>User</code> struct.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;#struct_identifier&gt; <span class="hljs-keyword">for</span> std::collections::HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; {}
</code></pre>
<p>Finally, you have the actual method body:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(value: #struct_identifier) -&gt; <span class="hljs-keyword">Self</span> {
    #implementation

    hash_map
}
</code></pre>
<p>As you can see, you can easily nest <code>TokenStream</code>s into other <code>TokenStreams</code> using the same <code>#</code> syntax that lets you use external variables within the <code>quote</code> macro. </p>
<p>Here, you declare that your hash map implementation should be inserted as the first few lines of the function. And then you simply return the same <code>hash_map</code>. This completes your trait implementation.</p>
<p>As the very last step, you call <code>.into()</code> on the return type of our <code>match</code> block, which returns the output of <code>quote</code> macro call. This converts the <code>TokenStream</code> type used by <code>quote</code> into the <code>TokenStream</code> type that comes from the standard library and is expected by the compiler to be returned from a macro.</p>
<p>If it was harder to understand it when I broke it down line by line, you can look at the following complete but commented code in addition:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Tell the compiler that this function is a derive macro, and the identifier for derive is `IntoHashMap`.</span>
<span class="hljs-meta">#[proc_macro_derive(IntoHashMap)]</span>
<span class="hljs-comment">// Declare a function that takes an input `TokenStream` and outputs `TokenStream`.</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">into_hash_map</span></span>(item: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse the input token stream as `DeriveInput` type provided by `syn` crate.</span>
    <span class="hljs-keyword">let</span> input = syn::parse_macro_input!(item <span class="hljs-keyword">as</span> syn::DeriveInput);

    <span class="hljs-comment">// Store the struct identifier (name) into a variable so that you can insert it in the output code.</span>
    <span class="hljs-keyword">let</span> struct_identifier = &amp;input.ident;

    <span class="hljs-comment">// Match over the target type to which the derive macro was applied</span>
    <span class="hljs-keyword">match</span> &amp;input.data {
        <span class="hljs-comment">// Match that the target was a struct, and destructure the `fields` field from its information.</span>
        Data::Struct(syn::DataStruct { fields, .. }) =&gt; {
            <span class="hljs-comment">// Declare a new quote block that will hold the code for your implementation of the hash map.</span>
            <span class="hljs-comment">// This block will both create a new hash map, and also populate it with all of the fields from</span>
            <span class="hljs-comment">// the struct.</span>
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> implementation = quote!{
                <span class="hljs-comment">// This is just code that you want to see in the output. In this case, you want to have</span>
                <span class="hljs-comment">// a new hash map created.</span>
                <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_map = std::collections::HashMap::&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;::new();
            };

            <span class="hljs-comment">// Iterate over all the fields of your target struct</span>
            <span class="hljs-keyword">for</span> field <span class="hljs-keyword">in</span> fields {
                <span class="hljs-comment">// Create a variable to store the identifier (name) of the field for later use</span>
                <span class="hljs-keyword">let</span> identifier = field.ident.as_ref().unwrap();
                <span class="hljs-comment">// Extend your `implementation` block to include code in the output that populates</span>
                <span class="hljs-comment">// the hash map you create with the information from current field.</span>
                implementation.extend(quote!{
                    <span class="hljs-comment">// Convert the field identifier to a string using `stringify!` macro. This is used</span>
                    <span class="hljs-comment">// as the key in your new hash map entry. For value of this key, we access the field value</span>
                    <span class="hljs-comment">// from the struct using `value.#identifier`, where `#identifier` is replaced with the actual</span>
                    <span class="hljs-comment">// field name in output code.</span>
                    hash_map.insert(<span class="hljs-built_in">stringify!</span>(#identifier).to_string(), <span class="hljs-built_in">String</span>::from(value.#identifier));
                });
            }

            <span class="hljs-comment">// Create the final output block</span>
            quote! {
                <span class="hljs-comment">// Implement the `From` trait to allow converting your target struct, identified by</span>
                <span class="hljs-comment">// `struct_identifier` to a HashMap with both the key and the value as `String`.</span>
                <span class="hljs-comment">// Just like previously, #struct_identifier is replaced with the actual name of the</span>
                <span class="hljs-comment">// target struct in output code.</span>
                <span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;#struct_identifier&gt; <span class="hljs-keyword">for</span> std::collections::HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; {
                    <span class="hljs-comment">// This is just a method that the `From` trait requires you to implement. The</span>
                    <span class="hljs-comment">// type of the input value is again `#struct_identifier`, which is replaced with</span>
                    <span class="hljs-comment">// the name of the target struct in output code.</span>
                    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(value: #struct_identifier) -&gt; <span class="hljs-keyword">Self</span> {
                        <span class="hljs-comment">// Include the `implementation` block you created using `quote!` as the body</span>
                        <span class="hljs-comment">// of this method. `quote` allows you to nest other `quote` blocks freely.</span>
                        #implementation

                        <span class="hljs-comment">// Return the hash_map.</span>
                        hash_map
                    }
                }
            }
        }
        <span class="hljs-comment">// If the target is of any other type, panic.</span>
        _ =&gt; <span class="hljs-built_in">unimplemented!</span>()
        <span class="hljs-comment">// Convert the `TokenStream` type used by `quote` to `TokenStream` type used by the</span>
        <span class="hljs-comment">// standard library and the compiler</span>
    }.into()
}
</code></pre>
<p>And that's it. You've written your very first procedural macro in Rust!</p>
<p><strong>It's now time to enjoy the fruits of your labour.</strong></p>
<h3 id="heading-how-to-use-your-derive-macro">How to Use Your Derive Macro</h3>
<p>Coming back to your <code>my-app/main.rs</code>, let's debug-print the hashmap that you create using the macro you implemented. Your <code>main.rs</code> should look like this:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app/src/main.rs</span>

<span class="hljs-keyword">use</span> std::collections::HashMap;
<span class="hljs-keyword">use</span> my_app_macros::IntoHashMap;

<span class="hljs-meta">#[derive(IntoHashMap)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">User</span></span> {
    username: <span class="hljs-built_in">String</span>,
    first_name: <span class="hljs-built_in">String</span>,
    last_name: <span class="hljs-built_in">String</span>,
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> user = User {
        username: <span class="hljs-string">"username"</span>.to_string(),
        first_name: <span class="hljs-string">"First"</span>.to_string(),
        last_name: <span class="hljs-string">"Last"</span>.to_string(),
    };

    <span class="hljs-keyword">let</span> hash_map = HashMap::&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;::from(user);

    dbg!(hash_map);
}
</code></pre>
<p>If you run this using <code>cargo run</code>, you should see the following output in your terminal:</p>
<pre><code class="lang-shell">[src/main.rs:20:5] hash_map = {
    "last_name": "Last",
    "first_name": "First",
    "username": "username",
}
</code></pre>
<p>And there you go!</p>
<h3 id="heading-how-to-improve-our-implementation">How to Improve Our Implementation</h3>
<p>There is a better way to work with iterators and <code>quote</code> that I skipped over in our original implementation – intentionally so, because it requires us to learn a bit more of the syntax specific to <code>quote</code>. </p>
<p>Let's see what it would have looked like with that, before we dive into how it works:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> input = syn::parse_macro_input!(item <span class="hljs-keyword">as</span> syn::DeriveInput);
    <span class="hljs-keyword">let</span> struct_identifier = &amp;input.ident;

    <span class="hljs-keyword">match</span> &amp;input.data {
        Data::Struct(syn::DataStruct { fields, .. }) =&gt; {
            <span class="hljs-keyword">let</span> field_identifiers = fields.iter().map(|item| item.ident.as_ref().unwrap()).collect::&lt;<span class="hljs-built_in">Vec</span>&lt;_&gt;&gt;();

            quote! {
                <span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;#struct_identifier&gt; <span class="hljs-keyword">for</span> std::collections::HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; {
                    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(value: #struct_identifier) -&gt; <span class="hljs-keyword">Self</span> {
                        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_map = std::collections::HashMap::&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;::new();

                        #(
                            hash_map.insert(<span class="hljs-built_in">stringify!</span>(#field_identifiers).to_string(), <span class="hljs-built_in">String</span>::from(value.#field_identifiers));
                        )*

                        hash_map
                    }
                }
            }
        }
        _ =&gt; <span class="hljs-built_in">unimplemented!</span>()
    }.into()
</code></pre>
<p>That looks so much more concise and easier to understand! Let's look at the special bit of syntax that makes it possible – in particular, the following line:</p>
<pre><code class="lang-rust">#(
    hash_map.insert(<span class="hljs-built_in">stringify!</span>(#field_identifiers).to_string(), <span class="hljs-built_in">String</span>::from(value.#field_identifiers));
)*
</code></pre>
<p>Let's break it down. First, you wrap the entire block in a <code>#()*</code> and your code goes inside the parentheses. This syntax is what allows you to make use of any iterator inside of the parenthesis, and it will repeat that block of code for all items in the iterator, while replacing the variable with correct item in each iteration.</p>
<p>In this case, you first create a <code>field_identifiers</code> iterator, that is a collection of all the field identifiers in your target struct. You then write your <code>hash_map</code> insert statement while using the iterator directly as if it is a single item. The <code>#()*</code> wrapper converts this into the expected output of multiple lines, one for each item in the iterator.</p>
<h2 id="heading-a-more-elaborate-derive-macro">A More Elaborate Derive Macro</h2>
<p>Now that you're comfortable writing a simple Derive macro, it's time to move on and create something that will actually be useful in the real world – especially if you're working with database models.</p>
<h3 id="heading-the-derivecustommodel-macro">The <code>DeriveCustomModel</code> Macro</h3>
<p>You're going to be building a Derive macro that helps you generate derived structs from your original struct. You're going to be needing this all the time whenever you're working with databases, and only want to load part of the data.</p>
<p>For example, if you have a <code>User</code> struct, which has all of the user information, but you only want to load the name information for the User from the database, you'll need a struct that only contains those fields – unless you want to make all the fields an Option, which isn't the best idea.</p>
<p>We will also need to add an implementation of <code>From</code> trait to automatically convert from <code>User</code> struct to the derived struct. Another thing our macro needs is to be able to derive multiple models from the same target struct.</p>
<p>Let's start by declaring it in <code>lib.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// lib.rs</span>

<span class="hljs-meta">#[proc_macro_derive(DeriveCustomModel, attributes(custom_model))]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">derive_custom_model</span></span>(item: TokenStream) -&gt; TokenStream {
    todo!()
}
</code></pre>
<p>Most of this syntax should familiar to you by now from our previous example. The only addition we have here, is now we also define <code>attributes(custom_model)</code> in the call to <code>proc_macro_derive</code>, which basically tells the compiler to treat any attribute that begins with <code>#[custom_model]</code> as an argument for this derive macro on that target.</p>
<p>For example, once you've defined this, you can apply <code>#[custom_model(name = "SomeName")]</code> to the target struct, to define that the derived struct should have the name "SomeName". You need to parse this yourself and handle it too, of course – the definition was only to tell the compiler to pass that through to your macro implementation and not treat it as an unknown attribute.</p>
<p>Let's also create a new file that will contain the implementation detail of this macro. The macro rule states that it needs to be <strong>defined</strong> in <code>lib.rs</code>, and we've done that. The implementation itself can live anywhere in the project.</p>
<p>Create a new file <code>custom_model.rs</code>:</p>
<pre><code class="lang-shell">touch src/custom_model.rs
</code></pre>
<h3 id="heading-how-to-separate-the-implementation-from-the-declaration">How to Separate the Implementation from the Declaration</h3>
<p>Define a function that implements the <code>DeriveCustomModel</code> macro. We're also going to add all imports right away to avoid confusion later:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// custom_model.rs</span>

<span class="hljs-keyword">use</span> syn::{
    parse_macro_input, Data::Struct, DataStruct, DeriveInput, Field, Fields, Ident, Path,
};
<span class="hljs-keyword">use</span> darling::util::PathList;
<span class="hljs-keyword">use</span> darling::{FromAttributes, FromDeriveInput, FromMeta};
<span class="hljs-keyword">use</span> proc_macro::TokenStream;
<span class="hljs-keyword">use</span> quote::{quote, ToTokens};

<span class="hljs-keyword">pub</span>(<span class="hljs-keyword">crate</span>) <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">derive_custom_model_impl</span></span>(input: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse input token stream as `DeriveInput`</span>
    <span class="hljs-keyword">let</span> original_struct = parse_macro_input!(input <span class="hljs-keyword">as</span> DeriveInput);

    <span class="hljs-comment">// Destructure data &amp; ident fields from the input</span>
    <span class="hljs-keyword">let</span> DeriveInput { data, ident, .. } = original_struct.clone();
}
</code></pre>
<p>This is just a Rust function, so there are no special rules here. You can call this from the declaration just like a regular Rust function.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[proc_macro_derive(DeriveCustomModel, attributes(custom_model))]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">derive_custom_model</span></span>(item: TokenStream) -&gt; TokenStream {
    custom_model::custom_model_impl(item)
}
</code></pre>
<h3 id="heading-how-to-parse-derive-macro-arguments">How to Parse Derive Macro Arguments</h3>
<p>To parse the arguments to our derive macro (which are usually provided using attributes applied to either the target or to its fields), we are going to rely on the <code>darling</code> crate to make it as simple as defining the data type for them.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// custom_model.rs</span>

<span class="hljs-comment">// Derive `FromDeriveInput` for this struct, which is a</span>
<span class="hljs-comment">// macro provided by darling to automatically add the ability</span>
<span class="hljs-comment">// to parse argument tokens into the given struct.</span>
<span class="hljs-meta">#[derive(FromDeriveInput, Clone)]</span>
<span class="hljs-comment">// We tell darling that we're looking for arguments</span>
<span class="hljs-comment">// that are defined using the `custom_model` attribute, and</span>
<span class="hljs-comment">// that we only support named structs for this.</span>
<span class="hljs-meta">#[darling(attributes(custom_model), supports(struct_named))]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">CustomModelArgs</span></span> {
    <span class="hljs-comment">// Specify parameters for generating a derive model.</span>
    <span class="hljs-comment">// Multiple models can be generated by repeating</span>
    <span class="hljs-comment">// this attribute with parameters for each model.</span>
    <span class="hljs-meta">#[darling(default, multiple, rename = <span class="hljs-meta-string">"model"</span>)]</span>
    <span class="hljs-keyword">pub</span> models: <span class="hljs-built_in">Vec</span>&lt;CustomModel&gt;,
}
</code></pre>
<p>We've told <code>darling</code> that for arguments to the struct, we should expect a list of <code>model</code> arguments, and each one will define parameters for a single derived model. This allows us to use the macro to generate multiple derived structs from a single input struct.</p>
<p>Next, let's define the arguments for each model:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// custom_model.rs</span>

<span class="hljs-comment">// Derive `FromMeta` for this struct, which is a</span>
<span class="hljs-comment">// macro provided by darling to automatically add the ability</span>
<span class="hljs-comment">// to parse metadata into the given struct.</span>
<span class="hljs-meta">#[derive(FromMeta, Clone)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">CustomModel</span></span> {
    <span class="hljs-comment">// Name of the generated model.</span>
    name: <span class="hljs-built_in">String</span>,
    <span class="hljs-comment">// Comma-separated list of field identifiers</span>
    <span class="hljs-comment">// to be included in the generated model</span>
    fields: PathList,
    <span class="hljs-comment">// List of additional derives to apply to the</span>
    <span class="hljs-comment">// resulting struct such as `Eq` or `Hash`.</span>
    <span class="hljs-meta">#[darling(default)]</span>
    extra_derives: PathList,
}
</code></pre>
<p>In this, we have two required arguments, <code>name</code> and <code>fields</code>, and one optional argument <code>extra_derives</code>. It's optional because of the <code>#[darling(default)]</code> annotation on it.</p>
<h3 id="heading-how-to-implement-derivecustommodel">How to Implement <code>DeriveCustomModel</code></h3>
<p>Now that we have all of our data types defined, let's get to parsing – which is as simple as calling a method on our argument struct! The complete function implementation should like this:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// custom_model.rs</span>

<span class="hljs-keyword">pub</span>(<span class="hljs-keyword">crate</span>) <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">derive_custom_model_impl</span></span>(input: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse input token stream as `DeriveInput`</span>
    <span class="hljs-keyword">let</span> original_struct = parse_macro_input!(input <span class="hljs-keyword">as</span> DeriveInput);

    <span class="hljs-comment">// Destructure data &amp; ident fields from the input</span>
    <span class="hljs-keyword">let</span> DeriveInput { data, ident, .. } = original_struct.clone();

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> Struct(data_struct) = data {
        <span class="hljs-comment">// Extract the fields from this data struct</span>
        <span class="hljs-keyword">let</span> DataStruct { fields, .. } = data_struct;

        <span class="hljs-comment">// `darling` provides this method on the struct</span>
        <span class="hljs-comment">// to easily parse arguments, and also handles</span>
        <span class="hljs-comment">// errors for us.</span>
        <span class="hljs-keyword">let</span> args = <span class="hljs-keyword">match</span> CustomModelArgs::from_derive_input(&amp;original_struct) {
            <span class="hljs-literal">Ok</span>(v) =&gt; v,
            <span class="hljs-literal">Err</span>(e) =&gt; {
                <span class="hljs-comment">// If darling returned an error, generate a</span>
                <span class="hljs-comment">// token stream from it so that the compiler</span>
                <span class="hljs-comment">// shows the error in the right location.</span>
                <span class="hljs-keyword">return</span> TokenStream::from(e.write_errors());
            }
        };

        <span class="hljs-comment">// Destructure `models` field from parsed args.</span>
        <span class="hljs-keyword">let</span> CustomModelArgs { models } = args;

        <span class="hljs-comment">// Create a new output</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> output = quote!();

        <span class="hljs-comment">// Panic if no models are defined but macro is</span>
        <span class="hljs-comment">// used.</span>
        <span class="hljs-keyword">if</span> models.is_empty() {
            <span class="hljs-built_in">panic!</span>(
                <span class="hljs-string">"Please specify at least 1 model using the `model` attribute"</span>
            )
        }

        <span class="hljs-comment">// Iterate over all defined models</span>
        <span class="hljs-keyword">for</span> model <span class="hljs-keyword">in</span> models {
            <span class="hljs-comment">// Generate custom model from target struct's fields and `model` args.</span>
            <span class="hljs-keyword">let</span> generated_model = generate_custom_model(&amp;fields, &amp;model);

            <span class="hljs-comment">// Extend the output to include the generated model</span>
            output.extend(quote!(#generated_model));
        }

        <span class="hljs-comment">// Convert output into TokenStream and return</span>
        output.into()
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// Panic if target is not a named struct</span>
        <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"DeriveCustomModel can only be used with named structs"</span>)
    }
}
</code></pre>
<p>The code that generates tokens for each model has been extracted away to another function that we call <code>generate_custom_model</code>. Let's implement that as well:</p>
<h3 id="heading-how-to-generate-each-custom-model">How to Generate Each Custom Model</h3>
<pre><code class="lang-rust"><span class="hljs-comment">// custom_model.rs</span>

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">generate_custom_model</span></span>(fields: &amp;Fields, model: &amp;CustomModel) -&gt; proc_macro2::TokenStream {
    <span class="hljs-keyword">let</span> CustomModel {
        name,
        fields: target_fields,
        extra_derives,
    } = model;

    <span class="hljs-comment">// Create new fields output</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> new_fields = quote!();

    <span class="hljs-comment">// Iterate over all fields in the source struct</span>
    <span class="hljs-keyword">for</span> Field {
        <span class="hljs-comment">// The identifier for this field</span>
        ident,
        <span class="hljs-comment">// Any attributes applied to this field</span>
        attrs,
        <span class="hljs-comment">// The visibility specifier for this field</span>
        vis,
        <span class="hljs-comment">// The colon token `:`</span>
        colon_token,
        <span class="hljs-comment">// The type of this field</span>
        ty,
        ..
    } <span class="hljs-keyword">in</span> fields
    {
        <span class="hljs-comment">// Make sure that field has an identifier, panic otherwise</span>
        <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(ident) = ident <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Failed to get struct field identifier"</span>)
        };

        <span class="hljs-comment">// Try to convert field identifier to `Path` which is a type provided</span>
        <span class="hljs-comment">// by `syn`. We do this because `darling`'s PathList type is just a</span>
        <span class="hljs-comment">// collection of this type with additional methods on it.</span>
        <span class="hljs-keyword">let</span> path = <span class="hljs-keyword">match</span> Path::from_string(&amp;ident.clone().to_string()) {
            <span class="hljs-literal">Ok</span>(path) =&gt; path,
            <span class="hljs-literal">Err</span>(error) =&gt; <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Failed to convert field identifier to path: {error:?}"</span>),
        };

        <span class="hljs-comment">// If the list of target fields doesn't contain this field,</span>
        <span class="hljs-comment">// skip to the next field</span>
        <span class="hljs-keyword">if</span> !target_fields.contains(&amp;path) {
            <span class="hljs-keyword">continue</span>;
        }

        <span class="hljs-comment">// If it does contain it, reconstruct the field declaration</span>
        <span class="hljs-comment">// and add it in `new_fields` output so that we can use it</span>
        <span class="hljs-comment">// in the output struct.</span>
        new_fields.extend(quote! {
            #(#attrs)*
            #vis #ident #colon_token #ty,
        });
    }

    <span class="hljs-comment">// Create a new identifier for output struct</span>
    <span class="hljs-comment">// from the name provided.</span>
    <span class="hljs-keyword">let</span> struct_ident = <span class="hljs-keyword">match</span> Ident::from_string(name) {
        <span class="hljs-literal">Ok</span>(ident) =&gt; ident,
        <span class="hljs-literal">Err</span>(error) =&gt; <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"{error:?}"</span>),
    };

    <span class="hljs-comment">// Create a TokenStream to hold the extra derive declarations</span>
    <span class="hljs-comment">// on new struct.</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> extra_derives_output = quote!();

    <span class="hljs-comment">// If extra_derives is not empty,</span>
    <span class="hljs-keyword">if</span> !extra_derives.is_empty() {
        <span class="hljs-comment">// This syntax is a bit compact, but you should already</span>
        <span class="hljs-comment">// know everything you need to understand it by now.</span>
        extra_derives_output.extend(quote! {
            #(#extra_derives,)*
        })
    }

    <span class="hljs-comment">// Construct the final struct by combining all the</span>
    <span class="hljs-comment">// TokenStreams generated so far.</span>
    quote! {
        <span class="hljs-meta">#[derive(#extra_derives_output)]</span>
        <span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> #<span class="hljs-title">struct_ident</span></span> {
            #new_fields
        }
    }
}
</code></pre>
<h3 id="heading-how-to-use-your-derivecustommodel-macro">How to Use Your <code>DeriveCustomModel</code> Macro</h3>
<p>Coming back to your <code>my-app/main.rs</code>, let's debug-print the generated hash-maps for your new structs that you create using the macro you implemented. Your <code>main.rs</code> should look like this:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app/src/main.rs</span>

<span class="hljs-keyword">use</span> macros::{DeriveCustomModel, IntoStringHashMap};
<span class="hljs-keyword">use</span> std::collections::HashMap;

<span class="hljs-meta">#[derive(DeriveCustomModel)]</span>
<span class="hljs-meta">#[custom_model(model(
    name = <span class="hljs-meta-string">"UserName"</span>,
    fields(first_name, last_name),
    extra_derives(IntoStringHashMap)
))]</span>
<span class="hljs-meta">#[custom_model(model(name = <span class="hljs-meta-string">"UserInfo"</span>, fields(username, age), extra_derives(Debug)))]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">User2</span></span> {
    username: <span class="hljs-built_in">String</span>,
    first_name: <span class="hljs-built_in">String</span>,
    last_name: <span class="hljs-built_in">String</span>,
    age: <span class="hljs-built_in">u32</span>,
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> user_name = UserName {
        first_name: <span class="hljs-string">"first_name"</span>.to_string(),
        last_name: <span class="hljs-string">"last_name"</span>.to_string(),
    };
    <span class="hljs-keyword">let</span> hash_map = HashMap::&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;::from(user_name);

    dbg!(hash_map);

    <span class="hljs-keyword">let</span> user_info = UserInfo {
        username: <span class="hljs-string">"username"</span>.to_string(),
        age: <span class="hljs-number">27</span>,
    };

    dbg!(user_info);
}
</code></pre>
<p>As you can see, <code>extra_derives</code> is already useful to us since we need to derive <code>Debug</code> and <code>IntoStringHashMap</code> for the new models.</p>
<p>If you run this using <code>cargo run</code>, you should see the following output in your terminal:</p>
<pre><code class="lang-shell">[src/main.rs:32:5] hash_map = {
    "last_name": "last_name",
    "first_name": "first_name",
}
[src/main.rs:39:5] user_info = UserInfo {
    username: "username",
    age: 27,
}
</code></pre>
<p>We are going to wrap up the derive macros here.</p>
<h2 id="heading-a-simple-attribute-macro">A Simple Attribute Macro</h2>
<p>In this section, you're going to learn how to write an <strong>attribute</strong> macro.</p>
<h3 id="heading-the-logduration-attribute">The <code>log_duration</code> Attribute</h3>
<p>You are going to write a simple attribute macro that can be applied to any function (or method) that will log the total run time of that function each time the function is called.</p>
<h3 id="heading-how-to-declare-an-attribute-macro">How to Declare an Attribute Macro</h3>
<p>You declare attribute macros by creating a function and annotating that function using the <code>proc_macro_attribute</code> macro that tells the compiler to consider that function as a macro declaration. Let's see what that looks like:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/lib.rs</span>

<span class="hljs-meta">#[proc_macro_attribute]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">log_duration</span></span>(args: TokenStream, item: TokenStream) -&gt; TokenStream {
    log_duration_impl(args, item)
}
</code></pre>
<p>For these macros, the function name is important, as that also becomes the name of the macro. As you can see, these take two different arguments. The first is the argument passed to the attribute macro, and the second is the target of the attribute macro.</p>
<p>Let's also implement <code>log_duration_impl</code>. Create a new file <code>log_duration.rs</code>:</p>
<pre><code class="lang-shell">touch src/log_duration.rs
</code></pre>
<h3 id="heading-how-to-implement-the-logduration-attribute-macro">How to Implement the <code>log_duration</code> Attribute Macro</h3>
<p>I'm going to give you the complete implementation first, and then I'll break down the parts that I haven't used so far:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/log_duration.rs</span>

<span class="hljs-keyword">use</span> proc_macro::TokenStream;
<span class="hljs-keyword">use</span> quote::quote;
<span class="hljs-keyword">use</span> syn::{parse_macro_input, ItemFn};

<span class="hljs-keyword">pub</span>(<span class="hljs-keyword">crate</span>) <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">log_duration_impl</span></span>(_args: TokenStream, input: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse the input as `ItemFn` which is a type provided</span>
    <span class="hljs-comment">// by `syn` to represent a function.</span>
    <span class="hljs-keyword">let</span> input = parse_macro_input!(input <span class="hljs-keyword">as</span> ItemFn);

    <span class="hljs-keyword">let</span> ItemFn {
        <span class="hljs-comment">// The function signature</span>
        sig,
        <span class="hljs-comment">// The visibility specifier of this function</span>
        vis,
        <span class="hljs-comment">// The function block or body</span>
        block,
        <span class="hljs-comment">// Other attributes applied to this function</span>
        attrs,
    } = input;

    <span class="hljs-comment">// Extract statements in the body of the functions</span>
    <span class="hljs-keyword">let</span> statements = block.stmts;

    <span class="hljs-comment">// Store the function identifier for logging</span>
    <span class="hljs-keyword">let</span> function_identifier = sig.ident.clone();

    <span class="hljs-comment">// Reconstruct the function as output using parsed input</span>
    quote!(
        <span class="hljs-comment">// Reapply all the other attributes on this function.</span>
        <span class="hljs-comment">// The compiler doesn't include the macro we are</span>
        <span class="hljs-comment">// currently working in this list.</span>
        #(#attrs)*
        <span class="hljs-comment">// Reconstruct the function declaration</span>
        #vis #sig {
            <span class="hljs-comment">// At the beginning of the function, create an instance of `Instant`</span>
            <span class="hljs-keyword">let</span> __start = std::time::Instant::now();

            <span class="hljs-comment">// Create a new block, the body of which is the body of the function.</span>
            <span class="hljs-comment">// Store the return value of this block as a variable so that we can</span>
            <span class="hljs-comment">// return it later from the parent function.</span>
            <span class="hljs-keyword">let</span> __result = {
                #(#statements)*
            };

            <span class="hljs-comment">// Log the duration information for this function</span>
            <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{} took {}μs"</span>, <span class="hljs-built_in">stringify!</span>(#function_identifier), __start.elapsed().as_micros());

            <span class="hljs-comment">// Return the result (if any)</span>
            <span class="hljs-keyword">return</span> __result;
        }
    )
    .into()
}
</code></pre>
<p>The only things that you might not have seen previously are the <code>sig</code> and the <code>block</code> fields you get from parsing the input as <code>ItemFn</code>. <code>sig</code> contains the entire signature of a function while <code>block</code> contains the entire body of the function. This is why, by using the following code, we can basically reconstruct the unmodified function:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Example code to reconstruct unmodified fn in macro</span>

#vis #sig #block
</code></pre>
<p>In this example, you want to modify the function body, which is why you create a new block that encapsulates the original function block.</p>
<h3 id="heading-how-to-use-your-logduration-macro">How to Use Your <code>log_duration</code> Macro</h3>
<p>Coming back to <code>main.rs</code>, using an attribute macro is simpler than you might think:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// main.rs</span>

<span class="hljs-meta">#[log_duration]</span>
<span class="hljs-meta">#[must_use]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">function_to_benchmark</span></span>() -&gt; <span class="hljs-built_in">u16</span> {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> counter = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..<span class="hljs-built_in">u16</span>::MAX {
        counter += <span class="hljs-number">1</span>;
    }

    counter
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, function_to_benchmark());
}
</code></pre>
<p>When you run this, you should get the following output:</p>
<pre><code class="lang-shell">function_to_benchmark took 498μs
65535
</code></pre>
<p>We are now ready to move on to a more complex use-case.</p>
<h2 id="heading-a-more-elaborate-attribute-macro">A More Elaborate Attribute Macro</h2>
<h3 id="heading-the-cachedfn-attribute">The <code>cached_fn</code> Attribute</h3>
<p>You are going to write an attribute macro that will allow you to add caching capability to any function. For the purposes of this example, we're going to assume that our function always has <code>String</code> arguments and also returns a <code>String</code> value. </p>
<p>Some of you might know this better as a "memoized" function. </p>
<p>In addition, you will need to allow the user of this macro to tell the macro how it can generate a dynamic key based on function args.</p>
<p>To help us facilitate the caching part so that we don't get diverted, we're going to use a dependency called <code>cacache</code>. <code>cacache</code> is a Rust library for managing local key and content caches. It works by writing the cache to the disk.</p>
<p>Let's add it to the project by editing the <code>Cargo.toml</code> file for <code>my-app</code> directly:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Cargo.toml</span>

workspace = { members = [<span class="hljs-string">"my-app-macros"</span>] }

[package]
name = <span class="hljs-string">"my-app"</span>
version = <span class="hljs-string">"0.1.0"</span>
edition = <span class="hljs-string">"2021"</span>
resolver = <span class="hljs-string">"2"</span>

# See more keys and their definitions at https:<span class="hljs-comment">//doc.rust-lang.org/cargo/reference/manifest.html</span>

[dependencies]
# New dependency
cacache = { version = <span class="hljs-string">"13.0.0"</span>, default-features = <span class="hljs-literal">false</span>, features = [<span class="hljs-string">"mmap"</span>] }
macros = { path = <span class="hljs-string">"./macros"</span> }
</code></pre>
<h3 id="heading-how-to-implement-the-cachedfn-attribute-macro">How to Implement the <code>cached_fn</code> Attribute Macro</h3>
<p>Let's start by declaring this macro in <code>lib.rs</code>:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/lib.rs</span>

<span class="hljs-meta">#[proc_macro_attribute]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cached_fn</span></span>(args: TokenStream, item: TokenStream) -&gt; TokenStream {
    cached_fn_impl(args, item)
}
</code></pre>
<p>Create a new file <code>cached_fn.rs</code> to store the implementation:</p>
<pre><code class="lang-shell">touch my-app-macros/src/cached_fn.rs
</code></pre>
<p>Let's define how our arguments should look before we go ahead and implement anything:</p>
<h3 id="heading-cachedfn-attribute-arguments"><code>cached_fn</code> Attribute Arguments</h3>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/cached_fn.rs</span>

<span class="hljs-meta">#[derive(FromMeta)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">CachedParams</span></span> {
    <span class="hljs-comment">// Accept any expression that we should use to compute the</span>
    <span class="hljs-comment">// key. This can be a constant string, or some computation</span>
    <span class="hljs-comment">// based on function arguments.</span>
    keygen: <span class="hljs-built_in">Option</span>&lt;Expr&gt;,
}
</code></pre>
<p>The only argument is an optional <code>keygen</code>, which is of type <code>Expr</code>. <code>Expr</code> represents any valid <a target="_blank" href="https://doc.rust-lang.org/reference/expressions.html">Rust expression</a>, so it can be very dynamic. In this example, you'll be passing an expression that generates the key based on function arguments of the target function.</p>
<p>As always, we'll first see the entire implementation and then break down the parts that are new:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/cached_fn.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">cached_fn_impl</span></span>(args: TokenStream, item: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse argument tokens as a list of NestedMeta items</span>
    <span class="hljs-keyword">let</span> attr_args = <span class="hljs-keyword">match</span> NestedMeta::parse_meta_list(args.into()) {
        <span class="hljs-literal">Ok</span>(v) =&gt; v,
        <span class="hljs-literal">Err</span>(e) =&gt; {
            <span class="hljs-comment">// Write error to output token stream if there is one</span>
            <span class="hljs-keyword">return</span> proc_macro::TokenStream::from(Error::from(e).write_errors());
        }
    };

    <span class="hljs-comment">// Parse the nested meta list as our `CachedParams` struct</span>
    <span class="hljs-keyword">let</span> CachedParams { keygen } = <span class="hljs-keyword">match</span> CachedParams::from_list(&amp;attr_args) {
        <span class="hljs-literal">Ok</span>(params) =&gt; params,
        <span class="hljs-literal">Err</span>(error) =&gt; {
            <span class="hljs-comment">// Write error to output token stream if there is one</span>
            <span class="hljs-keyword">return</span> proc_macro::TokenStream::from(Error::from(error).write_errors());
        }
    };

    <span class="hljs-comment">// Parse the input target item as a function</span>
    <span class="hljs-keyword">let</span> ItemFn {
        <span class="hljs-comment">// The function signature</span>
        sig,
        <span class="hljs-comment">// The visibility specifier of this function</span>
        vis,
        <span class="hljs-comment">// The function block or body</span>
        block,
        <span class="hljs-comment">// Other attributes applied to this function</span>
        attrs,
    } = parse_macro_input!(item <span class="hljs-keyword">as</span> ItemFn);

    <span class="hljs-comment">// Generate our key statement based on given param (or lack thereof)</span>
    <span class="hljs-keyword">let</span> key_statement = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(keygen) = keygen {
        <span class="hljs-comment">// If the user specified a `keygen`, use that as an expression to</span>
        <span class="hljs-comment">// get the cache key.</span>
        quote! {
            <span class="hljs-keyword">let</span> __cache_key = #keygen;
        }
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// If no `keygen` was provided, use the name of the function</span>
        <span class="hljs-comment">// as cache key.</span>
        <span class="hljs-keyword">let</span> fn_name = sig.ident.clone().to_string();
        quote! {
            <span class="hljs-keyword">let</span> __cache_key = #fn_name;
        }
    };

    <span class="hljs-comment">// Reconstruct the function as output using parsed input</span>
    quote!(
        <span class="hljs-comment">// Apply other attributes from the original function to the generated function</span>
        #(#attrs)*
        #vis #sig {
            <span class="hljs-comment">// Include the key_statement we generated above as the first</span>
            <span class="hljs-comment">// thing in the function body</span>
            #key_statement

            <span class="hljs-comment">// Try to read the value from cache</span>
            <span class="hljs-keyword">match</span> cacache::read_sync(<span class="hljs-string">"./__cache"</span>, __cache_key.clone()) {
                <span class="hljs-comment">// If the value exists, parse it as string and return it</span>
                <span class="hljs-literal">Ok</span>(value) =&gt; {
                    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Data is fetched from cached"</span>);
                    from_utf8(&amp;value).unwrap().to_string()
                },
                <span class="hljs-literal">Err</span>(_) =&gt; {
                    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Data is not fetched from cached"</span>);
                    <span class="hljs-comment">// Save the output of original function block into</span>
                    <span class="hljs-comment">// a variable.</span>
                    <span class="hljs-keyword">let</span> output = #block;

                    <span class="hljs-comment">// Write the output value to cache as bytes</span>
                    cacache::write_sync(<span class="hljs-string">"./__cache"</span>, __cache_key, output.as_bytes()).unwrap();

                    <span class="hljs-comment">// Return the original output</span>
                    output
                }
            }
        }
    )
    .into()
}
</code></pre>
<p>Well, turns out that you've seen everything that we used in this one before. </p>
<p>The only new thing here is the use of the <code>cacache</code> dependency, but that's also pretty straightforward. You just give the location where you want to store the cached data as the first argument to the <code>read_sync</code> and <code>write_sync</code> functions provided by <code>cacache</code>.</p>
<p>We've also added some logging to help us verify that the macro works as expected.</p>
<h3 id="heading-how-to-use-the-cachedfn-macro">How to Use the <code>cached_fn</code> Macro</h3>
<p>To make any function memoized or cached, we simply annotate it using the <code>cached_fn</code> attribute:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/main.rs</span>

<span class="hljs-meta">#[cached_fn(keygen = <span class="hljs-meta-string">"format!(\"</span>{first_name} {last_name}\<span class="hljs-meta-string">")"</span>)]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">test_cache</span></span>(first_name: <span class="hljs-built_in">String</span>, last_name: <span class="hljs-built_in">String</span>) -&gt; <span class="hljs-built_in">String</span> {
    <span class="hljs-built_in">format!</span>(<span class="hljs-string">"{first_name} {last_name}"</span>)
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    test_cache(<span class="hljs-string">"John"</span>.to_string(), <span class="hljs-string">"Appleseed"</span>.to_string());
    test_cache(<span class="hljs-string">"John"</span>.to_string(), <span class="hljs-string">"Appleseed"</span>.to_string());
    test_cache(<span class="hljs-string">"John"</span>.to_string(), <span class="hljs-string">"Doe"</span>.to_string());
}
</code></pre>
<p>If you run this, you should see the following output:</p>
<pre><code class="lang-shell">Data is not fetched from cached
Data is fetched from cached
Data is not fetched from cached
</code></pre>
<p>Which clearly shows that if the function is called more than once for the same arguments, data is returned from cache. But if the arguments are different, it doesn't return the value that was cached for a different set of arguments.</p>
<p>We did make a lot of assumptions for this one which don't hold true for a real-world use case. As such, this is only for learning purposes, but depicts a real-world use case.</p>
<p>For example, I've written attribute macros to cache HTTP handler functions using <code>redis</code> for production servers. Those have a very similar implementation to this, but contains a lot of bells and whistles to work with that particular use case.</p>
<h2 id="heading-a-simple-function-like-macro">A Simple Function-like Macro</h2>
<p>It's finally time to have some <em>fun</em> again. We are going to start simple, but the second example is going to include parsing custom syntax. <em>Fun</em>, right?</p>
<p>Disclaimer: If you're familiar with declarative macros (using <code>macro_rules!</code> syntax), you might realize that the following examples can easily be written using that syntax and don't need to be procedural macros. Writing example procedural macros that cannot be written as declarative ones is extremely difficult if you also want to keep things simple, which is why the examples were chosen despite this.</p>
<h3 id="heading-the-constantstring-macro">The <code>constant_string</code> Macro</h3>
<p>We're going to build a very simple macro that takes in a string literal (of type <code>&amp;str</code>) as input and creates a global public constant for it (the name of the variable being the same as the value). Basically, our macro will generate the following:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> STRING_LITERAL: &amp;<span class="hljs-built_in">str</span> = <span class="hljs-string">"STRING_LITERAL"</span>;
</code></pre>
<h3 id="heading-how-to-declare-a-function-like-macro">How to Declare a Function-like Macro</h3>
<p>You declare function-like macros by creating a function and annotating that function using a <code>proc_macro</code> macro. It tells the compiler to consider that function as a macro declaration. Let's see what that looks like:‌</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/lib.rs</span>

<span class="hljs-meta">#[proc_macro]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">constant_string</span></span>(item: TokenStream) -&gt; TokenStream {
    constant_string_impl(item)
}
</code></pre>
<p>For these macros, the function name is important, as that also becomes the name of the macro. As you can see, these only take a single argument, which is whatever you pass on to the macro. It can literally be anything, even custom syntax that's not valid Rust code.</p>
<h3 id="heading-how-to-implement-the-constantstring-macro">How to Implement the <code>constant_string</code> Macro</h3>
<p>For the implementation, let's create a new file <code>constant_string.rs</code>:</p>
<pre><code class="lang-rust">touch my-app-macros/src/constant_string.rs
</code></pre>
<p>The implementation is pretty simple:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> darling::FromMeta;
<span class="hljs-keyword">use</span> proc_macro::TokenStream;
<span class="hljs-keyword">use</span> quote::quote;
<span class="hljs-keyword">use</span> syn::{parse_macro_input, Ident, LitStr};

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">constant_string_impl</span></span>(item: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse input as a string literal</span>
    <span class="hljs-keyword">let</span> constant_value = parse_macro_input!(item <span class="hljs-keyword">as</span> LitStr);

    <span class="hljs-comment">// Create a new `Ident` (identifier) from the passed string value.</span>
    <span class="hljs-comment">// This is going to be the name of the constant variable.</span>
    <span class="hljs-keyword">let</span> constant_value_name = Ident::from_string(&amp;constant_value.value()).unwrap();

    <span class="hljs-comment">// Generate the code for declaring the constant variable.</span>
    quote!(<span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> #constant_value_name: &amp;<span class="hljs-built_in">str</span> = #constant_value;).into()
}
</code></pre>
<p>All we're doing is parsing input as a string literal. If you pass something to do this is not a string literal, it will throw an error. Then we take the string, create a identifier out of it, and generate the output code. Short and simple.</p>
<h3 id="heading-how-to-use-the-constantstring-macro">How to Use the <code>constant_string</code> Macro</h3>
<p>The usage of this macro is also pretty simple:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/main.rs</span>

constant_string!(<span class="hljs-string">"SOME_CONSTANT_STRING_VALUE"</span>);
</code></pre>
<p>The above code will expand to this:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> SOME_CONSTANT_STRING_VALUE: &amp;<span class="hljs-built_in">str</span> = <span class="hljs-string">"SOME_CONSTANT_STRING_VALUE"</span>;
</code></pre>
<h2 id="heading-a-more-elaborate-function-like-macro">A More Elaborate Function-like Macro</h2>
<p>Function-like macros, as the name might suggest, can be used in a similar way to calling a function. You can also use them in any place where you can call a function, and beyond.</p>
<h3 id="heading-the-hashmapify-macro">The <code>hash_mapify</code> Macro</h3>
<p>Moving on to the interesting parts: the macro you're going to write now will allow you to generate a <code>HashMap</code> by simply passing in a list of key-value pairs. For example:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> variable = <span class="hljs-string">"Some variable"</span>;

hash_mapify!(
    &amp;<span class="hljs-built_in">str</span>,
    key = <span class="hljs-string">"value"</span>, 
    key2 = <span class="hljs-string">"value2"</span>, 
    key3 = <span class="hljs-string">"value3"</span>, 
    key4 = variable
);
</code></pre>
<p>As you can see, we want the first argument to be the type of the value, and the subsequent arguments to be the key-value pairs. And we'll need to parse all of this ourselves.</p>
<p>To keep things simple, since this can easily get out of hand, we're only going to support primitive values such as strings, integers, floats and booleans. So we're not going to support creating a <code>hash_map</code> with non-string keys or <code>enum</code> and <code>struct</code> as values.</p>
<h3 id="heading-how-to-implement-the-hashmapify-macro">How to Implement the <code>hash_mapify</code> Macro</h3>
<p>We're going to start as usual by declaring our macro:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/lib.rs</span>

<span class="hljs-meta">#[proc_macro]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">hash_mapify</span></span>(item: TokenStream) -&gt; TokenStream {
    hash_mapify_impl(item)
}
</code></pre>
<p>Next, you're going to define a data structure to hold your input data. In this case, you need to know the value type passed, as well as a list of key-value pairs. </p>
<p>We are going to extract the implementation to a separate file, which is where you'll also implement the data types and parsing logic. </p>
<p>Create new file <code>hash_mapify.rs</code> and declare the data type to hold input data:</p>
<pre><code class="lang-shell">touch my-app-macros/src/hash_mapify.rs
</code></pre>
<h3 id="heading-how-to-parse-hashmapifys-input">How to Parse <code>hash_mapify</code>'s Input</h3>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">use</span> proc_macro::TokenStream;
<span class="hljs-keyword">use</span> quote::{quote, ToTokens};
<span class="hljs-keyword">use</span> syn::parse::{Parse, ParseStream};
<span class="hljs-keyword">use</span> syn::{parse_macro_input, Lit, LitStr, Token, Type};

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ParsedMapEntry</span></span>(<span class="hljs-built_in">String</span>, proc_macro2::TokenStream);

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ParsedMap</span></span> {
    value_type: Type,
    entries: <span class="hljs-built_in">Vec</span>&lt;ParsedMapEntry&gt;,
}
</code></pre>
<p>You store the value as <code>TokenStream</code> directly because you need to support both literal values as well as variables, both of which only have 1 common type in this context, <code>TokenStream</code>.</p>
<p>You also might have noticed that we save the <code>value_type</code> as <code>Type</code> which is a type provided by <code>syn</code> crate which is an enum of the possible types that a Rust value could have. That was a mouthful! </p>
<p>You won't need to handle each variant of this enum, since this type can also directly be converted to <code>TokenStream</code>. You'll better understand what that means shortly.</p>
<p>Next, you need to implement the <code>syn::parse::Parse</code> trait for <code>ParsedMap</code> declared previously, so that it can be computed from the <code>TokenStream</code> passed as arguments to the macro.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> entries = <span class="hljs-built_in">Vec</span>::&lt;ParsedMapEntry&gt;::new();
    }
}
</code></pre>
<p><code>input</code>, which is of type <code>ParsedStream</code> in this case, works similar to an iterator. You need to parse tokens out of the input using the method <code>parse</code> on it, which will also advance the stream to the beginning of the next token. </p>
<p>For example, if you have a stream of tokens representing <code>[a, b, c]</code>, as soon as you parse <code>[</code> out of this stream, the stream will be mutated to only contain <code>a, b, c]</code> . This is very similar to iterators, where as soon as you take a value out, the iterator is advanced by one position and only holds the remaining items.</p>
<p>Before you parse anything, you need to check if input is empty, and panic if it is:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// Check if input is empty (no arguments are passed). If</span>
        <span class="hljs-comment">// not, then panic as we cannot continue further.</span>
        <span class="hljs-keyword">if</span> input.is_empty() {
            <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"At least a type must be specified for an empty hashmap"</span>);
        }

        <span class="hljs-comment">// ...</span>
    }
}
</code></pre>
<p>Since we expect the first argument passed to the macro to be the type of the value in our hashmap, let's parse that out of the token stream:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// Since the first argument should be of type `Type`, you try</span>
        <span class="hljs-comment">// to parse `Type` out of input and returns an error otherwise.</span>
        <span class="hljs-keyword">let</span> ty = input.parse::&lt;Type&gt;()?;

        <span class="hljs-comment">// ...</span>
    }
}
</code></pre>
<p>Parse takes a single type argument which represents what to parse.</p>
<p>If the first argument cannot be parsed as a valid type, an error will be returned. Do note that this doesn't verify if the type you passed actually exists or not, this will only validate whether the tokens in the first argument are valid for a type definition, and that's all.</p>
<p>This means that if you pass <code>SomeRandomType</code> where <code>SomeRandomType</code> isn't actually defined, the parsing will still succeed. It will only fail after expanding the macro during compile time.</p>
<p>Moving on, we also expect the user to use <code>,</code> to separate the arguments. Let's parse that as the next token after type:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// Next, parse the `,` token, which you expect to be used to</span>
        <span class="hljs-comment">// separate the arguments.</span>
        input.parse::&lt;Token![,]&gt;()?;

        <span class="hljs-comment">// ...</span>
    }
}
</code></pre>
<p>You might notice the usage of the <code>Token!</code> macro when providing the type argument for the <code>parse</code> method. It's a macro provided by <code>syn</code> to easily convert built-ins such as keywords (<code>type</code>, <code>async</code> , <code>fn</code> and so on) as well as punctuation marks (<code>,</code>, <code>.</code>, <code>;</code> and so on) and delimiters (<code>{</code>, <code>[</code>, <code>(</code> and so on). This macro takes a single argument, which is the keyword/punctuation/delimiter literal for which the type is needed. </p>
<p>The official docs define it as:</p>
<blockquote>
<p>A type-macro that expands to the name of the Rust type representation of a given token.</p>
</blockquote>
<p>Now that you have the type of value as well as the first separator (comma), it's time to start parsing key-value pairs. All of the key-value pairs follow the same structure <code>key = value</code> and are separated by commas.</p>
<p>Do note that white-space isn't important, as that is entirely handled during the tokenization process and isn't something that you need to handle.</p>
<p>Since you won't know how many key-value pairs are passed, you need something to tell you when all of it is parsed:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// Loop until the input is empty (there is nothing else</span>
        <span class="hljs-comment">// left to parse).</span>
        <span class="hljs-keyword">while</span> !input.is_empty() {
            <span class="hljs-comment">// ..</span>
        }

        <span class="hljs-comment">// ...</span>
    }
}
</code></pre>
<p>As I explained previously, tokens are taken out of the stream and it's advanced each time you parse something. This means that when all of the tokens are parsed, the stream will be empty. We utilise this fact here to figure out when to break out of the loop.</p>
<p>Each key-value pair can be parsed in a similar fashion as you parsed the type argument:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// Loop until the input is empty (there is nothing else</span>
        <span class="hljs-comment">// left to parse).</span>
        <span class="hljs-keyword">while</span> !input.is_empty() {
            <span class="hljs-comment">// Try to parse the key as an identifier</span>
            <span class="hljs-keyword">let</span> key = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(key) = input.parse::&lt;syn::Ident&gt;() {
                key.to_string()
                <span class="hljs-comment">// If it's not an identifier, try to parse it as</span>
                <span class="hljs-comment">// a string literal</span>
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(key) = input.parse::&lt;LitStr&gt;() {
                key.value()
                <span class="hljs-comment">// If it's neither an identifier nor a string literal,</span>
                <span class="hljs-comment">// it is not a valid key, so panic with appropriate</span>
                <span class="hljs-comment">// error.</span>
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Key must be either a string literal or an identifier!"</span>);
            };

            <span class="hljs-comment">// Parse the `=` sign, which should be the next token after</span>
            <span class="hljs-comment">// a key.</span>
            input.parse::&lt;Token![=]&gt;()?;

            <span class="hljs-comment">// Next, try to parse the value as an identifier. If it is, it</span>
            <span class="hljs-comment">// means that it's a variable, so we should convert it to token</span>
            <span class="hljs-comment">// stream directly.</span>
            <span class="hljs-keyword">let</span> value = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(value) = input.parse::&lt;syn::Ident&gt;() {
                value.to_token_stream()
                <span class="hljs-comment">// If the input isn't an identifier, try to parse it as a</span>
                <span class="hljs-comment">// literal value such as `"string"` for strings, `42`</span>
                <span class="hljs-comment">// for numbers `false` for boolean value, etc.</span>
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(value) = input.parse::&lt;Lit&gt;() {
                value.to_token_stream()
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">// If the input is neither an identifier nor a literal value</span>
                <span class="hljs-comment">// panic with appropriate error.</span>
                <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Value must be either a literal or an identifier!"</span>);
            };

            <span class="hljs-comment">// Push the parsed key value pair to our list.</span>
            entries.push(ParsedMapEntry(key, value));

            <span class="hljs-comment">// Check if next token is a comma, without advancing the stream</span>
            <span class="hljs-keyword">if</span> input.peek(Token![,]) {
                <span class="hljs-comment">// If it is, then parse it out and advance the stream before</span>
                <span class="hljs-comment">// moving on to the next key-value pair</span>
                input.parse::&lt;Token![,]&gt;()?;
            }
        }

        <span class="hljs-comment">// ...</span>
    }
}
</code></pre>
<p>The only thing here that is new, is the call to <code>peek</code> method at the end. This is a special method that returns a boolean if the token that is passed to <code>peek</code> is the next token in the stream, and false otherwise.</p>
<p>As the name might suggest, this only performs a check, so it doesn't take that token out of the stream or advance the stream in any form.</p>
<p>Once all of the parsing is done, you just return the information as part of <code>ParsedMap</code> struct we declared earlier. The complete implementation for this trait is as below if that's easier for you to read through:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> entries = <span class="hljs-built_in">Vec</span>::&lt;ParsedMapEntry&gt;::new();

        <span class="hljs-comment">// Check if input is empty (no arguments are passed). If not, then</span>
        <span class="hljs-comment">// panic as we cannot continue further.</span>
        <span class="hljs-keyword">if</span> input.is_empty() {
            <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"At least a type must be specified for an empty hashmap"</span>);
        }

        <span class="hljs-comment">// Since the first argument should be of type `Type`, you try</span>
        <span class="hljs-comment">// to parse `Type` out of input and returns an error otherwise.</span>
        <span class="hljs-keyword">let</span> ty = input.parse::&lt;Type&gt;()?;

        <span class="hljs-comment">// Next, parse the `,` token, which you expect to be used to</span>
        <span class="hljs-comment">// separate the arguments.</span>
        input.parse::&lt;Token![,]&gt;()?;

        <span class="hljs-comment">// Loop until the input is empty (there is nothing else</span>
        <span class="hljs-comment">// left to parse).</span>
        <span class="hljs-keyword">while</span> !input.is_empty() {
            <span class="hljs-comment">// Try to parse the key as an identifier</span>
            <span class="hljs-keyword">let</span> key = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(key) = input.parse::&lt;syn::Ident&gt;() {
                key.to_string()
                <span class="hljs-comment">// If it's not an identifier, try to parse it as</span>
                <span class="hljs-comment">// a string literal</span>
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(key) = input.parse::&lt;LitStr&gt;() {
                key.value()
                <span class="hljs-comment">// If it's neither an identifier nor a string literal,</span>
                <span class="hljs-comment">// it is not a valid key, so panic with appropriate</span>
                <span class="hljs-comment">// error.</span>
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Key must be either a string literal or an identifier!"</span>);
            };

            <span class="hljs-comment">// Parse the `=` sign, which should be the next token after</span>
            <span class="hljs-comment">// a key.</span>
            input.parse::&lt;Token![=]&gt;()?;

            <span class="hljs-comment">// Next, try to parse the value as an identifier. If it is, it</span>
            <span class="hljs-comment">// means that it's a variable, so we should convert it to token</span>
            <span class="hljs-comment">// stream directly.</span>
            <span class="hljs-keyword">let</span> value = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(value) = input.parse::&lt;syn::Ident&gt;() {
                value.to_token_stream()
                <span class="hljs-comment">// If the input isn't an identifier, try to parse it as a</span>
                <span class="hljs-comment">// literal value such as `"string"` for strings, `42`</span>
                <span class="hljs-comment">// for numbers `false` for boolean value, etc.</span>
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(value) = input.parse::&lt;Lit&gt;() {
                value.to_token_stream()
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">// If the input is neither an identifier nor a literal value</span>
                <span class="hljs-comment">// panic with appropriate error.</span>
                <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Value must be either a literal or an identifier!"</span>);
            };

            <span class="hljs-comment">// Push the parsed key value pair to our list.</span>
            entries.push(ParsedMapEntry(key, value));

            <span class="hljs-comment">// Check if next token is a comma, without advancing the stream</span>
            <span class="hljs-keyword">if</span> input.peek(Token![,]) {
                <span class="hljs-comment">// If it is, then parse it out and advance the stream before</span>
                <span class="hljs-comment">// moving on to the next key-value pair</span>
                input.parse::&lt;Token![,]&gt;()?;
            }
        }

        <span class="hljs-literal">Ok</span>(ParsedMap {
            value_type: ty,
            entries,
        })
    }
}
</code></pre>
<h3 id="heading-how-to-generate-the-output-code">How to Generate the Output Code</h3>
<p>You can now finally write the actual macro implementation, which is going to be pretty-straightforward:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">hash_mapify_impl</span></span>(item: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse input token stream as `ParsedMap` defined by us.</span>
    <span class="hljs-comment">// This will use the logic from parse trait we implemented</span>
    <span class="hljs-comment">// earlier.</span>
    <span class="hljs-keyword">let</span> input = parse_macro_input!(item <span class="hljs-keyword">as</span> ParsedMap);

    <span class="hljs-keyword">let</span> key_value_pairs = input.entries;
    <span class="hljs-keyword">let</span> ty = input.value_type;

    <span class="hljs-comment">// Generate the output hashmap inside a code block so that</span>
    <span class="hljs-comment">// we don't shadow any existing variables. Return the hashmap</span>
    <span class="hljs-comment">// from the block.</span>
    quote!({
        <span class="hljs-comment">// Create a new hashmap with `String` for key type and `#ty` for </span>
        <span class="hljs-comment">// value type, which parsed from the macro input arguments.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_map = std::collections::HashMap::&lt;<span class="hljs-built_in">String</span>, #ty&gt;::new();

        <span class="hljs-comment">// Insert all key-value pairs into the hashmap.</span>
        #(
            hash_map.insert(#key_value_pairs);
        )*

        <span class="hljs-comment">// Return the generated hashmap</span>
        hash_map
    })
    .into()
}
</code></pre>
<p>If you're coding along with me, or if you have a keen eye, you might have noticed that there is an error here. The type of variable <code>key_value_pairs</code> is <code>Vec&lt;ParsedMapEntry&gt;</code>. We are trying to use it in the output as:</p>
<pre><code class="lang-rust">#(hash_map.insert(#key_value_pairs);)*
</code></pre>
<p>which is the correct syntax for working with lists, but the underlying type <code>ParsedMapEntry</code> is a custom type. And neither <code>syn</code> nor <code>quote</code> would know how to convert it to a token stream. So we cannot use it with this syntax.</p>
<p>But if we try to manually write an implementation where we loop it ourselves, generate a separate tokens stream in each loop, and extend the existing one, it's going to be quite tedious. Wouldn't it be great if there was a better solution? Turns out there is: <code>ToTokens</code> trait.</p>
<h3 id="heading-how-to-convert-custom-data-types-to-output-tokens">How to Convert Custom Data Types to Output Tokens</h3>
<p>This trait can be implemented for any of our custom types and defines how the type looks like when converted into the token stream. </p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">impl</span> ToTokens <span class="hljs-keyword">for</span> ParsedMapEntry {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_tokens</span></span>(&amp;<span class="hljs-keyword">self</span>, tokens: &amp;<span class="hljs-keyword">mut</span> proc_macro2::TokenStream) {
        <span class="hljs-keyword">let</span> key = <span class="hljs-keyword">self</span>.<span class="hljs-number">0</span>.clone();
        <span class="hljs-keyword">let</span> value = <span class="hljs-keyword">self</span>.<span class="hljs-number">1</span>.clone();

        tokens.extend(quote!(<span class="hljs-built_in">String</span>::from(#key), #value));
    }
}
</code></pre>
<p>As part of the implementation, you need to mutate the <code>tokens</code> argument and extend it to contain the token stream that we want our type to generate. The syntax I used to do that should all be familiar by now.</p>
<p>Once you've done this, <code>quote</code> can now easily convert the problematic code to token stream. So this: <code>#(hash_map.insert(#key_value_pairs);)*</code> will now work directly.</p>
<p>As usual, here's the complete implementation if that's easier to understand:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// my-app-macros/src/hash_mapify.rs</span>

<span class="hljs-keyword">use</span> proc_macro::TokenStream;
<span class="hljs-keyword">use</span> quote::{quote, ToTokens};
<span class="hljs-keyword">use</span> syn::parse::{Parse, ParseStream};
<span class="hljs-keyword">use</span> syn::{parse_macro_input, Lit, LitStr, Token, Type};

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ParsedMapEntry</span></span>(<span class="hljs-built_in">String</span>, proc_macro2::TokenStream);

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ParsedMap</span></span> {
    value_type: Type,
    entries: <span class="hljs-built_in">Vec</span>&lt;ParsedMapEntry&gt;,
}

<span class="hljs-keyword">impl</span> ToTokens <span class="hljs-keyword">for</span> ParsedMapEntry {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_tokens</span></span>(&amp;<span class="hljs-keyword">self</span>, tokens: &amp;<span class="hljs-keyword">mut</span> proc_macro2::TokenStream) {
        <span class="hljs-keyword">let</span> key = <span class="hljs-keyword">self</span>.<span class="hljs-number">0</span>.clone();
        <span class="hljs-keyword">let</span> value = <span class="hljs-keyword">self</span>.<span class="hljs-number">1</span>.clone();

        tokens.extend(quote!(<span class="hljs-built_in">String</span>::from(#key), #value));
    }
}

<span class="hljs-keyword">impl</span> Parse <span class="hljs-keyword">for</span> ParsedMap {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(input: ParseStream) -&gt; syn::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> entries = <span class="hljs-built_in">Vec</span>::&lt;ParsedMapEntry&gt;::new();

        <span class="hljs-comment">// Check if input is empty (no arguments are passed). If not, then</span>
        <span class="hljs-comment">// panic as we cannot continue further.</span>
        <span class="hljs-keyword">if</span> input.is_empty() {
            <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"At least a type must be specified for an empty hashmap"</span>);
        }

        <span class="hljs-comment">// Since the first argument should be of type `Type`, you try</span>
        <span class="hljs-comment">// to parse `Type` out of input and returns an error otherwise.</span>
        <span class="hljs-keyword">let</span> ty = input.parse::&lt;Type&gt;()?;

        <span class="hljs-comment">// Next, parse the `,` token, which you expect to be used to</span>
        <span class="hljs-comment">// separate the arguments.</span>
        input.parse::&lt;Token![,]&gt;()?;

        <span class="hljs-comment">// Loop until the input is empty (there is nothing else</span>
        <span class="hljs-comment">// left to parse).</span>
        <span class="hljs-keyword">while</span> !input.is_empty() {
            <span class="hljs-comment">// Try to parse the key as an identifier</span>
            <span class="hljs-keyword">let</span> key = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(key) = input.parse::&lt;syn::Ident&gt;() {
                key.to_string()
                <span class="hljs-comment">// If it's not an identifier, try to parse it as</span>
                <span class="hljs-comment">// a string literal</span>
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(key) = input.parse::&lt;LitStr&gt;() {
                key.value()
                <span class="hljs-comment">// If it's neither an identifier nor a string literal,</span>
                <span class="hljs-comment">// it is not a valid key, so panic with appropriate</span>
                <span class="hljs-comment">// error.</span>
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Key must be either a string literal or an identifier!"</span>);
            };

            <span class="hljs-comment">// Parse the `=` sign, which should be the next token after</span>
            <span class="hljs-comment">// a key.</span>
            input.parse::&lt;Token![=]&gt;()?;

            <span class="hljs-comment">// Next, try to parse the value as an identifier. If it is, it</span>
            <span class="hljs-comment">// means that it's a variable, so we should convert it to token</span>
            <span class="hljs-comment">// stream directly.</span>
            <span class="hljs-keyword">let</span> value = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(value) = input.parse::&lt;syn::Ident&gt;() {
                value.to_token_stream()
                <span class="hljs-comment">// If the input isn't an identifier, try to parse it as a</span>
                <span class="hljs-comment">// literal value such as `"string"` for strings, `42`</span>
                <span class="hljs-comment">// for numbers `false` for boolean value, etc.</span>
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(value) = input.parse::&lt;Lit&gt;() {
                value.to_token_stream()
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">// If the input is neither an identifier nor a literal value</span>
                <span class="hljs-comment">// panic with appropriate error.</span>
                <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Value must be either a literal or an identifier!"</span>);
            };

            <span class="hljs-comment">// Push the parsed key value pair to our list.</span>
            entries.push(ParsedMapEntry(key, value));

            <span class="hljs-comment">// Check if next token is a comma, without advancing the stream</span>
            <span class="hljs-keyword">if</span> input.peek(Token![,]) {
                <span class="hljs-comment">// If it is, then parse it out and advance the stream before</span>
                <span class="hljs-comment">// moving on to the next key-value pair</span>
                input.parse::&lt;Token![,]&gt;()?;
            }
        }

        <span class="hljs-literal">Ok</span>(ParsedMap {
            value_type: ty,
            entries,
        })
    }
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">hash_mapify_impl</span></span>(item: TokenStream) -&gt; TokenStream {
    <span class="hljs-comment">// Parse input token stream as `ParsedMap` defined by us.</span>
    <span class="hljs-comment">// This will use the logic from parse trait we implemented</span>
    <span class="hljs-comment">// earlier.</span>
    <span class="hljs-keyword">let</span> input = parse_macro_input!(item <span class="hljs-keyword">as</span> ParsedMap);

    <span class="hljs-keyword">let</span> key_value_pairs = input.entries;
    <span class="hljs-keyword">let</span> ty = input.value_type;

    <span class="hljs-comment">// Generate the output hashmap inside a code block so that</span>
    <span class="hljs-comment">// we don't shadow any existing variables. Return the hashmap</span>
    <span class="hljs-comment">// from the block.</span>
    quote!({
        <span class="hljs-comment">// Create a new hashmap with `String` for key type and `#ty` for</span>
        <span class="hljs-comment">// value type, which parsed from the macro input arguments.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_map = std::collections::HashMap::&lt;<span class="hljs-built_in">String</span>, #ty&gt;::new();

        <span class="hljs-comment">// Insert all key-value pairs into the hashmap.</span>
        #(
            hash_map.insert(#key_value_pairs);
        )*

        <span class="hljs-comment">// Return the generated hashmap</span>
        hash_map
    })
    .into()
}
</code></pre>
<h3 id="heading-how-to-use-the-hashmapify-macro">How to Use the <code>hash_mapify</code> Macro</h3>
<p>We can verify that our macro works by writing a simple usage:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// src/main.rs</span>

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    test_hashmap();
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">test_hashmap</span></span>() {
    <span class="hljs-keyword">let</span> some_variable = <span class="hljs-string">"Some variable value"</span>;

    <span class="hljs-keyword">let</span> hash_map = hash_mapify!(
        &amp;<span class="hljs-built_in">str</span>,
        <span class="hljs-string">"first_key"</span> = <span class="hljs-string">"first_value"</span>,
        <span class="hljs-string">"second_variable"</span> = some_variable,
        some_key = <span class="hljs-string">"value for variable key"</span>,
    );

    <span class="hljs-keyword">let</span> number_hash_map =
        hash_mapify!(<span class="hljs-built_in">usize</span>, <span class="hljs-string">"first_key"</span> = <span class="hljs-number">1</span>, <span class="hljs-string">"second_variable"</span> = <span class="hljs-number">2</span>, some_key = <span class="hljs-number">3</span>,);

    dbg!(hash_map);
    dbg!(number_hash_map);
}
</code></pre>
<p>If you run this code, you should see the following output:</p>
<pre><code class="lang-shell">[src/main.rs:62:5] hash_map = {
    "first_key": "first_value",
    "some_key": "value for variable key",
    "second_variable": "Some variable value",
}
[src/main.rs:63:5] number_hash_map = {
    "second_variable": 2,
    "first_key": 1,
    "some_key": 3,
}
</code></pre>
<p>which is what we would expect to happen.</p>
<p>And now that we've covered all three types of procedural macros, we're going to wrap up the examples here.</p>
<h2 id="heading-beyond-writing-macros">Beyond Writing Macros</h2>
<p>Now that you've learned how to write basic derive macros, I'd like to take some time to quickly introduce some additional tools and techniques that will be helpful when working with macros. I'll also point out some drawbacks of why and when to avoid them.</p>
<h3 id="heading-helpful-cratestools">Helpful Crates/Tools</h3>
<p><a target="_blank" href="https://github.com/dtolnay/cargo-expand"><strong>cargo-expand</strong></a></p>
<p>This is a CLI tool that can generate macro expanded code for any file in your project. Another great project by <a target="_blank" href="https://crates.io/users/dtolnay">David Tolnay</a>. You do need the nightly toolchain for Rust to use this, though. Don't worry – it's only required for the tool itself to work. You don't need to make your project use the nightly toolchain as well. Your project can stay in the stable zone.</p>
<p>Install nightly toolchain:</p>
<pre><code class="lang-shell">rustup toolchain install nightly
</code></pre>
<p>Install <code>cargo-expand</code>:</p>
<pre><code class="lang-shell">cargo install cargo-expand
</code></pre>
<p>Now that this is done, you can see what the actual expansion of your code in main looks like. Simply run the following in the <code>my-app</code> project directory:</p>
<pre><code class="lang-shell">cargo expand
</code></pre>
<p>and it will output the expanded code in the terminal output. You will see some unfamiliar stuff as well, such as what the <code>dbg!</code> macro expands to, but you can ignore those.</p>
<p><strong><a target="_blank" href="https://docs.rs/trybuild/latest/trybuild/#">trybuild</a> &amp; <a target="_blank" href="https://docs.rs/macrotest/latest/macrotest/#">macrotest</a></strong></p>
<p>These are 2 crates that are extremely useful if you want to unit-test your procedural macros' expanded forms, or assert any expected compilation errors.</p>
<h2 id="heading-downsides-of-macros">Downsides of Macros</h2>
<h3 id="heading-debugging-or-lack-thereof">Debugging (or lack thereof)</h3>
<p>You cannot put a breakpoint into any line of code that is generated by the macro. Nor can you get to it from the stacktrace of an error. This makes debugging generated code very difficult. </p>
<p>In my usual workflow, I either put logging into the generated code, or if that is not enough, I replace the usage of macro with the code given to me by <code>cargo expand</code> temporarily to debug it, make changes, and then update the macro code based on that. </p>
<p>There might be better ways out there, and if you know any, I'd be grateful if you can share them with me.</p>
<h3 id="heading-compile-time-costs">Compile Time Costs</h3>
<p>There's a non-zero cost for macro expansion that the compiler needs to run and process, and then check that the code it generated is valid. This becomes even more expensive when recursive macros are involved. </p>
<p>As a very crude estimation, each macro expansion adds 10ms to the compile time of the project. If you're interested, I encourage you to read through this <a target="_blank" href="https://rustc-dev-guide.rust-lang.org/macro-expansion.html">introduction on how the compiler processes macros</a> internally.</p>
<h3 id="heading-lack-of-auto-complete-and-code-checks">Lack of Auto-complete and Code Checks</h3>
<p>Code written as part of a macro output isn't presently supported fully by any IDE, nor is it supported by rust-analyzer. So in most cases, you're writing code without relying on features such as auto-complete, auto-suggestions, and so on.</p>
<h3 id="heading-where-do-we-draw-the-line">Where Do We Draw the Line?</h3>
<p>Given the insane potential of macros, it's very easy to get carried away with them. It's important to remember all of the drawbacks and make decisions accordingly, ensuring that you are not indulging yourselves into premature abstraction. </p>
<p>As a general rule, I personally avoid implementing any "business logic" with macros, nor do I attempt to write macros for generating code that I will need to step through with a debugger time and again. Or the code that I will need to make micro changes in for performance testing and improvement.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>This was a long journey! But I wanted anyone with basic knowledge and experience with Rust to be able to follow and come out of this able to write macros in their own projects. </p>
<p>Hopefully, I was able to do that for you. I will be writing a lot more about macros in general, so stay tuned for that.</p>
<p>You can find the complete code for everything we looked at in this article in <a target="_blank" href="https://github.com/anshulsanghi-blog/macros-handbook">https://github.com/anshulsanghi-blog/macros-handbook</a> repository.</p>
<p>Also, feel free to <strong><a target="_blank" href="mailto:contact@anshulsanghi.tech">contact me</a></strong> if you have any questions or opinions on this topic.</p>
<h3 id="heading-enjoying-my-work"><strong>Enjoying my work?</strong></h3>
<p>Consider buying me a coffee to support my work!</p>
<p><a target="_blank" href="https://buymeacoffee.com/anshulsanghi">☕Buy me a coffee</a></p>
<p>Till next time, happy coding and wishing you clear skies!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Rust Tutorial – How to Build a Naïve Star Detector for Images ]]>
                </title>
                <description>
                    <![CDATA[ Star detection is a crucial step in many of the processing and analysis routines that we perform on astronomical images. It is extremely important for a process called plate-solving, which is the process of figuring out which part of the sky an image... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rust-tutorial-naive-star-detector-for-images/</link>
                <guid isPermaLink="false">66bb57a029aa951a4c0628bc</guid>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Anshul Sanghi ]]>
                </dc:creator>
                <pubDate>Tue, 16 Apr 2024 19:34:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/cover.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Star detection is a crucial step in many of the processing and analysis routines that we perform on astronomical images. It is extremely important for a process called plate-solving, which is the process of figuring out which part of the sky an image shows, or which part of the sky your telescope is pointed at. </p>
<p>All modern telescope mounts can make use of plate solving software to automatically figure out where they're pointed at, and in which direction they need to move to point at the correct location.</p>
<p>Star detection, sometimes, is also used in correcting the effect of atmosphere on the sharpness of targets such as galaxies. It is also crucial for combining astronomical images from multiple nights, telescopes, locations and so on into a single output image that has a very high signal-to-noise ratio.</p>
<p>With this tutorial, I'd like to introduce a very naïve technique for detecting stars in an image.</p>
<h3 id="heading-a-quick-note">A quick note:</h3>
<p>Star detection is a very complex topic, and I've only scratched the surface both in my own understanding and in this article. </p>
<p>The steps I use and describe in this article are derived from public documentation on existing real world applications (both for star detection and for edge detection), as well as some blog posts from incredibly knowledgeable people (which I link to at the end of the article, be sure to check them out).</p>
<p>As such, this implementation is intended for learning purposes only.</p>
<h2 id="heading-before-you-read"><strong>Before You Read</strong></h2>
<h3 id="heading-prerequisites-for-the-first-part-of-the-tutorial"><strong>Prerequisites for the first part of the tutorial</strong></h3>
<p>The process described builds upon the concept of <a target="_blank" href="https://www.freecodecamp.org/news/multi-scale-analysis-of-images-in-rust/">multi-scale processing of images using a trous wavelet transform</a>. If you're not aware of what that is, I encourage you to learn more about it using my previous article that I just linked to, and then come back to this one.</p>
<p>This article also assumes that you have a basic understanding of <a target="_blank" href="https://en.wikipedia.org/wiki/Centroid">Centroids</a>. Just knowing what they mean is enough, as you don't have to calculate them yourself. Since the article focuses on image processing and analysis, a basic understanding of how pixels work in digital format is helpful, but not mandatory.</p>
<h3 id="heading-prerequisites-for-the-second-part-of-this-tutorial"><strong>Prerequisites for the second part of this tutorial</strong></h3>
<p>Here, we focus on implementing the algorithm using the Rust programming language, without going much into the details of the language itself. So being comfortable writing Rust programs, and comfortable reading crate documentations is required.</p>
<p>If this is not you, you can still read Part 1 and learn the technique, and then maybe you'll want to then try it out in a language of your choice. </p>
<p>If you're not familiar with Rust, I highly encourage you to learn the basics. <a target="_blank" href="https://www.freecodecamp.org/news/rust-in-replit/">Here's an interactive Rust course</a> that can get you started.</p>
<h2 id="heading-table-of-contents">Table of contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-how-star-detection-works-1">How Star Detection Works</a><ol>
<li><a class="post-section-overview" href="#heading-what-is-star-detection">What is Star Detection?</a></li>
<li><a class="post-section-overview" href="#heading-how-star-detection-works-1">How Star Detection Works</a></li>
<li><a class="post-section-overview" href="#heading-an-intermediary-look-at-the-process">An Intermediary Look at the Process</a></li>
<li><a class="post-section-overview" href="#heading-picking-it-apart">Picking It Apart</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-how-to-implement-it-in-rust">How to Implement it in Rust</a><ol>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-read-and-decompose-the-input-image">How to read and decompose the input image</a></li>
<li><a class="post-section-overview" href="#heading-noise-reduction">Noise reduction</a></li>
<li><a class="post-section-overview" href="#heading-how-to-optimize-the-threshold-and-binarization">How to optimize the threshold and binarization</a></li>
<li><a class="post-section-overview" href="#heading-how-to-construct-polygons-around-stars">How to construct polygons around stars</a></li>
<li><a class="post-section-overview" href="#heading-how-to-detect-star-size-and-location-using-contours">How to detect star size and location using contours</a></li>
<li><a class="post-section-overview" href="#heading-how-to-encapsulate-the-process">How to encapsulate the process</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-the-implementation-on-astronomical-images">How to test the implementation on astronomical images</a></li>
<li><a class="post-section-overview" href="#heading-how-to-optimize-minimum-star-count">How to optimize minimum star count</a></li>
<li><a class="post-section-overview" href="#heading-but-there-is-one-more-thing">But there is one more thing...</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-further-reading">Further Reading</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-how-star-detection-works">How Star Detection Works</h2>
<p>Since this process involves a lot of steps, let's see how it works, with an increasing level of detail about what actually happens as we go along. With each increasing level, we'll be unwrapping the black box bit by bit.</p>
<h3 id="heading-what-is-star-detection">What is Star Detection?</h3>
<p>Star detection, at it's simplest form, involves isolating the stars from the rest of the image, and then performing edge detection on it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/m42-star-detection-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>1. Input image</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-1-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>2. Detected stars visualised using green circles</em></p>
<h3 id="heading-how-star-detection-works-1">How Star Detection Works</h3>
<p>First, you try to extract away the pixels that you think might be stars from the rest of the pixels in the image. This new image, that only contains the extracted pixels, is then analysed using edge detection techniques to find the star positions in 2D space.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/m42-star-detection-2.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>1. Input image</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-1-2-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>2. Extracted pixels that are potentially stars</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-1-1-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>3. Detected stars visualised using green circles</em></p>
<h3 id="heading-an-intermediary-look-at-the-process">An Intermediary Look At The Process</h3>
<p>Then, you decompose your input image into multiple layers, each layer containing a part of the original data such that adding all layers gives us back the original data. </p>
<p>You then isolate the layers that would only contain small sized structures, such as noise and stars, and throw away the rest of the data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/layers-of-structure.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Different layers of structure in the image that the input is decomposed into. We throw away the final layer and retain the rest in this example</em></p>
<p>With this filtered data, you find the edges in the image using the contouring technique (which is explained in the next section). Each contour gives us multiple "points" in the 2D space. You then try to draw a closed shape using the points you have. </p>
<p>Once you've done this, all you need is to find the center of this shape and you have the location of the stars.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/m42-star-detection-5.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>1. Input image</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-3-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>2. Image after decomposing into layers and throwing away large scale data</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-1-2-2.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>3. Image after binarisation</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/polygon.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>4. Detected contours visualised using green outlines</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-1-1-2.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>5. Detected stars visualised using green circles</em></p>
<h3 id="heading-picking-it-apart">Picking It Apart</h3>
<p>Using a multi-scale analysis technique facilitated by the à trous transform algorithm, you break down the image into multiple layers, each containing different scaled structures from the original image. You take the layers containing smaller scale structures and throw away the rest. </p>
<p>To these layers, you apply a bilateral denoising filter to reduce noise so that you can ensure that you're only left with stars and not noise that the algorithm might pick up as stars later on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/decomposed-image.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Different layers of structure in the image that the input is decomposed into. We throw away the final layer and retain the rest in this example.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/m42-star-detection-5-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>1. Input image</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-3-1-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>2. Image after decomposing into layers and throwing away large scale data</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/level-4-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>3. Noise reduced image</em></p>
<p>Once you've filtered out the noise, you binarize your image using thresholding. Thresholding and binarization is the process of converting all of the pixels to either pure black or pure white, so that they're easier to work with. You can do this by selecting a certain intensity value, and all pixels with intensity less than this become black and all pixels with intensity more than this become white. </p>
<p>To find the optimum intensity value to binarize the image with, you define a minimum number of stars that you expect to find in the image, which is usually determined based on what you actually need to do with your star locations. </p>
<p>In our example, we'll start with a minimum of 500 and slowly push it to the limit of the sample image to see what happens.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/level-1-2-3.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Binarizing noise-reduced and wavelet filtered image</em></p>
<p>This makes the process of edge detection (which is the next step in our process) using contouring much more reliable. </p>
<p>Contouring is a term that describes the process of figuring out where the structures are in your image, and drawing a border along those structures – these are known as contours. </p>
<p>It is similar to edge-detection, but edge-detection helps you differentiate between individual neighbouring pixels, whereas contours are designed to work with a complete boundary of any structures in an image.</p>
<p>The library we'll be using finds the contours in an image using the algorithm proposed by Suzuki and Abe: <a target="_blank" href="https://www.sciencedirect.com/science/article/abs/pii/0734189X85900167">Topological Structural Analysis of Digitized Binary Images by Border Following</a>. Contouring in this manner will give you a collection of points that lie on the border of each contour.</p>
<p>For each contour it finds, you create a polygon by joining all of the border points within that contour. If this shape is an open shape, then you just extrapolate the final border to create a polygon, which needs to be a closed shape. You then use the centroid formulae on this polygon to find the center of mass of your shape, which gives you the center of your star (in most cases). </p>
<p>You also need to find the euclidean distances between the center of mass and each border point, the longest of which becomes the size of the star.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/polygon-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Contouring the binarized image to find closed polygons around stars visualised here using green outlines</em></p>
<p>Once you have your star size, you reject any stars that are either smaller than 1 pixel or larger than 24 pixels. These are educated guesses that I use, and they seem to give me the best results for sample images (but this is definitely a potential point of improvement). </p>
<p>After all of this, you should have the x and y coordinates of the star, as well as its size in pixels.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/level-1-1-3.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Detected stars visualised using green circles around them</em></p>
<p>We're going to stop there, but there's a lot more that you can do after this step to remove false-positives and fix the centroid/size of stars. </p>
<h2 id="heading-how-to-implement-it-in-rust">How to Implement it in Rust</h2>
<p>Let's create a new library project:</p>
<pre><code class="lang-shell">cargo new --lib stardetect-rs &amp;&amp; cd stardetect-rs
</code></pre>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>You need a couple of dependencies to get started. Let's add them and I'll explain why you need them:</p>
<pre><code class="lang-shell">cargo add image imageproc image-dwt geo
</code></pre>
<ul>
<li><code>image</code> is a Rust library we'll use to work with images of all of the standard formats and encodings. It also helps us convert between various formats, and provides easy access to pixel data as buffers.</li>
<li><code>imageproc</code> is another library by the people who created the <code>image</code> library. It's an extension for the same as it implements image processing functions and algorithms for the <code>image</code> lib.</li>
<li><code>image-dwt</code> is my own library (shameless plug) that implements the <a target="_blank" href="https://www.freecodecamp.org/news/multi-scale-analysis-of-images-in-rust/">à trous wavelet decomposition algorithm</a> for <code>image</code> crate. This is needed to break down our image into multiple scales that I mentioned previously.</li>
<li><code>geo</code> is a Rust library that allows us to easily work with geometric types (like points in 2d space), shapes (such as polygons), and algorithms implemented for them. We use this library to build our polygon based on contour data, and to also find the centroid of the polygon that I described above. It also helps us compute euclidean distances between points, which we use for determining star size.</li>
</ul>
<h3 id="heading-how-to-read-and-decompose-the-input-image">How to read and decompose the input image</h3>
<p>You start by reading the input image and decomposing it so that you're only left with stars (and noise).</p>
<p>You need to define a new struct that will act as a wrapper for your input image, and add a constructor for it to create an instance of this struct based on input:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// lib.rs</span>
<span class="hljs-keyword">use</span> image::{DynamicImage, GrayImage};

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">StarDetect</span></span> {
    source: GrayImage,
}

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;DynamicImage&gt; <span class="hljs-keyword">for</span> StarDetect {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(source: DynamicImage) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">Self</span> {
            source: source.to_luma8(),
        }
    }
}
</code></pre>
<p>You then need to add the ability to extract the first <code>n</code> layers from wavelet decomposition of your image:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// lib.rs</span>

<span class="hljs-keyword">use</span> image_dwt::kernels::LinearInterpolationKernel;
<span class="hljs-keyword">use</span> image_dwt::recompose::{OutputLayer, RecomposableWaveletLayers};
<span class="hljs-keyword">use</span> image_dwt::transform::ATrousTransform;

<span class="hljs-keyword">impl</span> StarDetect {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">extract_small_scale_structures</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) {
        <span class="hljs-keyword">let</span> (width, height) = <span class="hljs-keyword">self</span>.source.dimensions();

        <span class="hljs-comment">// Decompose the image into 8 layers</span>
        <span class="hljs-keyword">let</span> filtered_image = ATrousTransform::new(
            &amp;DynamicImage::ImageLuma8(<span class="hljs-keyword">self</span>.source.clone()),
            <span class="hljs-number">8</span>,
            LinearInterpolationKernel,
        )
        <span class="hljs-comment">// Filter out the residue image and keep the rest</span>
        .filter(|item| item.pixel_scale.is_some())
        <span class="hljs-comment">// Recompose the first 3 layers into a grayscale image.</span>
        .recompose_into_image(width <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, height <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, OutputLayer::Grayscale);

        <span class="hljs-comment">// Update the source image that we will work with</span>
        <span class="hljs-comment">// going forward.</span>
        <span class="hljs-keyword">self</span>.source = filtered_image.to_luma8();
    }
}
</code></pre>
<h3 id="heading-noise-reduction">Noise reduction</h3>
<p>Now that you have the input image (which should only contain noise and stars), let's get rid of the noise:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// lib.rs</span>

<span class="hljs-keyword">impl</span> StarDetect {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">apply_noise_reduction</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) {
        <span class="hljs-keyword">self</span>.source = imageproc::filter::bilateral_filter(&amp;<span class="hljs-keyword">self</span>.source, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>., <span class="hljs-number">3</span>.);
    }
}
</code></pre>
<p>Next, you need to determine the optimum threshold value for a given minimum star count. You find it by picking a value and iteratively optimising it until you hit a star count that's more than the minimum.</p>
<h3 id="heading-how-to-optimize-the-threshold-and-binarization">How to optimize the threshold and binarization</h3>
<p>Start by creating a new file <code>threshold.rs</code> and defining a trait with necessary methods. You need a method to optimise your threshold value and another for performing the binarization operation:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// threshold.rs</span>

<span class="hljs-keyword">pub</span>(<span class="hljs-keyword">crate</span>) <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">ThresholdingExtensions</span></span> {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">optimize_threshold_for_star_count</span></span>(&amp;<span class="hljs-keyword">self</span>, min_star_count: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-built_in">u8</span>;
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">binarize</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, threshold: <span class="hljs-built_in">u8</span>);
}
</code></pre>
<p>Let's implement both of these:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// threshold.rs</span>

<span class="hljs-keyword">use</span> crate::centroid::find_star_centres_and_size;
<span class="hljs-keyword">use</span> crate::StarDetect;

<span class="hljs-keyword">impl</span> ThresholdingExtensions <span class="hljs-keyword">for</span> StarDetect {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">optimize_threshold_for_star_count</span></span>(&amp;<span class="hljs-keyword">self</span>, min_star_count: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-built_in">u8</span> {
        <span class="hljs-comment">// Current star count</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> star_count = <span class="hljs-number">0</span>;

        <span class="hljs-comment">// Starting threshold value</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> threshold = <span class="hljs-built_in">u8</span>::MAX;

        <span class="hljs-comment">// Iterate until you've found the best threshold</span>
        <span class="hljs-keyword">while</span> star_count &lt; min_star_count {
            <span class="hljs-comment">// Panic if we reach the 0 intensity value while iterating.</span>
            <span class="hljs-comment">// This means that there are fewer stars than we hoped for.</span>
            <span class="hljs-keyword">if</span> threshold == <span class="hljs-number">0</span> {
                <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"Maximum iteration count reached"</span>);
            }

            <span class="hljs-comment">// Reduce threshold to 95% of its previous value.</span>
            <span class="hljs-comment">// Using this, we check finer and finer differences</span>
            <span class="hljs-comment">// in threshold for each iteration.</span>
            threshold = (<span class="hljs-number">0.95</span> * threshold <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>;

            <span class="hljs-comment">// Clone the source data since we need to modify it</span>
            <span class="hljs-comment">// without affecting original data.</span>
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> source = <span class="hljs-keyword">self</span>.clone();

            <span class="hljs-comment">// Binarize the source data image using current threshold</span>
            ThresholdingExtensions::binarize(&amp;<span class="hljs-keyword">mut</span> source, threshold);

            <span class="hljs-comment">// Find the number of stars detected with the current threshold</span>
            star_count = find_star_centres_and_size(&amp;source.source).len();
        }

        threshold
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">binarize</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, threshold: <span class="hljs-built_in">u8</span>) {
        <span class="hljs-comment">// Iterate over every pixel in source image</span>
        <span class="hljs-keyword">for</span> pixel <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span>.source.iter_mut() {
            <span class="hljs-keyword">if</span> *pixel &gt; threshold {
                <span class="hljs-comment">// If pixel intensity is greater than threshold</span>
                <span class="hljs-comment">// set it to maximum intensity instead.</span>
                *pixel = <span class="hljs-built_in">u8</span>::MAX;
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">// Otherwise, set it to 0 intensity.</span>
                *pixel = <span class="hljs-number">0</span>;
            }
        }
    }
}
</code></pre>
<p>You might notice that we use the <code>find_star_centres_and_size</code> function when trying to find the optimised threshold value. We'll get to that shortly, as we need to declare some types that will hold the state of our computation before we implement the function.</p>
<p>Create a new file <code>centroid.rs</code>.</p>
<p>Define a new struct that will hold the coordinates and size of the star:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// centroid.rs</span>

<span class="hljs-keyword">use</span> imageproc::point::Point;

<span class="hljs-meta">#[derive(Eq, PartialEq, Copy, Clone, Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">StarCenter</span></span> {
    coord: Point&lt;<span class="hljs-built_in">u32</span>&gt;,
    radius: <span class="hljs-built_in">u32</span>,
}

<span class="hljs-keyword">impl</span> StarCenter {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">coord</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; &amp;Point&lt;<span class="hljs-built_in">u32</span>&gt; {
        &amp;<span class="hljs-keyword">self</span>.coord
    }
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">radius</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">u32</span> {
        <span class="hljs-keyword">self</span>.radius
    }
}
</code></pre>
<p>We've also defined methods to retrieve these fields. <code>Point</code> is a type provided to you by <code>imageproc</code> crate to store coordinates in an image.</p>
<h3 id="heading-how-to-construct-polygons-around-stars">How to construct polygons around stars</h3>
<p>We're going to implement this function inside out. We first need a way to construct our polygon from contours. Let's implement that:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// centroid.rs</span>

<span class="hljs-keyword">use</span> geo::LineString;
<span class="hljs-keyword">use</span> imageproc::contours::Contour;

<span class="hljs-keyword">pub</span>(<span class="hljs-keyword">crate</span>) <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">construct_closed_polygon</span></span>(contour: &amp;Contour&lt;<span class="hljs-built_in">u32</span>&gt;) -&gt; LineString&lt;<span class="hljs-built_in">f32</span>&gt; {
    <span class="hljs-comment">// Create a new line string that connects all points</span>
    <span class="hljs-comment">// in the contour. This can create either an open</span>
    <span class="hljs-comment">// or a closed shape.</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> line_string = LineString::from_iter(contour.points.iter().map(|point| Coord {
        x: point.x <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>,
        y: point.y <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>,
    }));

    <span class="hljs-comment">// If it is an open shape, close the shape to create a</span>
    <span class="hljs-comment">// polygon. This does nothing otherwise.</span>
    line_string.close();

    line_string
}
</code></pre>
<p><code>Contour</code> is a type provided by the <code>imageproc</code> crate, which is what it returns as the result of contouring operation on an image. It contains a list of points that lie on the border of the contour.</p>
<p><code>LineString</code> is a type provided by <code>geo</code> and is defined by them as "An ordered collection of two or more <a target="_blank" href="https://docs.rs/geo/latest/geo/geometry/struct.Coord.html"><code>Coord</code></a>s, representing a path between locations.". In this case, we use this type to construct the polygon shape.</p>
<h3 id="heading-how-to-detect-star-size-and-location-using-contours">How to detect star size and location using contours</h3>
<p>Next, you need a way to compute the <code>StarCenter</code> type we declared previously from contour data:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// centroid.rs</span>

<span class="hljs-keyword">use</span> geo::{Centroid, Coord, EuclideanDistance};

<span class="hljs-keyword">pub</span>(<span class="hljs-keyword">crate</span>) <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">filter_map_contour_to_star_centers</span></span>(contour: &amp;Contour&lt;<span class="hljs-built_in">u32</span>&gt;) -&gt; <span class="hljs-built_in">Option</span>&lt;StarCenter&gt; {
    <span class="hljs-comment">// If there are no points in the contour</span>
    <span class="hljs-comment">// it is not a star.</span>
    <span class="hljs-keyword">if</span> contour.points.is_empty() {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>;
    }

    <span class="hljs-keyword">if</span> contour.points.len() == <span class="hljs-number">1</span> {
        <span class="hljs-comment">// If there's only 1 point in the contour</span>
        <span class="hljs-comment">// consider it to be the center of the star</span>
        <span class="hljs-comment">// of size 1px.</span>
        <span class="hljs-keyword">let</span> center = contour.points.first().unwrap();
        <span class="hljs-keyword">let</span> radius = <span class="hljs-number">1_u32</span>;

        <span class="hljs-keyword">return</span> <span class="hljs-literal">Some</span>(StarCenter {
            coord: *center,
            radius,
        });
    }

    <span class="hljs-comment">// Otherwise, construct a polygon around the star based on</span>
    <span class="hljs-comment">// contour information.</span>
    <span class="hljs-keyword">let</span> polygon = construct_closed_polygon(contour);

    <span class="hljs-comment">// Find the centre of gravity of this polygon (centroid)</span>
    <span class="hljs-keyword">let</span> center = polygon.centroid().unwrap();

    <span class="hljs-comment">// Find the radius of the star based on maximum distance between</span>
    <span class="hljs-comment">// the centroid and any of the points in contour.</span>
    <span class="hljs-keyword">let</span> radius = polygon.points().fold(<span class="hljs-number">0</span>., |distance, point| {
        point.euclidean_distance(&amp;center).max(distance)
    });

    <span class="hljs-comment">// If the radius is less than 1px or more than 24px</span>
    <span class="hljs-comment">// we reject it as a non-star.</span>
    <span class="hljs-keyword">if</span> !(<span class="hljs-number">1</span>. ..=<span class="hljs-number">24</span>.).contains(&amp;radius) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>;
    }

    <span class="hljs-comment">// Construct star center based on previously computed information</span>
    <span class="hljs-literal">Some</span>(StarCenter {
        coord: Point {
            x: center.x() <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>,
            y: center.y() <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>,
        },
        radius: radius <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>,
    })
}
</code></pre>
<p>This function utilises the <code>construct_closed_polygon</code> function you defined previously to compute the final star centers and sizes. Now for the easy part: let's implement the missing <code>find_star_centres_and_size</code>:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// centroid.rs</span>

<span class="hljs-keyword">use</span> image::GrayImage;

<span class="hljs-keyword">pub</span>(<span class="hljs-keyword">crate</span>) <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">find_star_centres_and_size</span></span>(image: &amp;GrayImage) -&gt; <span class="hljs-built_in">Vec</span>&lt;StarCenter&gt; {
    <span class="hljs-comment">// Compute the contours in source image</span>
    <span class="hljs-keyword">let</span> contours = imageproc::contours::find_contours::&lt;<span class="hljs-built_in">u32</span>&gt;(image);

    contours
        .iter()
        <span class="hljs-comment">// Iterate over all contours and create a list</span>
        <span class="hljs-comment">// of star center and size data.</span>
        .filter_map(filter_map_contour_to_star_centers)
        .collect()
}
</code></pre>
<h3 id="heading-how-to-encapsulate-the-process">How to encapsulate the process</h3>
<p>All you need now is to implement one last method on the <code>StarDetect</code> struct that encapsulates the entire process:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// lib.rs</span>

<span class="hljs-keyword">use</span> crate::centroid::{find_star_centres_and_size, StarCenter};
<span class="hljs-keyword">use</span> crate::threshold::ThresholdingExtensions;

<span class="hljs-keyword">impl</span> StarDetect {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">find_stars</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, min_stars: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-built_in">Vec</span>&lt;StarCenter&gt; {
        <span class="hljs-keyword">self</span>.extract_small_scale_structures();
        <span class="hljs-keyword">self</span>.apply_noise_reduction();

        <span class="hljs-keyword">let</span> threshold = <span class="hljs-keyword">self</span>.optimize_threshold_for_star_count(min_stars);
        <span class="hljs-keyword">self</span>.binarize(threshold);

        find_star_centres_and_size(&amp;<span class="hljs-keyword">self</span>.source)
    }
}
</code></pre>
<p>This method only calls the functions we've written so far. The user of your library will only need to call this function and nothing else.</p>
<p>You can now use what you've created to find stars in an image. For this article going forward, the image I'll be using to demonstrate is shown below. If you'd like to follow along, you can download the image I'll be using from <a target="_blank" href="https://anshulsanghi-assets.s3.ap-south-1.amazonaws.com/m42-star-detection.jpg"><strong>here</strong></a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/m42-star-detection.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>M42 Orion Nebula, The Dark Horse Nebula, The Flaming Star Nebula And The Surrounding H-Alpha Gas</em></p>
<p>As you might notice, we have a wide range of star shapes, sizes and colors in this image, but the same goes for noise and other large-scale nebulae structures too.</p>
<h3 id="heading-how-to-test-the-implementation-on-astronomical-images">How to test the implementation on astronomical images</h3>
<p>Create a new file <code>main.rs</code> and declare it as a binary target in the <code>Cargo.toml</code> file. It should look like this:</p>
<pre><code class="lang-toml"><span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"stardetector"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

<span class="hljs-section">[[bin]]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"stardetector"</span>
<span class="hljs-attr">path</span> = <span class="hljs-string">"src/main.rs"</span>

<span class="hljs-comment"># See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html</span>

<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">geo</span> = <span class="hljs-string">"0.28.0"</span>
<span class="hljs-attr">image</span> = <span class="hljs-string">"0.25.1"</span>
<span class="hljs-attr">image-dwt</span> = <span class="hljs-string">"0.3.2"</span>
<span class="hljs-attr">imageproc</span> = <span class="hljs-string">"0.24.0"</span>
</code></pre>
<p>You can finally use the lib we created to process the sample image. The final code in <code>main.rs</code> should look like this:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> image::Rgba;
<span class="hljs-keyword">use</span> stardetector::StarDetect;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// Load the image as mutable. You need mutability so that</span>
    <span class="hljs-comment">// you can draw on this image.</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> image = image::open(<span class="hljs-string">"m42-star-detection.jpg"</span>).unwrap();

    <span class="hljs-comment">// Create a new star detector instance. You clone the image</span>
    <span class="hljs-comment">// here because you need to also draw on the image for</span>
    <span class="hljs-comment">// visualisation purposes in this example.</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> star_detector = StarDetect::from(image.clone());

    <span class="hljs-comment">// Run the star finder function with a minimum star count of</span>
    <span class="hljs-comment">// 500</span>
    <span class="hljs-keyword">let</span> stars = star_detector.find_stars(<span class="hljs-number">500</span>);

    <span class="hljs-comment">// Iterate over all stars you've found</span>
    <span class="hljs-keyword">for</span> star <span class="hljs-keyword">in</span> stars {
        <span class="hljs-comment">// Draw a hollow circle on the image so that you</span>
        <span class="hljs-comment">// can see what the algorithm found</span>
        imageproc::drawing::draw_hollow_circle_mut(
            &amp;<span class="hljs-keyword">mut</span> image,
            (star.coord().x <span class="hljs-keyword">as</span> <span class="hljs-built_in">i32</span>, star.coord().y <span class="hljs-keyword">as</span> <span class="hljs-built_in">i32</span>),
            <span class="hljs-comment">// Extend the radius by 4px so that it's easier to see</span>
            <span class="hljs-comment">// in the visualisation.</span>
            star.radius() <span class="hljs-keyword">as</span> <span class="hljs-built_in">i32</span> + <span class="hljs-number">4</span>,
            <span class="hljs-comment">// Draw the circle with a pure green color</span>
            Rgba([<span class="hljs-number">0</span>, <span class="hljs-built_in">u8</span>::MAX, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>]),
        );
    }

    <span class="hljs-comment">// Save the image with star positions annotated with</span>
    <span class="hljs-comment">// green circles.</span>
    image.save(<span class="hljs-string">"annotated.jpg"</span>).unwrap();
}
</code></pre>
<p>Ensure that the downloaded image is present at the root of this project folder.</p>
<p>We can finally run the program and see what it gives us:</p>
<pre><code class="lang-shell">cargo run --release
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p>That looks pretty good! If we zoom in to a small part of the image:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated-zoomed.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p>We can see that there are some minor issues with the algorithm, such as stars that are very close to each other and have an overlap of their halos are considered as a single star. The problem is quite an interesting one.</p>
<p>There are various techniques to solve this issue, but they're out of the scope of this article.</p>
<h3 id="heading-how-to-optimize-minimum-star-count">How to optimize minimum star count</h3>
<p>Let's crank up the minimum star count to <strong>1000</strong> and see what happens:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated1-zoomed.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p>This time, it picked up many of the fainter stars since the threshold had to be lower to accommodate for the higher minimum star count.</p>
<p>It's time to crank it up further! Let's try <strong>2000</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated2.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated2-zoomed.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p>It picked up even more stars this time, but it has also started hallucinating some stars where there are none. This is being caused by lower threshold retaining more noise in the image, which is then picked up as a star. But noise isn't as visible in the final image unless you really pixel-peep, which is why it appears that the algorithm is hallucinating stars.</p>
<p><strong>Noise</strong>, in this particular situation, not only refers to the noise in the traditional sense – but also to any pixels that do no belong to a star for this particular purpose.</p>
<h3 id="heading-but-there-is-one-more-thing">But there is one more thing...</h3>
<p>Let's crank the minimum star count up to the absolute maximum for this particular image, which I found to be <strong>3500</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated3.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/annotated3-zoomed.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A part of the orion region with detected stars annotated with green circles</em></p>
<p>The algorithm now seems to have failed us miserably, which is expected when the noise is too high. There are too many false-positives for this data to be of any use at all.</p>
<p>I wanted to show you this anyway because it shows you the flaws in the algorithm. It also shows you what star detection on noise signal looks like and why we need to pre-process an image to remove everything that isn't a star before we run the star detection.</p>
<p>We're going to stop here for the implementation, but there's many resources you can find below if you're interested in learning more about the topic.</p>
<p>The complete code for everything I talked about today can be found here: <a target="_blank" href="https://github.com/anshulsanghi-blog/stardetector">https://github.com/anshulsanghi-blog/stardetector</a></p>
<h2 id="heading-further-reading"><strong>Further Reading</strong></h2>
<p>These are some of the resources that were very helpful to me when I was trying to figure out how star detection works. The resources are more about plate-solving (the process of figuring out the exact coordinates in the night sky of things in an image), but star detection is a crucial part of that process.</p>
<ul>
<li><a target="_blank" href="https://olegignat.com/how-plate-solving-works/">How astronomic plate-solving works</a> by Oleg Ignat</li>
<li><a target="_blank" href="https://pixinsight.com/doc/tools/StarAlignment/StarAlignment.html#description_002">Star Detection during StarAlignment Process In PixInsight</a></li>
</ul>
<p>Stars have pretty interesting characteristics, some of which are unique such as their <a target="_blank" href="https://en.wikipedia.org/wiki/Point_spread_function">point-spread function</a> estimates. These characteristics can be implemented to further improve the star detection and filtering of false-positives.</p>
<p>In addition, I've created a Rust library that implements this algorithm, but has some additional features already, and more robust processes are in the works.</p>
<p>Things such as handling RGB images properly instead of converting them to grayscale are already implemented. It also has the ability to work with RAW images.</p>
<p>I'm also soon going to be working on performance improvements for the same.</p>
<p>If you want to learn more, or contribute to the library, feel free to do so. The repository can be found here: <a target="_blank" href="https://github.com/anshap1719/stardetect">https://github.com/anshap1719/stardetect</a>  </p>
<h2 id="heading-wrapping-up"><strong>Wrapping Up</strong></h2>
<p>I hope you enjoyed the journey so far. If image processing and analysis techniques or their implementation in Rust is something that interests you, then stay tuned for more as these are the topics I love writing about.</p>
<p>Also, feel free to <strong><a target="_blank" href="mailto:contact@anshulsanghi.tech">contact me</a></strong> if you have any questions or opinions on this topic.</p>
<h3 id="heading-enjoying-my-work"><strong>Enjoying my work?</strong></h3>
<p>Consider buying me a coffee to support my work!</p>


<p>Till next time, happy coding and wishing you clear skies!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Rust Tutorial – Learn Multi-Scale Processing of Astronomical Images ]]>
                </title>
                <description>
                    <![CDATA[ Recently, there's been a massive amount of effort put into developing novel image processing techniques. And many of them are derived from digital signal processing methods such as Fourier and Wavelet transforms.  These techniques have not only enabl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/multi-scale-analysis-of-images-in-rust/</link>
                <guid isPermaLink="false">66bb5795f55324ca867c88e2</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Anshul Sanghi ]]>
                </dc:creator>
                <pubDate>Wed, 10 Apr 2024 15:48:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Watermark.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Recently, there's been a massive amount of effort put into developing novel image processing techniques. And many of them are derived from digital signal processing methods such as Fourier and Wavelet transforms. </p>
<p>These techniques have not only enabled a wide range of image processing techniques such as noise reduction, sharpening, and dynamic-range extension, but have also enabled many techniques used in compute vision such as edge detection, object detection, and so on.</p>
<p>Multi-scale analysis is one of the newer techniques (relatively speaking) that has been adopted in a wide range of applications, especially in the astronomical image and data processing applications. This technique, which is based on Wavelet transform, allows us to divide our data into multiple signals, that all add up to make the final signal. </p>
<p>We can then perform our processing or analysis work on this individual sub-signals, allowing us to do targeted operations that do not affect other sub-signals. </p>
<p>In this tutorial, we'll first be exploring what the technique is all about, through the lens of a particular algorithm for performing multi-scale analysis on images. We'll then move on to looking at how we can implement what we discussed in the first part in Rust programming language and recreate the examples you see in the first half of the article.</p>
<h2 id="heading-before-you-read">Before You Read:</h2>
<h3 id="heading-prerequisites-for-part-1">Prerequisites for Part 1:</h3>
<p>The technique described is derived from the concept of "Wavelet Transforms". You don't need to know everything about it, but a very basic understanding will help you grasp the material better.</p>
<p>Since the article focuses on image processing and analysis, a basic understanding of how pixels work in digital format is helpful, but not mandatory.</p>
<h3 id="heading-prerequisites-for-part-2">Prerequisites for Part 2:</h3>
<p>Here, we focus on implementing the algorithm using the Rust programming language, without going much into the details of the language itself. So being comfortable writing Rust programs, and comfortable reading crate documentations is required.</p>
<p>If this is not you, you can still read Part 1 and learn the technique, and then maybe you'll want to then try it out in a language of your choice. If you're not familiar with Rust, I highly encourage you to learn the basics. <a target="_blank" href="https://www.freecodecamp.org/news/rust-in-replit/">Here's an interactive Rust course</a> that can get you started.</p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-part-1-understanding-the-multi-scale-processing-technique-and-algorithm">Part 1: Understanding Multi-Scale Processing Technique And Algorithm</a><ol>
<li><a class="post-section-overview" href="#heading-what-is-multi-scale-image-processing">What is multi-scale image processing</a></li>
<li><a class="post-section-overview" href="#heading-the-a-trous-wavelet-transform">The <em>À Trous</em> Wavelet Transform</a></li>
<li><a class="post-section-overview" href="#heading-scaling-functions">Scaling Functions</a></li>
<li><a class="post-section-overview" href="#heading-convolution-pixels-at-each-scale">Convolution Pixels At Each Scale</a></li>
<li><a class="post-section-overview" href="#heading-handling-boundary-conditions">Handling Boundary Conditions</a> </li>
<li><a class="post-section-overview" href="#heading-computing-maximum-possible-scales-for-any-given-image">Computing Maximum Possible Scales For Any Given Image</a></li>
<li><a class="post-section-overview" href="#heading-closing-notes">Closing Notes</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-part-2-how-to-implement-a-trous-tranform-in-rust">Part 2: How to Implement <em>À Trous</em> Tranform in Rust</a><ol>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-the-a-trous-transform">The <em>À Trous</em> Transform</a></li>
<li><a class="post-section-overview" href="#heading-iterators-and-the-a-trous-transform">Iterators And The <em>À Trous</em> Transform</a></li>
<li><a class="post-section-overview" href="#heading-convolution">Convolution</a></li>
<li><a class="post-section-overview" href="#heading-implementing-the-iterator">Implementing the Iterator</a></li>
<li><a class="post-section-overview" href="#heading-recomposition">Recomposition</a></li>
<li><a class="post-section-overview" href="#heading-using-the-a-trous-transform">Using The <em>À Trous</em> Transform</a></li>
<li><a class="post-section-overview" href="#heading-further-reading">Further Reading</a></li>
</ol>
</li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-part-1-understanding-the-multi-scale-processing-technique-and-algorithm">Part 1: Understanding the Multi-Scale Processing Technique and Algorithm</h2>
<p>So what do we mean when we talk about multi-scale processing or analysis of some data? Well, we usually mean breaking down the input data into multiple signals, each representing a particular scale of information. </p>
<p>Scale, when talking about image analysis, simply refers to the size of structures that we are looking at at any given time. It ignores everything else that's either smaller or larger than the current scale.</p>
<h3 id="heading-what-is-multi-scale-image-processing">What is multi-scale image processing?</h3>
<p>For images, "scales" generally refer to the size in pixels of various structures or details in the image. You'll be able to get an intuitive understanding by looking at the following example:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Processed.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Messier 33, AKA Triangulum Galaxy</em></p>
<p>Assuming our naïve understanding is correct, we can derive images of at-least the following 3 scales:</p>
<ul>
<li>Very small structures, usually the size of a single pixel. This layer, when separated from the rest of the image, will only contain the noise and some sharp stars for the most part.</li>
<li>Small structures, usually a few pixels in size. This layer, when separated, will contain all of the stars and the very fine details in the galaxy arms.</li>
<li>Large and very large scale structures, usually 100s of pixels in size. This layer, when separated, will contain the general size and shape of the galaxy at the center.</li>
</ul>
<p>Now the question becomes, <strong>why do we need to do all of this in the first place?</strong></p>
<p>The answer is simple: it allows us to make targeted enhancements and changes to an image. </p>
<p>For example, noise reduction on the overall image will usually result in a loss of sharpness in the galaxy. But since we have broken our image down into multiple scales, we can easily apply noise reduction to only the first few layers, as most of the random noise that is easy to remove resides only in lower scale layers. </p>
<p>We then re-combine the noise-reduced low-scale layers with unmodified large-scale ones, and we have an output that gives us noise reduction without a loss in quality.</p>
<p>Another peculiar thing about noise is that it's almost always present in just one of these layers, making noise reduction process both easy and non-destructive.</p>
<p>If you're more of a visual learner, let's see this in practice using the image we used above. We're gonna be working with the following grayscale version of that image, where I've also added random gaussian noise:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/m33-noise-lum-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Messier 33 AKA Triangulum Galaxy, Converted to grayscale and with added Gaussian noise</em></p>
<p>Performing scale-based layer separation on this image, we get the following results. Note that the results are rescaled to a range where they can be viewed as an image for representational purpose. The actual transform produces pixel values that don't make sense when looked at independently, but all of the techniques and calculations described in this tutorial can still be safely applied without rescale. The recomposition process automatically gives us back the correct range:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/trous-decomposition..jpg" alt="Image" width="600" height="400" loading="lazy">
<em>9-level À Trous Decomposition. From top-left to bottom-right, we have images at the following pixel scales: 1, 2 4, 8, 16, 32, 64, 128, 256 (powers of 2)</em></p>
<ol>
<li>The first and second layers contain the noise and stars. In this particular example, noise is mixed in with the stars. But using the first and second layers, we can easily target areas that are not present in the second layer, as we can be sure that those are where the noise is present in the first layer.</li>
<li>With the third layer, we still see the residue luminance from stars. But if you look closely, we also see very faintly the arms of the galaxy starting to appear.</li>
<li>From the fourth layer onwards, we see the galaxy at varying scales and detail levels, completely without the stars. We start with the finer details (relatively small scale details) and increasingly move on to larger and larger scale samples. By the end, we only see a vague shape where the galaxy used to be.</li>
</ol>
<p>From here on, we can selectively apply noise reduction to the first two layers. Then we can recombine all of the layers to create the following image that has very little noise while preserving the same amount of details in the stars and the galaxy arms:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/wavelet-processed.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Messier 33 AKA Triangulum Galaxy, result of recombining all layers but with noise reduction applied to the pixel scale 1 &amp; 2 layers</em></p>
<p>In its most basic form, multi-scale analysis involves breaking up your source image, commonly referred to as the "signal", into multiple "signals" – each containing the data for a particular scale in the source signal. </p>
<p>Scale, when talking about image signal here, refers to the distance between adjacent pixels that we take when creating the layer from the source image.</p>
<p>In practice, this technique is used as the one of the first steps in all kinds of astronomical data analysis and image processing. </p>
<p>As an example, you can use the technique to detect locations of stars while ignoring larger structures much more easily than would be possible otherwise.</p>
<h3 id="heading-the-a-trous-wavelet-transform">The <em>À Trous</em> Wavelet Transform</h3>
<p>All of what I've showed you previously, and all of what you're going to see in this tutorial, was achieved with wavelet decomposition and recomposition using the à <em>trous</em> algorithm for discreet wavelet transforms.</p>
<p>This algorithm has been used throughout the years for various applications. But it's become particularly important recently in astronomical image processing applications, where different objects and signals in an image can be completely separated based on structural scales.</p>
<p>Here's how the algorithm works:</p>
<ol>
<li>We start with the source image input and number of levels to decompose into n.</li>
<li>For each level n:<ul>
<li>We convolve the image with our scaling function (we'll see what this is in a bit), where adjacent pixels are considered to be <strong>2<sup>n</sup></strong> units apart from each other, giving us the result <strong>result<sub>n</sub></strong>. This is where the "À Trous" name comes from, which literally translates to "with holes".</li>
<li>The layer output <strong>output<sub>n</sub></strong> is then computed using <strong>input</strong> - <strong>result<sub>n</sub></strong>.</li>
<li>We then update <strong>input</strong> to equal <strong>result<sub>n</sub></strong>. This is also known as residue data which serves as the source data for next layer.</li>
</ul>
</li>
<li>Repeat the above steps for all levels.</li>
<li>In the end, we have 9 wavelet layers, and 1 residue layer. All 10 layers are required for the recomposition.</li>
</ol>
<p>For a more mathematical approach to understanding this algorithm, I encourage you to read about <a target="_blank" href="https://www.eso.org/sci/software/esomidas/doc/user/18NOV/volb/node317.html"><strong>the à trous algorithm here</strong></a><strong>.</strong> </p>
<p>The recomposition process is very straightforward: we just need to add all 10 layers together. We can chose to apply positive or negative <strong>bias</strong> to any of the layers, which is a factor by which to multiply the layer pixel values during recomposition. You can use it either to enhance or diminish the characteristics of that particular layer.</p>
<h3 id="heading-scaling-functions">Scaling Functions</h3>
<p>Scaling functions are specific <a target="_blank" href="https://en.wikipedia.org/wiki/Kernel_(image_processing)">convolution kernels</a> that help us better represent data at a particular scale based on our use case. There are 3 most commonly used scaling functions, which are shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/b3spline-level2.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/linear-level2.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/low-scale-level2.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The images above show the 3 most commonly used scaling functions in the À Trous algorithm, visualised using 3rd level decomposition of the triangulum galaxy image used previously:</p>
<ul>
<li>B3 Spline is a very smooth kernel. It is mostly used in isolation of large scale structures. If we wanted to sharpen our galaxy, we would have used this kernel.</li>
<li>Low-scale is a very sharply peaked kernel, and is best at working with small scale structures.</li>
<li>Linear interpolation kernel gives us the best of both worlds, and hence is used when we need to work with both small scale and large scale structures. This is what we have used in all of our previous examples.</li>
</ul>
<h3 id="heading-convolution-pixels-at-each-scale">Convolution Pixels At Each Scale</h3>
<p>I mentioned in the algorithm that at each scale, the pixels in the image are considered to be 2<sup>n</sup> units apart. Let's try to grasp a better understanding of this using the following visualisation:</p>
<p>Consider the following 8px by 8px image. Each pixel is labeled 1 through 64, which is their index.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1-32x32mm.png" alt="Image" width="600" height="400" loading="lazy">
<em>A representational pixel grid of a 8x8px image</em></p>
<p>We're going to focus on a convolution operation of one of the center pixels only for this example, let's say pixel number 28.</p>
<p><strong>Scale 0:</strong> At scale 0, the value of 2<sup>n</sup> becomes <strong>1</strong>. This means that for convolution, we'll consider pixels that are 1 unit apart from our target center pixel. These pixels are highlighted below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/scale0-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>8x8px grid with pixels that are involved in convolution for pixel number 28 highlighted at scale 0</em></p>
<p><strong>Scale 1:</strong> This is where things get interesting. At scale 1, the value of 2<sup>n</sup> becomes <strong>2</strong>. This means that for convolution, we'll jump directly to pixels that are 2 locations apart from the target pixel:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/scale1-3.png" alt="Image" width="600" height="400" loading="lazy">
<em>8x8px grid with pixels that are involved in convolution for pixel number 28 highlighted at scale 1</em></p>
<p>As you can see, we've created "holes" in our computation of the value of the target pixel by skipping <strong>2<sup>n</sup> - 1</strong> adjacent pixels and selecting the <strong>2<sup>n</sup>th</strong> pixel. This is the basis of the algorithm.</p>
<p>This process is repeated for every pixel in the image, just like a regular convolution process. And each time, we consider increasing distances between pixels for computation of final values at increasing scales. </p>
<p>Let's look at just one more scale.</p>
<p><strong>Scale 2</strong>: This is where things get even more interesting. At scale 2 the value of 2<sup>n</sup> becomes <strong>4</strong>. This means that for convolution, we'll jump directly to pixels that are <strong>4</strong> locations apart from the target pixel:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/scale2-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>8x8px grid with pixels that are involved in convolution for pixel number 28 highlighted at scale 2</em></p>
<p>Wait what? Why are we choosing pixels 1, 4, 8, 25, &amp; 57? 1 &amp; 4 are only 3 locations apart, 25 is only 2 locations apart, and 8 &amp; 57 are not even diagonally aligned with the target pixel. What's going on?</p>
<h3 id="heading-handling-boundary-conditions">Handling Boundary Conditions</h3>
<p>As we've mentioned that this process is executed for all of the pixels in an image, we also need to consider cases where the pixel locations for convolution lie outside of the image.</p>
<p>This is not a concept unique to this algorithm. During convolution, this is referred to as a boundary condition or handling boundary pixels. There are various techniques for dealing with this, and all of them involve virtually extending the image in order to make it seem like we're not encountering the boundary at all.</p>
<p>Some of the techniques are:</p>
<ul>
<li>Extending as much as needed by copying the value of the last row/column</li>
<li>Mirroring the image on all edges and corners</li>
<li>Wrapping the image around the edges.</li>
</ul>
<p>In our example, we're employing the "mirroring" technique. When implementing such an algorithm, we don't need to actually create an extended image. Any boundary handling is implementable using just basic mathematical formulae.</p>
<p>Our extended image, with the correct pixels selected for scale 2, is as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/scale2-mirrored.png" alt="Image" width="600" height="400" loading="lazy">
<em>Source image extended on all edges and corners using the mirroring technique. All of the faded regions represent extended areas.</em></p>
<p>Again, the extension is only logical and is completely computed using formulae, as opposed to actually extending the source image and then checking. We can easily see that with the mirrored images in place, our basic rule of picking pixels that are 2<sup>n</sup> locations apart is still followed.</p>
<h3 id="heading-computing-maximum-possible-scales-for-any-given-image">Computing Maximum Possible Scales for Any Given Image</h3>
<p>If you think about it carefully, you'll see that the maximum layers an image can be decomposed into can be calculated by computing the log<sub>2</sub> of the image width or height (whichever is lower) and throwing away the fractional part. </p>
<p>In our 5x5 image, log<sub>2</sub>(5) ~= <strong>2.32</strong>. If we throw away the fractional part, that leaves us with 2 layers. Similarly, for a 1000x1000px image, log<sub>2</sub>1000 ~= <strong>9.96</strong>, which means we can decompose a 1000x1000 px image into a maximum of 9 layers. It simply implies that our "holes" cannot be larger than the width or height.</p>
<p>Even with the mirroring extension we used above, if the holes are larger than the width of the image, they'll still end up outside of the extended regions, specially for corner or boundary pixels, making it impossible to perform convolution at that scale.</p>
<h3 id="heading-closing-notes">Closing Notes</h3>
<p>Thinking about the examples and visualisations a bit more, you can clearly see how and why this algorithm works, and how it's able to separate out structures in an image based on their sizes. The increasing hole sizes make it so that only structures larger than the hole itself are retained for any given layer.</p>
<p>A big advantage of using this algorithm is the computational cost. Since this doesn't involve Fourier or Wavelet transforms, the computational cost is quite low, relatively speaking. The memory cost, however, is indeed higher. But more often than not that is a good tradeoff.</p>
<p>Another advantage of this algorithm when comparing it to other discreet wavelet transform algorithms is that the size of source image is preserved throughout the entire process. There's no decimation or upscaling happening here, making this algorithm one of the easiest ones to understand and implement.</p>
<p>The algorithm is used in almost all of the astronomical image processing softwares such as <a target="_blank" href="https://pixinsight.com/">PixInsight</a>, <a target="_blank" href="https://siril.org/">Siril</a>, and many others.</p>
<p>This algorithm is also known by other names such as <strong>Stationary Wavelet Transform</strong> and <strong>Starlet Transform</strong>.</p>
<h2 id="heading-part-2-how-to-implement-a-trous-tranform-in-rust">Part 2: How to Implement <em>À Trous</em> Tranform in Rust</h2>
<p>Now I'm going to show you how you can implement this algorithm in Rust. </p>
<p>For the purposes of this tutorial, I'm going to assume that you're pretty familiar with Rust and its basic concepts, such as data-types, iterators, and traits and are comfortable writing programs that use these concepts. </p>
<p>I'm also going to assume that you have an understanding of what convolution and convolution kernels mean in this context.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>We're going to need a couple of dependencies. Before we get to that, let's quickly create a new project:</p>
<pre><code class="lang-shell">cargo new --lib atrous-rs
cd atrous-rs
</code></pre>
<p>Now let's all of the dependencies we need. We actually only need 2:</p>
<pre><code class="lang-shell">cargo add image ndarray
</code></pre>
<p><strong><code>image</code></strong> is a Rust library we'll use to work with images of all of the standard formats and encodings. It also helps us convert between various formats, and provides easy access to pixel data as buffers.</p>
<p><strong><code>ndarray</code></strong> is a Rust library that helps you you create, manipulate, and work with 2D, 3D, or N-Dimensional arrays. We can use nested Vectors, but using a project like ndarray is better in this case because we need to perform a lot of operations on both individual values as well as their neighbours. Not only is it much easier to do with <strong>ndarray</strong>, but they also have performance optimisations built in for many operations and CPU types.</p>
<p>Although I'll be covering the basic functions/traits/methods/data-types we use from these crates, I'm not going to go into too much detail for them. I encourage you to read the docs instead.</p>
<p>We're actually going to jump straight to algorithm implementation, and come back later to see how we can use it.</p>
<h3 id="heading-the-a-trous-transform">The <em>À Trous</em> Transform</h3>
<p>Create a new file that will hold our implementation. Let's name it <code>transform.rs</code>.</p>
<p>Start with adding the following struct, that will hold the information we need to perform the transform:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// transform.rs</span>

<span class="hljs-keyword">use</span> ndarray::Array2;

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ATrousTransform</span></span> {
    input: Array2&lt;<span class="hljs-built_in">f32</span>&gt;, <span class="hljs-comment">// `Array2&lt;f32&gt;` is a 2D array where each value is of type `f32`. This will hold our pixel data for input image.</span>
    levels: <span class="hljs-built_in">usize</span>, <span class="hljs-comment">// The number of levels or scales to decompose the image into</span>
    current_level: <span class="hljs-built_in">usize</span>, <span class="hljs-comment">// Current level that we need to generate. This holds the state of our iterator.</span>
    width: <span class="hljs-built_in">usize</span>, <span class="hljs-comment">// Width of input image</span>
    height: <span class="hljs-built_in">usize</span>, <span class="hljs-comment">// Height of input image</span>
}
</code></pre>
<p>We also need a way to create this struct easily. In our case, we want to be able to create it from the input image directly. Also, input image can be of any of the supported format and encoding, but we want a consistent color-type to implement the calculations, so we'll also need to convert the image to our expected format.</p>
<p>It's helpful to extract all of this logic away using the "constructor" pattern in Rust. Let's implement that:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// transform.rs</span>

<span class="hljs-keyword">use</span> image::GenericImageView;

<span class="hljs-keyword">impl</span> ATrousTransform {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(input: &amp;image::DynamicImage, levels: <span class="hljs-built_in">usize</span>) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">let</span> (width, height) = input.dimensions();
        <span class="hljs-keyword">let</span> (width, height) = (width <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, height <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>);

        <span class="hljs-comment">// Create a new 2D array with proper size for each dimension to hold all of our input's pixel data. Method `zeros` takes a "shape" parameter, which is a tuple of (rows_count, columns_count).</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> data = Array2::&lt;<span class="hljs-built_in">f32</span>&gt;::zeros((height, width));

        <span class="hljs-comment">// Convert the image to be a grayscale image where each pixel value is of type `f32`. Loop over all pixels in the input image along with its 2D location.</span>
        <span class="hljs-keyword">for</span> (x, y, pixel) <span class="hljs-keyword">in</span> input.to_luma32f().enumerate_pixels() {
            <span class="hljs-comment">// Put the pixel value at appropriate location in our data array. The `[[]]` syntax is used to provide a 2-dimensional index such as `[[row_index, col_index]]`</span>
            data[[y <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, x <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>]] = pixel.<span class="hljs-number">0</span>[<span class="hljs-number">0</span>];
        }

        <span class="hljs-keyword">Self</span> {
            input: data,
            levels,
            current_level: <span class="hljs-number">0</span>,
            width,
            height
        }
    }
}
</code></pre>
<p>This takes care of converting the image to grayscale and converting the pixel values to <code>f32</code>. If you're not already aware, for images with floating-point pixel values, the values are always normalized. This means that they are always between 0 and 1 – 0 representing black and 1 representing white.</p>
<h3 id="heading-iterators-and-the-a-trous-transform">Iterators and the <em>À Trous</em> Transform</h3>
<p>Before we continue, let's think about the algorithm for a second. We need to be able to generate images at increasing scales, until we hit the maximum number of levels we need. </p>
<p>We want the consumer of our library to have access to all of these scales, and be able to manipulate them and also easily recombine once they're done. They need to be able to filter layers to ignore structures at certain scales, manipulate or "map" them to change their characteristics, perform operations on them, or even store each image if they so need.</p>
<p>This sounds an awful lot like Iterators! Iterators give us methods like <code>filter</code>, <code>skip</code>, <code>take</code>, <code>map</code>, <code>for_each</code>, and so on, all of which are exactly all we need to work with our layers before recomposition.</p>
<p>One added advantage of Iterators is that it allows you to finish processing each layer all the way through before you move on to the next one. If you're unsure why this is, I suggest reading more about <a target="_blank" href="https://doc.rust-lang.org/book/ch13-02-iterators.html">processing a series of items with Iterators in Rust</a>.</p>
<p>We're going implement the <code>Iterator</code> trait for our <code>ATrousTransform</code> type which should produce a wavelet layer as output for each iteration. </p>
<p>We're going to be implementing the inner-most parts of the algorithm first, and build out from there. So we first need a way to convolve an input data buffer with the scaling function while making sure that adjacent pixels are 2<sup>n</sup> locations apart, which is the first step in our loop.</p>
<h3 id="heading-convolution">Convolution</h3>
<p>We need to define our convolution kernel before we can do anything else. Create a new file <code>kernel.rs</code> and add it to <code>lib.rs</code> with the following contents:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// kernel.rs</span>

<span class="hljs-meta">#[derive(Copy, Clone)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">LinearInterpolationKernel</span></span> {
    values: [[<span class="hljs-built_in">f32</span>; <span class="hljs-number">3</span>]; <span class="hljs-number">3</span>]
}

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Default</span> <span class="hljs-keyword">for</span> LinearInterpolationKernel {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">Self</span> {
            values: [
                [<span class="hljs-number">1</span>. / <span class="hljs-number">16</span>., <span class="hljs-number">1</span>. / <span class="hljs-number">8</span>., <span class="hljs-number">1</span>. / <span class="hljs-number">16</span>.],
                [<span class="hljs-number">1</span>. / <span class="hljs-number">8</span>., <span class="hljs-number">1</span>. / <span class="hljs-number">4</span>., <span class="hljs-number">1</span>. / <span class="hljs-number">8</span>.],
                [<span class="hljs-number">1</span>. / <span class="hljs-number">16</span>., <span class="hljs-number">1</span>. / <span class="hljs-number">8</span>., <span class="hljs-number">1</span>. / <span class="hljs-number">16</span>.],
            ]
        }
    }
}
</code></pre>
<p>We define it using a struct instead of a constant array of arrays because we need to define some tiny helpful methods on it related to index handling. We'll come back to that later.</p>
<p>Create another file <code>convolve.rs</code>. This is where all of the code for handling convolution for individual pixels will go. We'll define a <code>Convolution</code> trait that will define methods needed to perform the convolution on every pixel in current layer.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// convolve.rs</span>

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Convolution</span></span> {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">compute_pixel_index</span></span>(
        &amp;<span class="hljs-keyword">self</span>,
        distance: <span class="hljs-built_in">usize</span>,
        kernel_index: [<span class="hljs-built_in">isize</span>; <span class="hljs-number">2</span>],
        target_pixel_index: [<span class="hljs-built_in">usize</span>; <span class="hljs-number">2</span>]
    ) -&gt; [<span class="hljs-built_in">usize</span>; <span class="hljs-number">2</span>];

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">compute_convoluted_pixel</span></span>(
        &amp;<span class="hljs-keyword">self</span>, 
        distance: <span class="hljs-built_in">usize</span>, 
        index: [<span class="hljs-built_in">usize</span>; <span class="hljs-number">2</span>]
    ) -&gt; <span class="hljs-built_in">f32</span>;
}
</code></pre>
<p>You may ask why we need a trait here instead of a simple <code>impl</code> block. We are only working with Grayscale images in this article, but you may want to extend it to implement it for RGB or other color modes as well.</p>
<p>Now, you need to implement this trait for your <code>ATrousTransform</code> struct:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// convolve.rs</span>

<span class="hljs-keyword">impl</span> Convolution <span class="hljs-keyword">for</span> ATrousTransform {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">compute_pixel_index</span></span>(
        &amp;<span class="hljs-keyword">self</span>, 
        distance: <span class="hljs-built_in">usize</span>, 
        kernel_index: [<span class="hljs-built_in">isize</span>; <span class="hljs-number">2</span>], 
        target_pixel_index: [<span class="hljs-built_in">usize</span>; <span class="hljs-number">2</span>]
    ) -&gt; [<span class="hljs-built_in">usize</span>; <span class="hljs-number">2</span>] {
        <span class="hljs-keyword">let</span> [kernel_index_x, kernel_index_y] = kernel_index;

        <span class="hljs-comment">// Compute the actual distance of adjacent pixel</span>
        <span class="hljs-comment">// by multiplying their relative position with the</span>
        <span class="hljs-comment">// size of the hole.</span>
        <span class="hljs-keyword">let</span> x_distance = kernel_index_x * distance <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span>;
        <span class="hljs-keyword">let</span> y_distance = kernel_index_y * distance <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span>;

        <span class="hljs-keyword">let</span> [x, y] = target_pixel_index;

        <span class="hljs-comment">// Compute the index of adjacent pixel in the 2D</span>
        <span class="hljs-comment">// image based on the index of current pixel.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> x = x <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span> + x_distance;
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> y = y <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span> + y_distance;

        <span class="hljs-comment">// If x index is out of bounds, consider x to be</span>
        <span class="hljs-comment">// the nearest boundary location</span>
        <span class="hljs-keyword">if</span> x &lt; <span class="hljs-number">0</span> {
            x = <span class="hljs-number">0</span>;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> x &gt; <span class="hljs-keyword">self</span>.width <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span> - <span class="hljs-number">1</span> {
            x = <span class="hljs-keyword">self</span>.width <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span> - <span class="hljs-number">1</span>;
        }

        <span class="hljs-comment">// If y index is out of bounds, consider y to be</span>
        <span class="hljs-comment">// the nearest boundary location</span>
        <span class="hljs-keyword">if</span> y &lt; <span class="hljs-number">0</span> {
            y = <span class="hljs-number">0</span>;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> y &gt; <span class="hljs-keyword">self</span>.height <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span> - <span class="hljs-number">1</span> {
            y = <span class="hljs-keyword">self</span>.height <span class="hljs-keyword">as</span> <span class="hljs-built_in">isize</span> - <span class="hljs-number">1</span>;
        }

        <span class="hljs-comment">// The final 2D index of pixel.</span>
        [y <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, x <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>]
    }

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">compute_convoluted_pixel</span></span>(
        &amp;<span class="hljs-keyword">self</span>, 
        distance: <span class="hljs-built_in">usize</span>, 
        [x, y]: [<span class="hljs-built_in">usize</span>; <span class="hljs-number">2</span>]
    ) -&gt; <span class="hljs-built_in">f32</span> {
        <span class="hljs-comment">// Create new variable to hold the result of convolution</span>
        <span class="hljs-comment">// for current pixel.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> pixels_sum = <span class="hljs-number">0.0</span>;

        <span class="hljs-keyword">let</span> kernel = LinearInterpolationKernel::default();

        <span class="hljs-comment">// Iterate over relative position of pixels from the center</span>
        <span class="hljs-comment">// pixel to perform convolution with. In other words, </span>
        <span class="hljs-comment">// these are the indexes of neighbouring pixels from the</span>
        <span class="hljs-comment">// center pixel.</span>
        <span class="hljs-keyword">for</span> kernel_index_x <span class="hljs-keyword">in</span> -<span class="hljs-number">1</span>..=<span class="hljs-number">1</span> {
            <span class="hljs-keyword">for</span> kernel_index_y <span class="hljs-keyword">in</span> -<span class="hljs-number">1</span>..=<span class="hljs-number">1</span> {
                <span class="hljs-comment">// Get the computed pixel location that maps to</span>
                <span class="hljs-comment">// the current position in kernel</span>
                <span class="hljs-keyword">let</span> pixel_index = <span class="hljs-keyword">self</span>.compute_pixel_index(
                    distance,
                    [kernel_index_x, kernel_index_y],
                    [x, y]
                );

                <span class="hljs-comment">// Get the multiplicative factor (kernel value) for </span>
                <span class="hljs-comment">// this relative location from the kernel.</span>
                <span class="hljs-keyword">let</span> kernel_value = kernel.value_from_relative_index(
                    kernel_index_x,
                    kernel_index_y
                );

                <span class="hljs-comment">// Multiply the pixel value with kernel scaling</span>
                <span class="hljs-comment">// factor and add it to the pixel sum.</span>
                pixels_sum += kernel_value * <span class="hljs-keyword">self</span>.input[pixel_index];
            }
        }

        <span class="hljs-comment">// Return the value of computed pixel from convolution process.</span>
        pixels_sum
    }
}
</code></pre>
<p>We need to do computations to figure out each pixel's location based on the relative position in the kernel from the center pixel as well as ensure that the "hole size" is also being taken into consideration for the final pixel index. As you might notice, you also want to handle the boundary conditions when computing indexes.</p>
<p>I encourage to take your time here and go through the code and the comments.</p>
<h3 id="heading-implementing-the-iterator">Implementing the Iterator</h3>
<p>It's finally time to implement the <code>Iterator</code> trait for your <code>ATrousTransform</code>:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// transform.rs</span>

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Iterator</span> <span class="hljs-keyword">for</span> ATrousTransform {
    <span class="hljs-comment">// Our output is an image as well as the current level for each</span>
    <span class="hljs-comment">// iteration. The current level is an `Option` to represent the</span>
    <span class="hljs-comment">// final residue layer after the intermediary layers have been</span>
    <span class="hljs-comment">// generated.</span>
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Item</span></span> = (Array2::&lt;<span class="hljs-built_in">f32</span>&gt;, <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">usize</span>&gt;);

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">next</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;Self::Item&gt; {
        <span class="hljs-keyword">let</span> pixel_scale = <span class="hljs-keyword">self</span>.current_level;
        <span class="hljs-keyword">self</span>.current_level += <span class="hljs-number">1</span>;

        <span class="hljs-comment">// We've already generated all the layers. Return None to </span>
        <span class="hljs-comment">// exit the iterator.</span>
        <span class="hljs-keyword">if</span> pixel_scale &gt; <span class="hljs-keyword">self</span>.levels {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>;
        }

        <span class="hljs-comment">// We've generated all intermediary layers, return the </span>
        <span class="hljs-comment">// residue layer.</span>
        <span class="hljs-keyword">if</span> pixel_scale == <span class="hljs-keyword">self</span>.levels {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Some</span>((<span class="hljs-keyword">self</span>.input.clone(), <span class="hljs-literal">None</span>))
        }

        <span class="hljs-keyword">let</span> (width, height) = (<span class="hljs-keyword">self</span>.width, <span class="hljs-keyword">self</span>.height);

        <span class="hljs-comment">// Distance between adjacent pixels for convolution (also </span>
        <span class="hljs-comment">// referred to as size of "hole").</span>
        <span class="hljs-keyword">let</span> distance = <span class="hljs-number">2_usize</span>.pow(pixel_scale <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>);

        <span class="hljs-comment">// Create new buffer to hold the computed data for this layer.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> current_data = Array2::&lt;<span class="hljs-built_in">f32</span>&gt;::zeros((height, width));

        <span class="hljs-comment">// Iterate over each pixel location in the 2D image</span>
        <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..width {
            <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..height {
                <span class="hljs-comment">// Set the current pixel in current layer to</span>
                <span class="hljs-comment">// the result of convolution on the current</span>
                <span class="hljs-comment">// pixel in input data.</span>
                current_data[[y, x]] = <span class="hljs-keyword">self</span>.compute_convoluted_pixel(
                    distance, 
                    [x, y]
                );
            }
        }

        <span class="hljs-comment">// Create current layer by subtracting currently computed pixels </span>
        <span class="hljs-comment">// from previous layer</span>
        <span class="hljs-keyword">let</span> final_data = <span class="hljs-keyword">self</span>.input.clone() - &amp;current_data;

        <span class="hljs-comment">// Set the input layer to equal the current computed layer so </span>
        <span class="hljs-comment">// that it can be used as the "previous layer" in next iteration.</span>
        <span class="hljs-comment">// This is also our residue data for each layer.</span>
        <span class="hljs-keyword">self</span>.input = current_data;

        <span class="hljs-comment">// Return the current layer data as well as current level information.</span>
        <span class="hljs-literal">Some</span>((final_data, <span class="hljs-literal">Some</span>(<span class="hljs-keyword">self</span>.current_level)))
    }
}
</code></pre>
<p>I'm going to point out that there's a lot of potential for optimizing for performance here, but that's out of the scope of this article.</p>
<p>We'll finally look at how we can take all of these layers and reconstruct our input image.</p>
<h3 id="heading-recomposition">Recomposition</h3>
<p>As I've said previously, reconstructing an image that was decomposed with the A Trous transform is as simple as summing all of the layers together.</p>
<p>We're going to define a trait for this. Why we need a trait here should be clear once you look at the implementation.</p>
<p>Create a new file <code>recompose.rs</code> with the following contents:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// recompose.rs</span>

<span class="hljs-keyword">use</span> image::{DynamicImage, ImageBuffer, Luma};
<span class="hljs-keyword">use</span> ndarray::Array2;

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">RecomposableLayers</span></span>: <span class="hljs-built_in">Iterator</span>&lt;Item = (Array2&lt;<span class="hljs-built_in">f32</span>&gt;, <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">usize</span>&gt;)&gt; {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">recompose_into_image</span></span>(
        <span class="hljs-keyword">self</span>,
        width: <span class="hljs-built_in">usize</span>,
        height: <span class="hljs-built_in">usize</span>,
    ) -&gt; DynamicImage
        <span class="hljs-keyword">where</span>
            <span class="hljs-keyword">Self</span>: <span class="hljs-built_in">Sized</span>,
    {
        <span class="hljs-comment">// Create a result buffer to hold the pixel data for our output image.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> result = Array2::&lt;<span class="hljs-built_in">f32</span>&gt;::zeros((height, width));

        <span class="hljs-comment">// For each layer, add the layer data to current value of result buffer.</span>
        <span class="hljs-keyword">for</span> layer <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span> {
            result += &amp;layer.<span class="hljs-number">0</span>;
        }

        <span class="hljs-comment">// Compute min and max pixel intensity values in the final data so that</span>
        <span class="hljs-comment">// we can perform a "rescale", which normalizes all pixel values to be</span>
        <span class="hljs-comment">// between the range of 0 &amp; 1, as is expected by float 32 images.</span>
        <span class="hljs-keyword">let</span> min_pixel = result.iter().copied().reduce(<span class="hljs-built_in">f32</span>::min).unwrap();
        <span class="hljs-keyword">let</span> max_pixel = result.iter().copied().reduce(<span class="hljs-built_in">f32</span>::max).unwrap();

        <span class="hljs-comment">// Create a new `ImageBuffer`, which is a type provided by `image` crate to</span>
        <span class="hljs-comment">// serve as buffer for pixel data of an image. Here, we're creating a new</span>
        <span class="hljs-comment">// `Luma` ImageBuffer with pixel value of type `u16`. Luma just refers to</span>
        <span class="hljs-comment">// grayscale.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> result_img: ImageBuffer&lt;Luma&lt;<span class="hljs-built_in">u16</span>&gt;, <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u16</span>&gt;&gt; =
            ImageBuffer::new(width <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>, height <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>);

        <span class="hljs-comment">// Pre-compute the denominator for scaling computation so that we don't</span>
        <span class="hljs-comment">// repeat this unnecessarily for every iteration.</span>
        <span class="hljs-keyword">let</span> rescale_ratio = max_pixel - min_pixel;

        <span class="hljs-comment">// Iterate over all pixels in the `ImageBuffer` and fill it based on data</span>
        <span class="hljs-comment">// from the `result` buffer after rescaling the value.</span>
        <span class="hljs-keyword">for</span> (x, y, pixel) <span class="hljs-keyword">in</span> result_img.enumerate_pixels_mut() {
            <span class="hljs-keyword">let</span> intensity = result[(y <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, x <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>)];

            *pixel =
                Luma([((intensity - min_pixel) / rescale_ratio * <span class="hljs-built_in">u16</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>]);
        }

        <span class="hljs-comment">// Convert the `ImageBuffer` into `DynamicImage` and return it</span>
        DynamicImage::ImageLuma16(result_img)
    }
}

<span class="hljs-comment">// Implement this trait for anything that implements the Iterator trait</span>
<span class="hljs-comment">// with the given item type</span>
<span class="hljs-keyword">impl</span>&lt;T&gt; RecomposableLayers <span class="hljs-keyword">for</span> T <span class="hljs-keyword">where</span> T: <span class="hljs-built_in">Iterator</span>&lt;Item = (Array2&lt;<span class="hljs-built_in">f32</span>&gt;, <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">usize</span>&gt;)&gt; {}
</code></pre>
<p>If you haven't noticed, since we implement this trait for a generic, this will work with any iterator, such as <code>Filter</code>, <code>Map</code>, and so on. If you didn't use a trait here, you'll have had to implement the same thing again and again for every built-in iterator type, and your code wouldn't have worked with 3rd party types.</p>
<h3 id="heading-using-the-a-trous-transform">Using the <em>À Trous</em> Transform</h3>
<p>After all of that, it's finally time to reproduce the processing that I showed you for the galaxy image with lots of noise. Create a new file <code>main.rs</code> with the following contents:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> image::{DynamicImage, ImageBuffer, Luma};
<span class="hljs-keyword">use</span> atrous::recompose::RecomposableLayers;
<span class="hljs-keyword">use</span> atrous::transform::ATrousTransform;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// Open our noisy image</span>
    <span class="hljs-keyword">let</span> image = image::open(<span class="hljs-string">"m33-noise-lum.jpg"</span>).unwrap();

    <span class="hljs-comment">// Create a new instance of the transform with 9 layers</span>
    <span class="hljs-keyword">let</span> transform = ATrousTransform::new(&amp;image, <span class="hljs-number">9</span>);

    <span class="hljs-comment">// Map over each layer</span>
    transform.map(|(<span class="hljs-keyword">mut</span> buffer, pixel_scale)| {
        <span class="hljs-comment">// Create a new image buffer to hold the pixel data. This</span>
        <span class="hljs-comment">// will be populated from the raw buffer for this layer.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> new_buffer =
            ImageBuffer::&lt;Luma&lt;<span class="hljs-built_in">u16</span>&gt;, <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u16</span>&gt;&gt;::new(buffer.ncols() <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>, buffer.nrows() <span class="hljs-keyword">as</span> <span class="hljs-built_in">u32</span>);

        <span class="hljs-comment">// Iterate over all pixels of the `ImageBuffer` to populate it. We also</span>
        <span class="hljs-comment">// convert from `f32` pixels to `u16` pixels.</span>
        <span class="hljs-keyword">for</span> (x, y, pixel) <span class="hljs-keyword">in</span> new_buffer.enumerate_pixels_mut() {
            *pixel = Luma([(buffer[[y <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, x <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>]] * <span class="hljs-built_in">u16</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">u16</span>])
        }

        <span class="hljs-comment">// If the present layer is a small scale layer (&lt; 3), </span>
        <span class="hljs-comment">// perform noise reduction</span>
        <span class="hljs-keyword">if</span> pixel_scale.is_some_and(|scale| scale &lt; <span class="hljs-number">3</span>) {
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> image = DynamicImage::ImageLuma16(new_buffer).to_luma8();

            <span class="hljs-comment">// Bilateral filter is a de-noising filter. Apply it to the image.</span>
            image = imageproc::filter::bilateral_filter(&amp;image, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>., <span class="hljs-number">3</span>.);

            <span class="hljs-comment">// Modify the raw buffer to contain the updated pixel values after</span>
            <span class="hljs-comment">// filtering.</span>
            <span class="hljs-keyword">for</span> (x, y, pixel) <span class="hljs-keyword">in</span> image.enumerate_pixels() {
                buffer[[y <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, x <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>]] = pixel.<span class="hljs-number">0</span>[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / <span class="hljs-built_in">u8</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;
            }

            <span class="hljs-comment">// Return the updated buffer.</span>
            (buffer, pixel_scale)
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Return the unmodified buffer for larger scale layers.</span>
            (buffer, pixel_scale)
        }
    })
        <span class="hljs-comment">// Call the recomposition method on iterator</span>
        .recompose_into_image(image.width() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>, image.height() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>)
        <span class="hljs-comment">// Convert output to 8-bit grayscale image</span>
        .to_luma8()
        <span class="hljs-comment">// Save it to jpg file</span>
        .save(<span class="hljs-string">"noise-reduced.jpg"</span>)
        .unwrap()
}
</code></pre>
<p>You also need to add a new dependency, <code>imageproc</code>, which provides useful image processing implementations on top of the <code>image</code> crate.</p>
<pre><code class="lang-shell">cargo add imageproc
</code></pre>
<p>To make this work, we also need to modify our <code>Cargo.toml</code> to explicitly define both binary and library targets:</p>
<pre><code class="lang-toml">// Cargo.toml

<span class="hljs-section">[package]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"atrous-rs"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

<span class="hljs-section">[[bin]]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"atrous"</span>
<span class="hljs-attr">path</span> = <span class="hljs-string">"src/main.rs"</span>

<span class="hljs-section">[lib]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"atrous"</span>
<span class="hljs-attr">path</span> = <span class="hljs-string">"src/lib.rs"</span>

<span class="hljs-comment"># See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html</span>

<span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">image</span> = <span class="hljs-string">"0.25.1"</span>
<span class="hljs-attr">imageproc</span> = <span class="hljs-string">"0.24.0"</span>
<span class="hljs-attr">ndarray</span> = <span class="hljs-string">"0.15.6"</span>
</code></pre>
<p>You may download the test image from <a target="_blank" href="https://anshulsanghi-assets.s3.ap-south-1.amazonaws.com/m33-noise-lum.jpg">here</a>. Move it to the root directory of your project, and run <code>cargo run --release</code>. Once it finishes, you should have a new file <code>noise-reduced.jpg</code> as the output of our process.</p>
<p>And there we have it.</p>
<h2 id="heading-further-reading">Further Reading</h2>
<p>These are some of the resources that were very helpful to me when I was learning about this algorithm and how to use it. I highly encourage anyone who wants a more technical understanding of the algorithm to check these out.</p>
<ul>
<li><a target="_blank" href="https://www.eso.org/sci/software/esomidas/doc/user/18NOV/volb/node317.html">The <em>à trous</em> algorithm</a> </li>
<li><a target="_blank" href="https://www.pixinsight.com/doc/legacy/LE/20_wavelets/a_trous_wavelet_transform/a_trous_wavelet_transform.html">The <em>À Trous</em> Discrete Wavelet Transform In PixInsight</a></li>
<li><a target="_blank" href="https://jstarck.cosmostat.org/publications/books/book2/">Astronomical Image and Data Analysis</a> by Jean-Luc Starck and Fionn Murtagh</li>
<li><a target="_blank" href="https://jstarck.cosmostat.org/publications/books/book-2015/">Sparse Image and Signal Processing: Wavelets and Related Geometric Multiscale Analysis</a> by J.L. Starck, F. Murtagh, and J. Fadili</li>
</ul>
<p>In addition, I've created a Rust library for working with <em>À Trous</em> transform. It closely matches with what I've showed you here, but has some additional features already, and will have even more. </p>
<p>Things such as handling RGB images and working with all the 3 different kernels is already implemented. It also has better logic for handling boundary conditions, where it uses the image folding technique.</p>
<p>I'm also soon going to be working on performance improvements for the same.</p>
<p>If you want to learn more, or contribute to the library, feel free to do so. The repository can be found here: <a target="_blank" href="https://github.com/anshap1719/image-dwt">https://github.com/anshap1719/image-dwt</a>  </p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>I hope you enjoyed the journey so far. If image processing techniques or their implementation in Rust is something that interests you, then stay tuned for more as these are the topics I love writing about.</p>
<p>Also, feel free to <a target="_blank" href="mailto:nitric-brisk.0s@icloud.com"><strong>contact me</strong></a> if you have any questions or opinions on this topic.</p>
<h3 id="heading-enjoying-my-work">Enjoying my work?</h3>
<p>Consider buying me a coffee to support my work!</p>


<p>Till next time, happy coding and wishing you clear skies!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Hello World in Rust – Example Program ]]>
                </title>
                <description>
                    <![CDATA[ Starting with a new programming language is like taking your first step into a whole new world. One of the very first things you'll do is write a simple program that says "Hello World!". Rust, known for being fast and safe, is no exception. Let's jum... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/hello-world-in-rust/</link>
                <guid isPermaLink="false">66bb8809c32849d18c5cdc9d</guid>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sahil ]]>
                </dc:creator>
                <pubDate>Mon, 08 Apr 2024 09:21:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Neon-Green-Motivational.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Starting with a new programming language is like taking your first step into a whole new world. One of the very first things you'll do is write a simple program that says "Hello World!".</p>
<p>Rust, known for being fast and safe, is no exception. Let's jump right in and create our very first Rust program together!</p>
<h2 id="heading-how-to-write-a-hello-world-program-in-rust">How to Write a Hello World Program in Rust</h2>
<p>First, create a file named <code>main.rs</code>. Every Rust program contains <code>.rs</code> as its file extension.</p>
<p>Then write the following code in the file:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// main.rs</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Hello World!"</span>);
}
</code></pre>
<p>In the code above, we are trying to print <code>Hello World!</code> in the console or terminal.</p>
<h2 id="heading-how-to-compile-rust-code">How to Compile Rust Code</h2>
<p>In Rust, compiling and running the code are two separate processes.</p>
<p>First, you need to compile the Rust program. To compile it, write the following in the terminal (make sure in the terminal is at at the same directory where the Rust file lives):</p>
<pre><code class="lang-bash">rustc main.rs
</code></pre>
<p>For now, you won't see any output because the code was just compiled. But one thing you can see in the current directory is that a new executable file has been added with the same name as the Rust file.</p>
<h2 id="heading-how-to-run-the-executable-file">How to Run the Executable File</h2>
<p>Now you can run the executable file that gets generated after you successfully compiled the Rust code.</p>
<p>To run the executable file, write the following in your terminal:</p>
<pre><code class="lang-bash">./main
</code></pre>
<p>You should see an output like this:</p>
<pre><code class="lang-bash">Hello World!
</code></pre>
<h2 id="heading-understanding-the-hello-world-code-in-depth">Understanding the Hello World Code in Depth</h2>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {

}
</code></pre>
<p>The program starts with a function called <code>main()</code>. Every Rust executable code starts execution from the main function. </p>
<p>The main function can have some parameters inside the <code>()</code> parenthesis, but we have no need for them in the code so we left that empty.</p>
<p>Everything that is between the curly braces <code>{}</code> is the body of the function. It is necessary to have braces for the body otherwise it'll throw an error.</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
  <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Hello World!"</span>);
}
</code></pre>
<p>This line does the work of printing the "Hello World!" text to the terminal or console.</p>
<p>Here, <code>println!</code> is not a function unlike other languages like C, Python, and so on. It is a macro – if there's an <code>!</code> symbol at the end of a keyword, then it's a macro.</p>
<p>Finally, we passed the string as argument to the macro and it prints the string to the terminal.</p>
<p>To end the statement in Rust, you must use <code>;</code>.If you don't provide the semi-colon at the end of every statement, then it'll throw an error.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>And there we have it – your first Rust program! By printing out "Hello World!" you've dipped your toes into the world of Rust. </p>
<p>This simple program has given you a taste of Rust's syntax and how it compiles. As you keep going, you'll discover more about Rust's cool features and find out just how powerful it can be. </p>
<p>Ready to dive deeper? Let's keep exploring!</p>
<p>If you have any feedback, then feel free to DM me on <a target="_blank" href="https://twitter.com/introvertedbot">Twitter</a> and <a target="_blank" href="https://www.linkedin.com/in/sahil-mahapatra/">LinkedIn</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Rust Project – Create an Authentication Server ]]>
                </title>
                <description>
                    <![CDATA[ The Rust programming language is often used for system-level programming, emphasizing safety, concurrency, and performance, making it a popular choice for building systems software, game engines, and web browsers. An authentication server is another ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rust-tutorial-authentication-server/</link>
                <guid isPermaLink="false">66b2065da2135cc2539a21ea</guid>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Fri, 22 Sep 2023 16:02:43 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/rustauthserver.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The Rust programming language is often used for system-level programming, emphasizing safety, concurrency, and performance, making it a popular choice for building systems software, game engines, and web browsers. An authentication server is another good use case for Rust.</p>
<p>We just published a course on the freeCodeCamp.org YouTube channel that will teach you how to use Rust to create an authentication server.</p>
<p>User authentication is the cornerstone of any secure digital platform. Whether you're developing a cutting-edge mobile app, a dynamic web platform, or a robust cloud solution, understanding the nuances of user management and security is paramount. This course is designed to provide developers with the skills and knowledge they need to implement modern authentication solutions.</p>
<p>The course offers a step-by-step guide to understanding and implementing user authentication in Rust, starting with the basic principles and culminating in advanced methodologies.</p>
<p>In this course, Warp, a high-performance web server framework for Rust, serves as the backbone for our web application development. It provides the tools and foundation necessary to build efficient and reliable web services. Alongside Warp, JSON Web Tokens (JWT) play a pivotal role in managing user authentication. JWT allows for secure transmission of information between parties in the form of a compact, self-contained token.</p>
<p>Throughout the course, you will gain hands-on experience in integrating Warp with JWT, ensuring that user data remains both accessible and protected. By combining the power of Warp's web server capabilities with the security and efficiency of JWT, you will be equipped to design and deploy robust, safe, and performant web applications.</p>
<p>Here are the key learning objectives of this course:</p>
<p><strong>Understanding Authentication</strong>:</p>
<ul>
<li>Differentiate between user types: Explore the unique attributes of admin versus regular users.</li>
<li>Discover the importance of roles and their impact on platform access.</li>
</ul>
<p><strong>Deep Dive into User Structures</strong>:</p>
<ul>
<li>Learn about user data structures, attributes, and how they integrate into larger systems.</li>
<li>Explore best practices in data management, ensuring both usability and security.</li>
</ul>
<p><strong>Token Management and Security</strong>:</p>
<ul>
<li>Grasp the intricacies of token-based authentication.</li>
<li>Delve deep into JWT (JSON Web Tokens) and their role in modern authentication.</li>
<li>Understand token expiration, renewal, and the associated security considerations.</li>
</ul>
<p><strong>Error Handling and Debugging</strong>:</p>
<ul>
<li>Equip yourself with techniques to identify, troubleshoot, and resolve common authentication errors.</li>
<li>Learn about error types, their root causes, and effective solutions.</li>
</ul>
<p><strong>Hands-on Practice</strong>:</p>
<ul>
<li>Engage with practical demos and real-world scenarios.</li>
<li>Practice token creation, user validation, and advanced authentication techniques.</li>
</ul>
<p>By the end of this course, you will have a comprehensive understanding of how to implement modern user authentication techniques using Rust.</p>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/6oMoHZZeyb0">the freeCodeCamp.og YouTube channel</a> (2-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/6oMoHZZeyb0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
