<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Rust dramas and success stories]]></title><description><![CDATA[Rust-powered thoughts on audio programming, DSP, and creative coding.]]></description><link>https://blog.paramako.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1750514503556/14c66e42-4a09-49bd-bf74-5122fe093afd.png</url><title>Rust dramas and success stories</title><link>https://blog.paramako.com</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 22:12:35 GMT</lastBuildDate><atom:link href="https://blog.paramako.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Rust Audio Programming: Oscillator – Exploring the waveforms [PART 3]]]></title><description><![CDATA[So what’s an oscillator?
An oscillator is a digital or analog component that generates a repeating waveform — think of it as a signal source. In audio programming, it’s the piece of code that spits out samples of a sine wave (or other waveform) over ...]]></description><link>https://blog.paramako.com/rust-audio-programming-oscillator-exploring-the-waveforms-part-3</link><guid isPermaLink="true">https://blog.paramako.com/rust-audio-programming-oscillator-exploring-the-waveforms-part-3</guid><category><![CDATA[Rust]]></category><category><![CDATA[audio]]></category><category><![CDATA[#audiovisual]]></category><category><![CDATA[audio programming]]></category><category><![CDATA[DSP]]></category><dc:creator><![CDATA[Yurii]]></dc:creator><pubDate>Sat, 10 Jan 2026 16:11:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768059131682/6b7fde45-3aed-4b39-ab61-c5ddafb242db.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-so-whats-an-oscillator">So what’s an oscillator?</h2>
<p>An <strong>oscillator</strong> is a digital or analog component that <strong>generates a repeating waveform</strong> — think of it as a signal source. In audio programming, it’s the piece of code that spits out samples of a <strong>sine wave</strong> (or other <strong>waveform</strong>) over time, at a given <strong>frequency</strong>.</p>
<p>For example:</p>
<ul>
<li><p>A <strong>440 Hz oscillator</strong> emits values that, when played back at 44.1 kHz, recreate the pitch of the musical note A4.</p>
</li>
<li><p>You can think of it as a mathematical function that cycles through waveform values at a certain speed.</p>
</li>
</ul>
<p><img src="https://i.ytimg.com/vi/G5_zul5wrTY/hq720.jpg?sqp=-oaymwE7CK4FEIIDSFryq4qpAy0IARUAAAAAGAElAADIQj0AgKJD8AEB-AH-CYAC0AWKAgwIABABGHIgTShCMA8=&amp;rs=AOn4CLDv0QkEmS876YFmy3_WoGyjlKo-sw" alt="Amplitude, Frequency, and Phase" /></p>
<p>By adjusting the oscillator's <strong>frequency</strong>, <strong>amplitude</strong>, and <strong>waveform shape</strong>, we can synthesize anything from a beep to a bass line.</p>
<p>So far in this series, we’ve been implementing <strong>oscillator</strong> logic manually inside our sample loop — like we did in <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2">Part 2</a>. But now, we’re going to wrap that logic into a <strong>proper, reusable oscillator</strong> — one that behaves more like what you’d find in real audio engines and synthesizers.</p>
<h2 id="heading-defining-our-naive-oscillator"><strong>Defining our naive oscillator</strong></h2>
<p>To begin shaping different waveforms, we’re going to write our first reusable <strong>oscillator</strong>. This will let us plug in different waveform logic — like square, triangle, and sawtooth — all using the same reusable structure.</p>
<p>If you’re already familiar with how Rust <strong>structs</strong> and <strong>enums</strong> work — great!</p>
<p>If not, don’t worry — you can still follow along or check out those links for a quick refresher.</p>
<ul>
<li><p><a target="_blank" href="https://doc.rust-lang.org/rust-by-example/custom_types/structs.html">https://doc.rust-lang.org/rust-by-example/custom_types/structs.html</a></p>
</li>
<li><p><a target="_blank" href="https://doc.rust-lang.org/rust-by-example/custom_types/enum.html">https://doc.rust-lang.org/rust-by-example/custom_types/enum.html</a></p>
</li>
</ul>
<p>To keep things familiar, we’ll start with just the <strong>sine wave</strong> — the same waveform we’ve been using throughout <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-build-a-sine-wave-part-1">Part 1￼</a> and <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2">Part 2</a>￼. It’s smooth, simple, and perfect for verifying that our <strong>oscillator</strong> behaves correctly.</p>
<p>Here’s our minimal <code>Oscillator</code> struct that generates a <strong>sine wave</strong>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::<span class="hljs-built_in">f32</span>::consts::TAU;

<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Oscillator</span></span> {
    phase: <span class="hljs-built_in">f32</span>,
    phase_increment: <span class="hljs-built_in">f32</span>,
    sample_rate: <span class="hljs-built_in">f32</span>,
}

<span class="hljs-keyword">impl</span> Oscillator {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(sample_rate: <span class="hljs-built_in">f32</span>, frequency: <span class="hljs-built_in">f32</span>) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">let</span> phase_increment = frequency / sample_rate;
        <span class="hljs-keyword">Self</span> {
            phase: <span class="hljs-number">0.0</span>,
            phase_increment,
            sample_rate
        }
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">set_frequency</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, frequency: <span class="hljs-built_in">f32</span>) {
        <span class="hljs-keyword">self</span>.phase_increment = frequency / <span class="hljs-keyword">self</span>.sample_rate;
    }

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">next_sample</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">f32</span> {
        <span class="hljs-keyword">self</span>.phase += <span class="hljs-keyword">self</span>.phase_increment;
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.phase &gt;= <span class="hljs-number">1.0</span> {
            <span class="hljs-keyword">self</span>.phase -= <span class="hljs-number">1.0</span>;
        }

        (<span class="hljs-keyword">self</span>.phase * TAU).sin()
    }
}
</code></pre>
<p>Let’s compare this new <code>Oscillator</code> implementation to what we did manually back in <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2">Part 2</a>.</p>
<p>Here’s a quick reminder of the relevant lines from our previous code:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> phase_increment = <span class="hljs-number">2.0</span> * PI * freq_hz / sample_rate;
phase = (phase + phase_increment) % (<span class="hljs-number">2.0</span> * PI);
<span class="hljs-keyword">let</span> sample = (amplitude * phase.sin()) <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>;
</code></pre>
<p>And here’s what we do now inside our <code>Oscillator::next_sample</code> method:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">self</span>.phase += <span class="hljs-keyword">self</span>.phase_increment;

<span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.phase &gt;= <span class="hljs-number">1.0</span> {
    <span class="hljs-keyword">self</span>.phase -= <span class="hljs-number">1.0</span>;
}

(<span class="hljs-keyword">self</span>.phase * TAU).sin()
</code></pre>
<h3 id="heading-lets-break-it-down"><strong>Let’s break it down:</strong></h3>
<h4 id="heading-amplitude-is-now-external"><strong>Amplitude is now external</strong></h4>
<p>We removed <strong>amplitude scaling</strong> from the <strong>oscillator</strong> itself. Why?</p>
<p>Because in most audio systems, amplitude is handled <strong>outside</strong> the oscillator — through gain controls, envelopes, or mixing. That’s more modular, and it gives you full control when combining signals later.</p>
<p>Now, instead of embedding it in the waveform, we do:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> sample = oscillator.next_sample() * amplitude;
</code></pre>
<h4 id="heading-we-changed-how-we-handle-the-phase"><strong>We changed how we handle the phase</strong></h4>
<p>In <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2">Part 2</a>, we tracked phase in <strong>radians</strong>, and wrapped it using: <code>phase = (phase + increment) % (2π)</code>.</p>
<p>Now we’re using a <strong>normalized phase</strong> in the range 0.0..1.0, and converting to <strong>radians</strong> only when we need the <strong>sine</strong> value. It’s simpler and matches DSP conventions more closely.</p>
<p>This also lets us write a cheaper phase wrap:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.phase &gt;= <span class="hljs-number">1.0</span> {
    <span class="hljs-keyword">self</span>.phase -= <span class="hljs-number">1.0</span>;
}
</code></pre>
<p>This avoids calling <code>.fract()</code> or <code>%</code> every sample, which helps when optimizing for performance (especially at higher sample rates).</p>
<h4 id="heading-why-tau-instead-of-2p"><strong>Why TAU instead of 2π?</strong></h4>
<p>Mathematically, <strong>TAU</strong> is just <strong>2π</strong> — one full circle in <strong>radians</strong>.</p>
<p>So instead of:</p>
<pre><code class="lang-rust">(phase * <span class="hljs-number">2.0</span> * PI).sin()
</code></pre>
<p>We now do:</p>
<pre><code class="lang-rust">(phase * TAU).sin()
</code></pre>
<p><strong>Same result</strong>, <strong>cleaner expression</strong> — and easier to think of 1.0 as one full waveform cycle.</p>
<h2 id="heading-updating-our-melody-generator-to-use-the-oscillator"><strong>Updating our melody generator to use the oscillator</strong></h2>
<p>Now that we’ve wrapped our sine wave logic into a reusable Oscillator, let’s use it to recreate the melody we built in <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2">Part 2</a>, but this time, with much cleaner code.</p>
<blockquote>
<p>For simplicity, we’re keeping the <code>Oscillator</code> struct definition in the same file as the melody code. This tutorial isn’t about Rust project structure or module hygiene — we’re here to explore audio concepts.</p>
<p>If you’re curious how this could be packaged more cleanly, you can also check out <a target="_blank" href="https://github.com/paramako/oscy">oscy</a> — a small crate I’m building that includes different oscillators and support for multiple waveforms.</p>
</blockquote>
<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-keyword">let</span> spec = hound::WavSpec {
        channels: <span class="hljs-number">1</span>,
        sample_rate: <span class="hljs-number">44100</span>,
        bits_per_sample: <span class="hljs-number">16</span>,
        sample_format: hound::SampleFormat::Int,
    };

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> writer = hound::WavWriter::create(<span class="hljs-string">"melody_struct.wav"</span>, spec)
        .expect(<span class="hljs-string">"Failed to create WAV file"</span>);

    <span class="hljs-keyword">let</span> sample_rate = spec.sample_rate <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;
    <span class="hljs-keyword">let</span> duration_secs = <span class="hljs-number">8.0</span>;
    <span class="hljs-keyword">let</span> amplitude = <span class="hljs-built_in">i16</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;
    <span class="hljs-keyword">let</span> total_samples = (sample_rate * duration_secs) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> osc = Oscillator::new(sample_rate, <span class="hljs-number">440.0</span>);

    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..total_samples {
        <span class="hljs-keyword">let</span> time = t <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / sample_rate;

        <span class="hljs-keyword">let</span> freq_hz = <span class="hljs-keyword">match</span> time.ceil() {
            <span class="hljs-number">1.0</span> =&gt; <span class="hljs-number">440.0</span>,  <span class="hljs-comment">// A4</span>
            <span class="hljs-number">2.0</span> =&gt; <span class="hljs-number">494.0</span>,  <span class="hljs-comment">// B4</span>
            <span class="hljs-number">3.0</span> =&gt; <span class="hljs-number">523.25</span>, <span class="hljs-comment">// C5</span>
            <span class="hljs-number">4.0</span> =&gt; <span class="hljs-number">587.33</span>, <span class="hljs-comment">// D5</span>
            <span class="hljs-number">5.0</span> =&gt; <span class="hljs-number">659.25</span>, <span class="hljs-comment">// E5</span>
            <span class="hljs-number">6.0</span> =&gt; <span class="hljs-number">698.46</span>, <span class="hljs-comment">// F5</span>
            <span class="hljs-number">7.0</span> =&gt; <span class="hljs-number">783.99</span>, <span class="hljs-comment">// G5</span>
            _ =&gt; <span class="hljs-number">880.0</span>,    <span class="hljs-comment">// A5</span>
        };

        osc.set_frequency(freq_hz);

        <span class="hljs-keyword">let</span> sample = (osc.next_sample() * amplitude) <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>;
        writer.write_sample(sample).unwrap();
    }

    writer.finalize().unwrap();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"✅ Melody written to 'melody_struct.wav'"</span>);
}
</code></pre>
<h3 id="heading-lets-listen-and-look"><strong>Let’s listen and look</strong></h3>
<p>Build and run your code again:</p>
<pre><code class="lang-bash">cargo run
</code></pre>
<p>This will generate a new <strong>WAV file</strong>: <code>melody_struct.wav</code>.</p>
<p>If you open both <code>melody_fixed.wav</code> (<strong>from Part 2</strong>) and <code>melody_struct.wav</code> (<strong>this version</strong>) in <strong>Audacity</strong> and zoom in around the <strong>5 to 6 second mark</strong>, just like we did before, you’ll notice there’s <strong>no visible difference</strong> between them — no harsh corners, no sudden jumps, and most importantly: <strong>no audible clicks</strong>.</p>
<p>That means our new <strong>oscillator-based approach</strong> is working exactly as intended.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767973511976/387ae4fd-3b28-4e68-9579-f319c49cd622.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-exploring-waveforms"><strong>Exploring waveforms</strong></h2>
<p>So we built a clean-sounding melody and solved a common audio issue: <strong>phase discontinuity</strong> (aka <em>clicks</em>). We even wrapped our <strong>sine wave</strong> logic into a reusable <code>Oscillator</code>.</p>
<p><strong>Now, it’s time to level up.</strong></p>
<p>We’re going to make our <strong>oscillator</strong> more flexible — not just locked to <strong>sine waves</strong>, but capable of generating other classic shapes too: <strong>square</strong>, <strong>sawtooth</strong>, and <strong>triangle</strong>.</p>
<p>Each of these <strong>waveforms</strong> sounds different and has its own <strong>harmonic profile</strong> — which gives them their character:</p>
<ul>
<li><p><strong>Sine waves</strong> are smooth and pure.</p>
</li>
<li><p><strong>Sawtooth waves</strong> are bright and buzzy.</p>
</li>
<li><p><strong>Square waves</strong> have a hollow, woody tone.</p>
</li>
<li><p><strong>Triangle waves</strong> are soft but richer than sine.</p>
</li>
</ul>
<p>The difference isn’t just in how they <strong>look</strong> — it’s in how they <strong>vibrate</strong>.</p>
<p>When you hear a musical note, you’re not just hearing one frequency. You’re actually hearing a <strong>blend of frequencies</strong>: the main one (called the <strong>fundamental</strong>) and a bunch of quieter ones stacked on top — called <strong>harmonics</strong> or <strong>overtones</strong>.</p>
<p>These harmonics are <strong>integer multiples</strong> of the <strong>fundamental frequency</strong>:</p>
<ul>
<li><p>If the <strong>fundamental</strong> is <strong>100 Hz</strong>, you might also hear <strong>200 Hz</strong>, <strong>300 Hz</strong>, <strong>400 Hz</strong>…</p>
</li>
<li><p>Each one adds flavor and texture to the sound.</p>
</li>
</ul>
<p>What makes each waveform unique is <strong>which harmonics are present</strong>, and <strong>how strong</strong> they are.</p>
<ul>
<li><p><strong>Sine wave</strong> → no harmonics at all — just the fundamental. Pure and tone-like.</p>
</li>
<li><p><strong>Square wave</strong> → odd harmonics only (3x, 5x, 7x…), creating a hollow, flute-like sound.</p>
</li>
<li><p><strong>Sawtooth wave</strong> → all harmonics (1x, 2x, 3x, 4x…), giving it a bright, brassy edge.</p>
</li>
<li><p><strong>Triangle wave</strong> → odd harmonics too, like square, but much softer — their intensity drops off faster.</p>
</li>
</ul>
<p>These harmonic “recipes” are what give each waveform its distinct voice. They don’t just change what we hear — they shape <strong><em>how</em></strong> we feel the sound.</p>
<h3 id="heading-square-wave"><strong>Square wave</strong></h3>
<p>Let’s kick things off with the <strong>square wave</strong> — one of the most recognizable shapes in digital sound synthesis.</p>
<p>It alternates between two levels: high and low, with no gradual transition between them. That sudden flip gives it a bold, buzzy sound full of <strong>odd harmonics</strong>.</p>
<p>In code, it’s one of the simplest <strong>waveforms</strong> to implement:</p>
<ul>
<li><p>If the <strong>phase</strong> is in the first half of the cycle (<code>0.0</code> to <code>0.5</code>), output <code>+1.0</code></p>
</li>
<li><p>Otherwise, output <code>-1.0</code></p>
</li>
</ul>
<p>Let’s update our <strong>oscillator</strong> so it can generate both <strong>sine</strong> and <strong>square</strong> waves based on a selected <strong>waveform</strong> <strong>type</strong>.</p>
<p>To support multiple <strong>waveform shapes</strong>, we’ll define a new enum called <code>Waveform</code>. For now, we’ll keep it simple with just two options:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Waveform</span></span> {
    Sine,
    Square,
}
</code></pre>
<p>We’ll now store the selected <strong>waveform</strong> in our <strong>oscillator</strong>. That way, <code>next_sample()</code> knows what shape to generate.</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">Oscillator</span></span> {
    phase: <span class="hljs-built_in">f32</span>,
    phase_increment: <span class="hljs-built_in">f32</span>,
    sample_rate: <span class="hljs-built_in">f32</span>,
    waveform: Waveform,
}
</code></pre>
<p>And we’ll update the constructor to accept the <strong>waveform</strong> as a parameter:</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">new</span></span>(sample_rate: <span class="hljs-built_in">f32</span>, frequency: <span class="hljs-built_in">f32</span>, waveform: Waveform) -&gt; <span class="hljs-keyword">Self</span> {
    <span class="hljs-keyword">let</span> phase_increment = frequency / sample_rate;
    <span class="hljs-keyword">Self</span> {
        phase: <span class="hljs-number">0.0</span>,
        phase_increment,
        sample_rate,
        waveform,
    }
}
</code></pre>
<p>To use the <strong>square wave</strong> in your melody code, simply update the <strong>oscillator</strong> construction like this:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> osc = Oscillator::new(sample_rate, <span class="hljs-number">440.0</span>, Waveform::Square);
</code></pre>
<p>Here’s what happens inside <code>next_sample()</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">next_sample</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">f32</span> {
    <span class="hljs-keyword">self</span>.phase += <span class="hljs-keyword">self</span>.phase_increment;
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.phase &gt;= <span class="hljs-number">1.0</span> {
        <span class="hljs-keyword">self</span>.phase -= <span class="hljs-number">1.0</span>;
    }

    <span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span>.waveform {
        Waveform::Sine =&gt; (<span class="hljs-keyword">self</span>.phase * TAU).sin(),
        Waveform::Square =&gt; {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.phase &lt; <span class="hljs-number">0.5</span> {
                <span class="hljs-number">1.0</span>
            } <span class="hljs-keyword">else</span> {
                -<span class="hljs-number">1.0</span>
            }
        }
    }
}
</code></pre>
<p>Time to test it out! Run your project to generate the new <strong>waveform</strong>.</p>
<p>Now open that file in <strong>Audacity</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767975413105/87afa0e8-3d67-4547-bf70-afd78312469d.png" alt class="image--center mx-auto" /></p>
<p>No curves, no slopes — just straight lines up and down. That’s your <strong>square wave</strong> in action.</p>
<p>It’ll also sound more <strong>intense</strong> and <strong>buzzy</strong> than the smooth <strong>sine wave</strong> from before — thanks to all those <strong>odd harmonics</strong> baked into the waveform.</p>
<h3 id="heading-saw-wave"><strong>Saw wave</strong></h3>
<p>Next up is the <strong>saw</strong> (or <strong>sawtooth</strong>) <strong>wave</strong> — a bright, sharp waveform known for its <strong>aggressive</strong> tone and rich harmonic content.</p>
<p>It gets its name from how it looks: a straight ramp up followed by a sharp drop — just like <strong>the teeth of a saw blade</strong>.</p>
<p>The formula to generate a <strong>saw wave</strong> is: <code>output = 2 × phase − 1</code>.</p>
<p><strong>Here’s what that means:</strong></p>
<ul>
<li><p>The <strong>phase</strong> always moves from <code>0.0</code> to <code>1.0</code> in a loop — that’s one full <strong>waveform</strong> <strong>cycle</strong>.</p>
</li>
<li><p>At the <strong>start</strong> of the cycle (<code>phase = 0.0</code>), we get:</p>
<p>  <code>2 × 0.0 − 1 = -1.0</code></p>
</li>
<li><p>In the <strong>middle</strong> (<code>phase = 0.5</code>):</p>
<p>  <code>2 × 0.5 − 1 = 0.0</code></p>
</li>
<li><p>At the <strong>end</strong> (<code>phase = 1.0</code>):</p>
<p>  <code>2 × 1.0 − 1 = +1.0</code></p>
</li>
</ul>
<p>Then the <strong>phase</strong> wraps back to <code>0</code>, and the pattern repeats.</p>
<p>This formula gives us a <strong>linear slope</strong> from <code>-1.0</code> to <code>+1.0</code> over the <strong>full waveform cycle</strong>. That’s what makes the <strong>sawtooth</strong> look like a ramp — and sound <strong>bright</strong> and <strong>buzzy</strong> due to all its harmonic content.</p>
<p>So lets update the <code>Waveform</code> enum:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Waveform</span></span> {
    Sine,
    Square,
    Saw,
}
</code></pre>
<p>Change the <strong>oscillator</strong> construction to:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> osc = Oscillator::new(sample_rate, <span class="hljs-number">440.0</span>, Waveform::Saw);
</code></pre>
<p>Update the <code>next_sample()</code> logic:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span>.waveform {
    <span class="hljs-comment">// ...other variants</span>
    Waveform::Saw =&gt; <span class="hljs-number">2.0</span> * <span class="hljs-keyword">self</span>.phase - <span class="hljs-number">1.0</span>,
}
</code></pre>
<p>Once we’ve updated the code and generated the <code>.wav</code> file, lets open it the editor:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767976189445/b73ebf8b-46ea-4fd2-ad47-bb232293e8b0.png" alt class="image--center mx-auto" /></p>
<p>By looking at it visually, you’ll immediately spot the <strong>sawtooth shape</strong>:</p>
<ul>
<li><p>A <strong>straight, linear ramp upward</strong> from <code>-1.0</code> to <code>+1.0</code></p>
</li>
<li><p>Followed by a <strong>sudden vertical drop</strong> back to <code>-1.0</code></p>
</li>
<li><p>And then the cycle repeats</p>
</li>
</ul>
<p>And of course, it sounds a lot <strong>brighter</strong> and <strong>harsher</strong> than <strong>sine</strong> or <strong>square</strong> — all thanks to its full spectrum of <strong>harmonics</strong>.</p>
<h3 id="heading-why-does-the-sine-wave-sound-quieter"><strong>Why does the sine wave sound quieter?</strong></h3>
<p>You might have noticed: <strong>the sine wave sounds noticeably quieter</strong> than the <strong>square</strong> and <strong>saw</strong> waves — even though they all use the same amplitude range (<code>-1.0</code> to <code>+1.0</code>).</p>
<p>That’s not a bug — it’s how <strong>sound perception</strong> works.</p>
<p>Here’s why:</p>
<ul>
<li><p><strong>A square wave</strong> holds full volume for half the cycle at <code>+1.0</code> and the other half at <code>-1.0</code>. That means its average power is very high.</p>
</li>
<li><p><strong>A saw wave</strong> is constantly moving, but it still spends a lot of time near high (and low) values as it ramps from <code>-1.0</code> to <code>+1.0</code>. It also contains lots of <strong>harmonics</strong>, which adds even more perceived loudness.</p>
</li>
<li><p><strong>A sine wave</strong>, on the other hand, gently eases up and down in a smooth curve — spending much less time near its peak values and containing only the <strong>fundamental frequency</strong>. So even though the <strong>peak values</strong> are the same, the <strong>harmonic content</strong> makes the <strong>square</strong> and <strong>saw</strong> waves feel <strong>louder</strong> and <strong>fuller</strong>.</p>
</li>
</ul>
<p>In real-world synths and audio engines, this is usually handled by <strong>scaling different waveforms</strong> so they have <strong>similar perceived loudness</strong> — not just matching the numbers.</p>
<p>You can experiment by <strong>adjusting the amplitude multiplier</strong> when writing samples, to make each waveform feel more balanced in loudness. Don’t stress about finding a perfect value — just adjust it until it feels right.</p>
<p>But keep in mind, a <strong>16-bit WAV</strong> file cannot natively contain <strong>amplitude</strong> values greater than the <strong>16-bit range</strong>.</p>
<p>If your signal goes beyond <code>-1.0..1.0</code> before converting to <code>i16</code>, it will be <strong>clamped</strong> to the max value (<code>32767</code> or -<code>32768</code>) — and this <strong>flattens the waveform’s peaks,</strong> making our <strong>sine wave</strong> look and sound more like a <strong>square wave</strong>.</p>
<p>It ends up looking like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768051692241/e4059600-748a-47d6-b36a-7453f05193aa.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-triangle-wave"><strong>Triangle wave</strong></h3>
<p>The <strong>triangle wave</strong> is a gentler cousin of the <strong>square wave</strong>.</p>
<p>Like the <strong>square wave</strong>, it only contains <strong>odd harmonics</strong>, but it rolls them off much faster — making it sound <strong>smoother</strong>, <strong>rounder</strong>, and less harsh.</p>
<p>Visually, it’s a perfect zig-zag:</p>
<ul>
<li><p>It rises steadily from <code>-1.0</code> to <code>+1.0</code></p>
</li>
<li><p>Then falls back down just as steadily</p>
</li>
</ul>
<p>To generate a <strong>triangle wave</strong> digitally, we once again rely on the <strong>phase</strong> value — which linearly moves from <code>0.0</code> to <code>1.0</code> every cycle.</p>
<p>The trick is to split the <strong>waveform</strong> into two halves:</p>
<ul>
<li><p><strong>First half (0.0..0.5)</strong>: the wave ramps up</p>
</li>
<li><p><strong>Second half (0.5..1.0)</strong>: the wave ramps down</p>
</li>
</ul>
<p>Here’s the piecewise <strong>formula</strong>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> phase &lt; <span class="hljs-number">0.5</span> {
    <span class="hljs-number">4.0</span> * phase - <span class="hljs-number">1.0</span>
} <span class="hljs-keyword">else</span> {
    -<span class="hljs-number">4.0</span> * phase + <span class="hljs-number">3.0</span>
}
</code></pre>
<p>In the <strong>first half</strong>, we want a linear rise from -1.0 → +1.0:</p>
<ul>
<li><p>When <strong>phase</strong> = <code>0.0</code>: <code>4.0 * 0.0 - 1.0 = -1.0</code></p>
</li>
<li><p>When <strong>phase</strong> = <code>0.5</code>: <code>4.0 * 0.5 - 1.0 = +1.0</code></p>
</li>
</ul>
<p>In the <strong>second half</strong>, we want to fall from +1.0 → -1.0:</p>
<ul>
<li><p>When <strong>phase</strong> = <code>0.5</code>: <code>-4.0 * 0.5 + 3.0 = +1.0</code></p>
</li>
<li><p>When <strong>phase</strong> = <code>1.0</code>: <code>-4.0 * 1.0 + 3.0 = -1.0</code></p>
</li>
</ul>
<p>The slope of <code>+/-4.0</code> gives us just the right speed to move between those values in <strong>half a cycle</strong>.</p>
<p>So lets extend the <code>Waveform</code> enum again:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Waveform</span></span> {
    Sine,
    Square,
    Saw,
    Triangle,
}
</code></pre>
<p>Then update the <code>next_sample()</code> method of your <code>Oscillator</code> struct to support it:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span>.waveform {
    <span class="hljs-comment">// ...other variants</span>
    Waveform::Triangle =&gt; {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.phase &lt; <span class="hljs-number">0.5</span> {
            <span class="hljs-number">4.0</span> * <span class="hljs-keyword">self</span>.phase - <span class="hljs-number">1.0</span>
        } <span class="hljs-keyword">else</span> {
            -<span class="hljs-number">4.0</span> * <span class="hljs-keyword">self</span>.phase + <span class="hljs-number">3.0</span>
        }
    }
}
</code></pre>
<p>And change the <strong>Oscillator</strong> construction to:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> osc = Oscillator::new(sample_rate, <span class="hljs-number">440.0</span>, Waveform::Triangle);
</code></pre>
<p>Run your project to generate the .wav file:</p>
<pre><code class="lang-bash">cargo run
</code></pre>
<p>Once the file is generated, open it in <strong>Audacity</strong> and you’ll see:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768048556510/2017933b-ce72-4f36-99e7-bc4e259cb2f6.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>A <strong>clean up–down ramp</strong></p>
</li>
<li><p>Peaks at <code>+1.0</code> and <code>-1.0</code></p>
</li>
<li><p><strong>Sharp corners</strong>, but not the harsh harmonics of <strong>saw</strong>/<strong>square</strong></p>
</li>
</ul>
<p>The result is a <strong>soft, muted tone</strong>.</p>
<h2 id="heading-wrapping-up-part-3"><strong>🎬 Wrapping up [PART 3]</strong></h2>
<p>In this post, we built a <strong>reusable oscillator</strong> in Rust, explored <strong>multiple waveform shapes</strong>, and visualized how their structure affects tone and loudness. Along the way, we touched on <strong>harmonics</strong>, <strong>amplitude scaling</strong>, and how even simple math shapes sound.</p>
<p>But as you’ve probably guessed, our <strong>oscillator</strong> is still kind of naive, and there’s much more to explore beneath the surface.</p>
<p>Our waveforms are generated using <strong>simple math</strong>, which means <strong>sharp corners</strong> in <strong>square</strong> and <strong>saw</strong> waves. That leads to a common problem in digital synthesis: <strong>aliasing</strong>.</p>
<p><strong>Aliasing</strong> happens when high-frequency content folds back into the audible range, creating unwanted artifacts — especially at <strong>higher</strong> <strong>pitches</strong>. It can make sounds <strong>harsher</strong>, <strong>noisier</strong>, and <strong>less realistic</strong>.</p>
<p>If you’re ready to go deeper, check out my crate <a target="_blank" href="https://github.com/paramako/oscy">oscy</a>. It includes alternate <strong>oscillator</strong> implementations (like <strong>PolyBLEP</strong>) that reduce aliasing while staying CPU-friendly.</p>
<h2 id="heading-whats-next"><strong>🚧 What’s next?</strong></h2>
<p>That wraps up our <strong>Oscillator Series</strong>!</p>
<p>Next up? A new series where we:</p>
<ul>
<li><p>Combine <strong>oscillators</strong></p>
</li>
<li><p>Add <strong>envelopes</strong> and <strong>modulation</strong></p>
</li>
<li><p>And build toward real-time <strong>Rust-powered synths</strong></p>
</li>
</ul>
<p>Stay tuned!</p>
<p>💾 <strong>Source code from this article:</strong></p>
<p><a target="_blank" href="https://github.com/paramako-blog/oscillator/blob/main/examples/part3_different_waveforms.rs"><strong>View on GitHub →</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[Rust Audio Programming: Oscillator – Handle frequency changes smoothly [PART 2]]]></title><description><![CDATA[In Part 1, we built a simple sine wave generator and saved it as a .wav file.
Now it’s time to make it sing — or at least play a short melody.
We’ll modify our existing code to switch between different notes over time, building up something that feel...]]></description><link>https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2</link><guid isPermaLink="true">https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2</guid><category><![CDATA[audio programming]]></category><category><![CDATA[Digital Signal Processing]]></category><category><![CDATA[Audio Processing]]></category><category><![CDATA[Rust]]></category><category><![CDATA[DSP]]></category><category><![CDATA[audio]]></category><dc:creator><![CDATA[Yurii]]></dc:creator><pubDate>Wed, 07 Jan 2026 18:14:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767809100433/1c4c9926-7385-48b2-b5ff-5045a8e8d0eb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-build-a-sine-wave-part-1">Part 1</a>, we built a simple sine wave generator and saved it as a .wav file.</p>
<p>Now it’s time to <strong>make it sing</strong> — or at least play a short melody.</p>
<p>We’ll modify our existing code to <strong>switch between different notes over time</strong>, building up something that feels more musical. But we’re also going to hit a snag — and that snag is going to teach us an important concept in audio programming.</p>
<p>Let’s dive in.</p>
<p>We’ll play an <strong>8-second melody</strong>, changing the note <strong>once per second</strong>. We’ll reuse the core logic from <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-build-a-sine-wave-part-1">Part 1</a>, but adapt it to loop over an array of frequencies — one for each second.</p>
<p>This is a <strong>naive implementation:</strong></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::<span class="hljs-built_in">f32</span>::consts::PI;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// WAV file settings</span>
    <span class="hljs-keyword">let</span> spec = hound::WavSpec {
        channels: <span class="hljs-number">1</span>,        <span class="hljs-comment">// mono</span>
        sample_rate: <span class="hljs-number">44100</span>, <span class="hljs-comment">// samples per second</span>
        bits_per_sample: <span class="hljs-number">16</span>,
        sample_format: hound::SampleFormat::Int,
    };
    <span class="hljs-comment">// Create a WAV writer</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> writer =
        hound::WavWriter::create(<span class="hljs-string">"melody.wav"</span>, spec).expect(<span class="hljs-string">"Failed to create WAV file"</span>);
    <span class="hljs-comment">// Sine wave parameters</span>
    <span class="hljs-keyword">let</span> duration_secs = <span class="hljs-number">8.0</span>; <span class="hljs-comment">// 2 seconds</span>
    <span class="hljs-keyword">let</span> amplitude = <span class="hljs-built_in">i16</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>; <span class="hljs-comment">// max volume</span>

    <span class="hljs-keyword">let</span> sample_rate = spec.sample_rate <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;
    <span class="hljs-keyword">let</span> total_samples = (sample_rate * duration_secs) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;

    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..total_samples {
        <span class="hljs-keyword">let</span> time = t <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / sample_rate;

        <span class="hljs-keyword">let</span> freq_hz = <span class="hljs-keyword">match</span> time.ceil() {
            <span class="hljs-number">1.0</span> =&gt; <span class="hljs-number">440.0</span>,  <span class="hljs-comment">// A4</span>
            <span class="hljs-number">2.0</span> =&gt; <span class="hljs-number">494.0</span>,  <span class="hljs-comment">// B4</span>
            <span class="hljs-number">3.0</span> =&gt; <span class="hljs-number">523.25</span>, <span class="hljs-comment">// C5</span>
            <span class="hljs-number">4.0</span> =&gt; <span class="hljs-number">587.33</span>, <span class="hljs-comment">// D5</span>
            <span class="hljs-number">5.0</span> =&gt; <span class="hljs-number">659.25</span>, <span class="hljs-comment">// E5</span>
            <span class="hljs-number">6.0</span> =&gt; <span class="hljs-number">698.46</span>, <span class="hljs-comment">// F5</span>
            <span class="hljs-number">7.0</span> =&gt; <span class="hljs-number">783.99</span>, <span class="hljs-comment">// G5</span>
            _ =&gt; <span class="hljs-number">880.0</span>,    <span class="hljs-comment">// A5</span>
        };

        <span class="hljs-keyword">let</span> sample = (amplitude * (<span class="hljs-number">2.0</span> * PI * freq_hz * time).sin()) <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>;
        writer.write_sample(sample).unwrap();
    }

    writer.finalize().unwrap();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"✅ Melody written to 'melody.wav'"</span>);
}
</code></pre>
<p>Let’s break down what we’ve changed in this version of the code:</p>
<p>In <a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-build-a-sine-wave-part-1">Part 1</a>, we generated a <strong>single 2-second tone</strong>.</p>
<p>Now we’ve extended the total duration to <strong>8 seconds</strong> so we can play <strong>eight notes</strong>, one per second:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> duration_secs = <span class="hljs-number">8.0</span>;
</code></pre>
<p>We keep a single loop running over all the samples:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..total_samples {
    <span class="hljs-keyword">let</span> time = t <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / sample_rate;
    <span class="hljs-keyword">let</span> freq_hz = <span class="hljs-keyword">match</span> time.ceil() { ... };
}
</code></pre>
<p>Instead of generating one note from start to finish, we now <strong>check the current time</strong> and <strong>change the frequency every second</strong>.</p>
<p>This lets us build a full melody from just one continuous time stream.</p>
<p>The rest stays the same — we’re still generating samples, writing them to a .wav file.</p>
<h2 id="heading-lets-play-our-melody"><strong>Let’s play our melody</strong></h2>
<p>Run the program with:</p>
<pre><code class="lang-bash">cargo run
</code></pre>
<p>You’ll see the file <code>melody.wav</code> pop up in your project folder. Go ahead and open it in your favorite audio player — or better yet, drop it into <a target="_blank" href="https://www.audacityteam.org/"><strong>Audacity</strong></a> to <strong>listen and inspect</strong> the waveform.</p>
<p>At first, it’ll sound like a simple melody — but listen closely 👂 and you might hear something <em>unexpected</em> between the notes…</p>
<p>Those little <strong>clicks or pops</strong> you’re hearing between notes aren’t a bug in your system — they’re a classic issue in audio programming caused by <strong>discontinuities in the waveform</strong>.</p>
<p>Remember, we’re using this formula: <code>sample = amplitude * sin(2π × frequency × time)</code></p>
<p>What that means is:</p>
<ul>
<li><p>At the end of each second, the sine wave is at a certain phase (e.g., somewhere mid-curve).</p>
</li>
<li><p>Then, without warning, we jump to a <strong>new sine wave</strong> — starting at a totally different frequency, <em>but continuing the same time</em>.</p>
</li>
</ul>
<p>The result? The waveform suddenly <strong>jumps</strong> from one value to another — and your ear <strong>hears that jump</strong> as a <strong>click</strong>.</p>
<p>To be smooth and click-free, a waveform should <strong>connect seamlessly</strong> — one sample to the next, with no sudden jumps in value.</p>
<p>But when we change the frequency without resetting or adjusting the phase, we break that continuity.</p>
<p>So instead of a curve that flows naturally, we get a <strong>sharp corner</strong> in the waveform — and your ear <em>hates</em> sharp corners.</p>
<h2 id="heading-see-it-for-yourself-in-audacity"><strong>See it for yourself (in Audacity)</strong></h2>
<p>By default, Audacity might show <strong>beats and measures</strong>, which isn’t helpful for our waveform timing.</p>
<p>To change that:</p>
<ol>
<li><p>Look at the <strong>timeline above the waveform</strong>.</p>
</li>
<li><p>Click the little drop-down arrow on the left side of the timeline.</p>
</li>
<li><p>Select <strong>“Minutes and Seconds”</strong> from the list (instead of “Beats and Measures”).</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752082936538/6b839395-311c-4fd2-b3ee-886217e4000b.png" alt class="image--center mx-auto" /></p>
<p>To see the discontinuity clearly:</p>
<ol>
<li><p>Zoom in until you’re seeing <strong>just a few milliseconds</strong> of waveform per screen.</p>
</li>
<li><p>Navigate to the <strong>5 to 6 second</strong> mark (between note 6 and 7).</p>
</li>
<li><p>Look closely at the <strong>transition point</strong> — right around the 6.0s boundary.</p>
</li>
</ol>
<p>🎯 You should see a clean, repeating wave suddenly <strong>jump</strong> to a new shape — no smooth transition.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752082765474/aef65dae-6bad-4dc3-8ae3-296e0ab35011.png" alt class="image--center mx-auto" /></p>
<p>Or even closer</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752082817894/cbec67a2-e6e6-407c-b163-30c7042e1975.png" alt class="image--center mx-auto" /></p>
<p>This is the exact spot where our <strong>phase mismatch</strong> causes a <strong>discontinuity</strong> in the waveform — and that’s what we’ll fix in the next step. You can choose any transition point between notes to inspect — I picked the gap around second 6 just as an example. The same issue will appear wherever the frequency changes abruptly mid-wave.</p>
<h2 id="heading-lets-smooth-it-out"><strong>Let’s smooth it out</strong></h2>
<p>We’re going to fix this with as little code change as possible — just enough to demonstrate the concept of <strong>phase continuity.</strong></p>
<p>We’ll do that by:</p>
<ul>
<li><p>Tracking a persistent phase variable across the entire loop</p>
</li>
<li><p>Using freq only to adjust <strong>how fast</strong> phase advances — not where it starts</p>
</li>
</ul>
<h3 id="heading-quick-recap"><strong>Quick recap</strong></h3>
<p>As we saw earlier, using this formula: <code>sample = amplitude * sin(2π × frequency × time)</code> …works great <strong>until the frequency changes</strong>. Then the wave <strong>jumps</strong> because time keeps going, but the math rebuilds a brand new sine wave. The waveform doesn’t connect smoothly — and that sharp transition becomes an audible <strong>click</strong>.</p>
<h3 id="heading-the-fix"><strong>The fix</strong></h3>
<p>Here’s our original melody code, with just a few crucial lines added:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::<span class="hljs-built_in">f32</span>::consts::PI;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> spec = hound::WavSpec {
        channels: <span class="hljs-number">1</span>,
        sample_rate: <span class="hljs-number">44100</span>,
        bits_per_sample: <span class="hljs-number">16</span>,
        sample_format: hound::SampleFormat::Int,
    };

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> writer =
        hound::WavWriter::create(<span class="hljs-string">"melody_fixed.wav"</span>, spec).expect(<span class="hljs-string">"Failed to create WAV file"</span>);

    <span class="hljs-keyword">let</span> duration_secs = <span class="hljs-number">8.0</span>;
    <span class="hljs-keyword">let</span> amplitude = <span class="hljs-built_in">i16</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;

    <span class="hljs-keyword">let</span> sample_rate = spec.sample_rate <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;
    <span class="hljs-keyword">let</span> total_samples = (sample_rate * duration_secs) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;

    <span class="hljs-comment">// NEW: keep track of waveform position</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> phase = <span class="hljs-number">0.0</span>;

    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..total_samples {
        <span class="hljs-keyword">let</span> time = t <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / sample_rate;

        <span class="hljs-keyword">let</span> freq_hz = <span class="hljs-keyword">match</span> time.ceil() {
            <span class="hljs-number">1.0</span> =&gt; <span class="hljs-number">440.0</span>,  <span class="hljs-comment">// A4</span>
            <span class="hljs-number">2.0</span> =&gt; <span class="hljs-number">494.0</span>,  <span class="hljs-comment">// B4</span>
            <span class="hljs-number">3.0</span> =&gt; <span class="hljs-number">523.25</span>, <span class="hljs-comment">// C5</span>
            <span class="hljs-number">4.0</span> =&gt; <span class="hljs-number">587.33</span>, <span class="hljs-comment">// D5</span>
            <span class="hljs-number">5.0</span> =&gt; <span class="hljs-number">659.25</span>, <span class="hljs-comment">// E5</span>
            <span class="hljs-number">6.0</span> =&gt; <span class="hljs-number">698.46</span>, <span class="hljs-comment">// F5</span>
            <span class="hljs-number">7.0</span> =&gt; <span class="hljs-number">783.99</span>, <span class="hljs-comment">// G5</span>
            _ =&gt; <span class="hljs-number">880.0</span>,    <span class="hljs-comment">// A5</span>
        };

        <span class="hljs-comment">// NEW: advance phase smoothly based on current frequency</span>
        <span class="hljs-keyword">let</span> phase_increment = <span class="hljs-number">2.0</span> * PI * freq_hz / sample_rate;
        phase = (phase + phase_increment) % (<span class="hljs-number">2.0</span> * PI);

        <span class="hljs-comment">// sample now comes from continuous phase</span>
        <span class="hljs-keyword">let</span> sample = (amplitude * phase.sin()) <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>;
        writer.write_sample(sample).unwrap();
    }

    writer.finalize().unwrap();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"✅ Melody written to 'melody_fixed.wav'"</span>);
}
</code></pre>
<p>If you open the new <code>.wav</code> file in Audacity, you’ll notice something important:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767808240689/3fcece35-8925-4ab1-afd5-08b8dac8e159.png" alt class="image--center mx-auto" /></p>
<p>✅ No more sudden jumps in the waveform.</p>
<p>Even when the <strong>frequency</strong> changes, the wave connects naturally.</p>
<p>If you zoom in to the same transition point as before (say, between second 5 and 6), you’ll see that the waveform now flows <strong>without a visible click</strong>.</p>
<p>That’s <strong>phase continuity</strong> in action.</p>
<h2 id="heading-what-changed"><strong>What changed?</strong></h2>
<p>Instead of recalculating the sine wave angle from scratch every time, we now:</p>
<ul>
<li><p>Keep a <strong>phase</strong> that tracks our position inside the waveform</p>
</li>
<li><p>Move it forward a tiny bit for each sample, based on the <strong>current frequency</strong></p>
</li>
<li><p>Use <strong>sin(phase)</strong> to get the sample value</p>
</li>
<li><p>Wrap it around once it reaches <strong>2π</strong> to avoid overflow</p>
</li>
</ul>
<h3 id="heading-what-is-a-radian"><strong>What is a radian?</strong></h3>
<p>A <strong>radian</strong> is just a unit for measuring angles — like degrees, but more mathematically convenient.</p>
<ul>
<li><p>A full circle is <strong>360°</strong>, right?</p>
</li>
<li><p>In radians, a full circle is <strong>2π radians</strong> (≈ 6.283)</p>
</li>
</ul>
<p>So when we talk about <strong>2π</strong>, we’re talking about <strong>one full rotation</strong> — or in waveform terms, <strong>one full sine wave cycle</strong>.</p>
<p>Let’s say we want to generate a <strong>440 Hz</strong> tone (A4). That means we need to complete <strong>440 full sine wave cycles every second</strong>.</p>
<p>Since one full cycle is <strong>2π radians</strong>, we need to sweep through: <code>2π × 440 = 2764.6</code> <strong>radians per second</strong>.</p>
<p>That’s the <strong>total angular distance</strong> our sine wave needs to travel per second to hit that pitch.</p>
<h3 id="heading-how-much-to-move-per-sample"><strong>How much to move per sample</strong></h3>
<p>But we don’t generate one sample per second — we generate <strong>44100 samples per second</strong>. So we have to split that angular distance across all <strong>44100 samples</strong>.</p>
<p>Here’s the math:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> phase_increment = (<span class="hljs-number">2.0</span> * PI * frequency) / sample_rate;
</code></pre>
<p>This gives us the <strong>tiny step</strong> we take through the wave with each sample.</p>
<p>Using our <strong>440 Hz</strong> example: <code>phase_increment ≈ 0.0627</code> <strong>radians per sample</strong>.</p>
<p>That means <strong>every sample</strong> moves us forward about <strong>0.0627 radians</strong> through the sine wave.</p>
<p>And since one full wave cycle is <strong>2π radians</strong>, we can divide: <code>2π / 0.0627 ≈ 100</code> <strong>samples</strong>.</p>
<p>So it takes <strong>around 100 samples</strong> to complete <strong>one full sine wave cycle</strong> at <strong>440 Hz.</strong></p>
<p>By adjusting the <strong>phase increment</strong>, we control how many samples it takes to go from <strong>0</strong> → <strong>2π</strong> → back to <strong>0</strong>.</p>
<h3 id="heading-why-2p"><strong>Why % (2π)</strong></h3>
<p>In our code, we update the phase like this:</p>
<pre><code class="lang-rust">phase = (phase + phase_increment) % (<span class="hljs-number">2.0</span> * PI);
</code></pre>
<p>So why are we using <strong>modulo 2π</strong> here?</p>
<p><strong>Because the sine wave is a loop.</strong></p>
<p>A full sine wave cycle is exactly <strong>2π radians</strong> — and after that, it just repeats.</p>
<p><strong>That means:</strong></p>
<ul>
<li><p>sin(0) = sin(2π) = sin(4π)</p>
</li>
<li><p>sin(π/2) = sin(2π + π/2) = sin(4π + π/2)</p>
</li>
<li><p>…and so on</p>
</li>
</ul>
<p>So whether the phase is 6.3, 12.6, 18.9, etc — the result of sin(phase) will be the <strong>same shape</strong>, just wrapped around.</p>
<p>By keeping phase in the range <strong>0.0..2π</strong>, we:</p>
<ul>
<li><p>Keep everything tidy</p>
</li>
<li><p>Prevent precision drift</p>
</li>
<li><p>Avoid weird edge cases down the line</p>
</li>
</ul>
<h2 id="heading-thats-a-wrap-for-part-2"><strong>🏁 That’s a wrap for [PART 2]</strong></h2>
<p>In this post, we turned our naive melody generator into something <strong>smarter</strong> and <strong>smoother</strong>.</p>
<p>We uncovered and explained a common problem in audio programming (clicks from phase discontinuity), and we fixed it using one of the most fundamental DSP concepts: <strong>tracking phase over time</strong>.</p>
<p>This technique isn’t just a trick — it’s the foundation of how digital sound generators work under the hood.</p>
<p>And even though we haven’t formally built an <strong>oscillator</strong> yet, we’re already using one in spirit — <strong>walking through the waveform cycle sample by sample</strong>.</p>
<h2 id="heading-whats-next"><strong>🔜 What’s next?</strong></h2>
<p>In <strong>Part 3</strong>, we’ll finally write our first <strong>true oscillator</strong> and take things further:</p>
<ul>
<li><p>Generate different waveforms</p>
</li>
<li><p>Compare how they sound and look</p>
</li>
<li><p>Learn how waveform shape affects tone and harmonics</p>
</li>
</ul>
<p>▶️ <strong>Continue to Part 3:</strong></p>
<p><a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-exploring-the-waveforms-part-3">Rust Audio Programming: Oscillator – Exploring the waveforms [PART 3]</a></p>
<p>💾 <strong>Source code from this article:</strong></p>
<p><a target="_blank" href="https://github.com/paramako-blog/oscillator/blob/main/examples/part2_frequency_changes.rs"><strong>View on GitHub →</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[Rust Audio Programming: Oscillator – Build a sine wave [PART 1]]]></title><description><![CDATA[Hey there 👋!
Whether you’re a seasoned rustacean, a curious audio hacker, or just someone who thinks synths are cool — welcome aboard!
This is the Rust Audio Programming series, and today we’re diving into the basics of audio programming by building...]]></description><link>https://blog.paramako.com/rust-audio-programming-oscillator-build-a-sine-wave-part-1</link><guid isPermaLink="true">https://blog.paramako.com/rust-audio-programming-oscillator-build-a-sine-wave-part-1</guid><category><![CDATA[audio programming]]></category><category><![CDATA[Digital Signal Processing]]></category><category><![CDATA[Audio Processing]]></category><category><![CDATA[audio]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Yurii]]></dc:creator><pubDate>Sat, 21 Jun 2025 13:21:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750511628093/bd609b42-1241-4509-8bfa-83e55786595f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey there 👋!</p>
<p>Whether you’re a seasoned rustacean, a curious audio hacker, or just someone who thinks synths are cool — <strong>welcome aboard!</strong></p>
<p>This is the <strong>Rust Audio Programming</strong> series, and today we’re diving into the <strong>basics of audio programming</strong> by building our very first <strong>sine wave</strong> — the audio equivalent of “hello, world”.</p>
<blockquote>
<p>⚙️ <em>This tutorial assumes you already have the Rust toolchain installed (via</em> <a target="_blank" href="https://rustup.rs"><em>rustup</em></a>). If not, check out the official install guide — setting it up is out of scope for this post.</p>
</blockquote>
<h2 id="heading-so-what-digital-sound-is">So what digital sound is?</h2>
<p><strong>Sound</strong>, at its core, is a <strong>vibration in the air</strong> — pressure <strong>waves</strong> that travel to our ears. Inside, these vibrations are turned into signals that our brains understand as sound.</p>
<p>In the digital world, we sample these continuous waves at <strong>discrete intervals</strong> — usually thousands of times per second — and store the values as numbers.</p>
<p>This is known as <strong>digital audio</strong>. For example, CD-quality audio samples the waveform 44,100 times per second (44.1 kHz), capturing its shape with enough detail that it sounds smooth and natural to the human ear.</p>
<h2 id="heading-enter-the-waveform">Enter the waveform</h2>
<p>Every sound you hear — a piano note, a bird chirp, a voice — has a unique <strong>waveform</strong>. The shape of this waveform determines the character or <strong>timbre</strong> of the sound.</p>
<p>Waves are building blocks of synthetic sound, and they’re what we’ll be working with in this series.</p>
<h2 id="heading-whats-a-note-really">What’s a note, really?</h2>
<p>When we talk about a musical <strong>note</strong>, we're really talking about <strong>a specific frequency of vibration</strong> — how fast the air is wiggling back and forth. Each full wiggle is called a <strong>cycle</strong>.</p>
<p>That frequency is measured in <strong>hertz (Hz)</strong>, or <strong>cycles per second</strong>. So if a sound wave vibrates 440 times in one second, it has a frequency of <strong>440 Hz</strong> — which just happens to be the pitch of the musical note <strong>A4</strong>.</p>
<p><img src="https://images.squarespace-cdn.com/content/v1/5d0434f328d8d9000101f755/1585620613365-X8HXP8D6S9MNEE04CL8W/Screen+Shot+2020-03-30+at+6.32.27+PM.png" alt="The Science of Music — Kaitlin Bove Music" /></p>
<p>Different notes are just <strong>different frequencies</strong>:</p>
<ul>
<li><p>A lower note? Slower vibrations (lower Hz).</p>
</li>
<li><p>A higher note? Faster vibrations (higher Hz).</p>
</li>
</ul>
<p>So when we generate sound in code, we’re not saying <strong>“<em>play A4</em>”</strong> we’re saying <strong><em>“generate a waveform that cycles at 440 Hz.”</em></strong>.</p>
<h2 id="heading-lets-try-it-out">Let’s try it out!</h2>
<p>First, let’s set up a fresh Rust project for our experiment. Open your terminal and run:</p>
<pre><code class="lang-bash">cargo new sine_wave &amp;&amp; <span class="hljs-built_in">cd</span> sine_wave
</code></pre>
<blockquote>
<p>💡 <em>These examples use Unix-style commands (Linux/macOS). If you’re on Windows… well, you know the drill — adjust accordingly</em>.</p>
</blockquote>
<p>Before jumping into code, let’s take a second to understand <strong>what we’re actually generating</strong>.</p>
<p>We’re going to produce a <strong>2-second sine wave</strong> that plays the musical note <strong>A4</strong> — which has a frequency of <strong>440 Hz</strong>. That means the waveform will complete <strong>440 full cycles every second</strong>.</p>
<p>To represent that wave digitally, we’ll <strong>sample it</strong> — break it down into thousands of tiny values we can save to a file.</p>
<p>We’ll use a <strong>sample rate of 44100 Hz</strong> (standard CD quality), meaning we’ll capture <strong>44100 samples per second</strong>. For 2 seconds of audio: <code>44100 samples/sec × 2 sec = 88200 samples.</code></p>
<p>To generate each sample, we’ll use the classic sine wave equation: <code>sample = amplitude × sin(2π × frequency × time)</code>, where:</p>
<ul>
<li><p>frequency is <strong>440.0 (A4)</strong></p>
</li>
<li><p>time is the current time in seconds for each sample (t / sample_rate)</p>
</li>
<li><p>amplitude controls the volume — we’ll use the max for 16-bit audio</p>
</li>
</ul>
<blockquote>
<p>🧠 <strong>Isn’t the sine formula usually written differently?</strong></p>
<p>In math you’ll often see it as A × sin(2πft + φ), where φ is the <strong>phase offset</strong>.</p>
<p>In our case, we’re starting the wave right at the beginning of its cycle, so we just set phase to zero — and skip it entirely.</p>
</blockquote>
<p>Now let’s generate our very first <strong>sine wave</strong> and save it as a .wav file we can actually play and analyze.</p>
<p>To do that, we’ll use a single dependency: <a target="_blank" href="https://crates.io/crates/hound">hound</a>.</p>
<p>Run this in your terminal:</p>
<pre><code class="lang-bash">cargo add hound@3.5
</code></pre>
<blockquote>
<p>hound is a simple Rust library for reading and writing WAV files.</p>
</blockquote>
<p>Open <code>src/main.rs</code> and replace everything with this:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::<span class="hljs-built_in">f32</span>::consts::PI;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// WAV file settings</span>
    <span class="hljs-keyword">let</span> spec = hound::WavSpec {
        channels: <span class="hljs-number">1</span>,        <span class="hljs-comment">// mono</span>
        sample_rate: <span class="hljs-number">44100</span>, <span class="hljs-comment">// samples per second</span>
        bits_per_sample: <span class="hljs-number">16</span>,
        sample_format: hound::SampleFormat::Int,
    };
    <span class="hljs-comment">// Create a WAV writer</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> writer = hound::WavWriter::create(<span class="hljs-string">"sine.wav"</span>, spec).expect(<span class="hljs-string">"Failed to create WAV file"</span>);
    <span class="hljs-comment">// Sine wave parameters</span>
    <span class="hljs-keyword">let</span> freq_hz = <span class="hljs-number">440.0</span>; <span class="hljs-comment">// frequency (A4)</span>
    <span class="hljs-keyword">let</span> duration_secs = <span class="hljs-number">2.0</span>; <span class="hljs-comment">// 2 seconds</span>
    <span class="hljs-keyword">let</span> amplitude = <span class="hljs-built_in">i16</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>; <span class="hljs-comment">// max volume</span>

    <span class="hljs-keyword">let</span> sample_rate = spec.sample_rate <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;
    <span class="hljs-keyword">let</span> total_samples = (sample_rate * duration_secs) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;

    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..total_samples {
        <span class="hljs-keyword">let</span> time = t <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / sample_rate;
        <span class="hljs-keyword">let</span> sample = (amplitude * (<span class="hljs-number">2.0</span> * PI * freq_hz * time).sin()) <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>;
        writer.write_sample(sample).unwrap();
    }

    writer.finalize().unwrap();
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"✅ Sine wave written to 'sine.wav'"</span>);
}
</code></pre>
<h3 id="heading-whats-happening-in-the-code"><strong>What’s happening in the code?</strong></h3>
<p>Let’s break down the essential parts:</p>
<p><strong>1. WAV file setup</strong></p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> spec = hound::WavSpec {
    channels: <span class="hljs-number">1</span>,
    sample_rate: <span class="hljs-number">44100</span>,
    bits_per_sample: <span class="hljs-number">16</span>,
    sample_format: hound::SampleFormat::Int,
};
</code></pre>
<p>We configure the .wav file to be:</p>
<ul>
<li><p><strong>Mono</strong> audio (channels: 1)</p>
</li>
<li><p><strong>44.1 kHz</strong> sample rate (standard quality)</p>
</li>
<li><p><strong>16-bit samples</strong> (i.e., each sample is stored as a signed 16-bit integer)</p>
</li>
</ul>
<p><strong>2. Main parameters</strong></p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> freq_hz = <span class="hljs-number">440.0</span>;
<span class="hljs-keyword">let</span> duration_secs = <span class="hljs-number">2.0</span>;
<span class="hljs-keyword">let</span> amplitude = <span class="hljs-built_in">i16</span>::MAX <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>;
</code></pre>
<p>We want a <strong>440 Hz sine wave</strong> (A4 note) that lasts <strong>2 seconds</strong>, at <strong>maximum volume</strong>.</p>
<p><strong>3. Generate samples</strong></p>
<pre><code class="lang-rust"><span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..total_samples {
    <span class="hljs-keyword">let</span> time = t <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span> / sample_rate;
    <span class="hljs-keyword">let</span> sample = (amplitude * (<span class="hljs-number">2.0</span> * PI * freq_hz * time).sin()) <span class="hljs-keyword">as</span> <span class="hljs-built_in">i16</span>;
    writer.write_sample(sample).unwrap();
}

writer.finalize().unwrap();
</code></pre>
<p>We:</p>
<ul>
<li><p><strong>Loop through each sample</strong></p>
</li>
<li><p><strong>Use the sine wave formula to calculate its value</strong></p>
</li>
<li><p><strong>Write the value to the WAV writer’s internal buffer</strong></p>
</li>
</ul>
<p>Then, in the next step:</p>
<ul>
<li><strong>Call .finalize() to flush the buffer and write everything to the file</strong></li>
</ul>
<p>Now let’s actually <strong>run the code</strong> and hear what we’ve created:</p>
<pre><code class="lang-bash">cargo run
</code></pre>
<p>You should see:</p>
<blockquote>
<p>✅ Sine wave written to 'sine.wav'</p>
</blockquote>
<p>That means your .wav file was successfully generated! Now go ahead and <strong>play</strong> <code>sine.wav</code> using your favourite audio player.</p>
<p>If everything worked, you should hear a <strong>clean, steady tone</strong> — no clicks, no weird noise. That’s a <strong>pure 440 Hz sine wave</strong>, also known as <strong>concert A</strong>.</p>
<h2 id="heading-lets-see-the-sound"><strong>Let’s see the sound</strong></h2>
<p>To visualize the waveform, open <code>sine.wav</code> in <a target="_blank" href="https://www.audacityteam.org/"><strong>Audacity</strong></a> — a free, open-source audio editor that makes it easy to zoom in and inspect waveforms.</p>
<p>You should see a <strong>smooth, repeating sine wave</strong> — but heads up, it might not look like much at first.</p>
<p>Audacity will probably show it as a solid block by default. <strong>Zoom in horizontally</strong> until you can see the individual wave cycles — that’s your sine wave in action!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749388654941/361e09a5-5c0f-44a2-8a35-4b1a3e07899f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-thats-a-wrap-for-part-1"><strong>🏁 That’s a wrap for [PART 1]</strong></h2>
<p>Congrats — you just generated your first sine wave <strong>from scratch</strong> using Rust. 🎉</p>
<p>You now understand:</p>
<ul>
<li><p>What digital sound is</p>
</li>
<li><p>How sampling works</p>
</li>
<li><p>How to generate individual audio samples using math</p>
</li>
</ul>
<p>Not bad for one article, huh?</p>
<h2 id="heading-whats-next"><strong>🔜 What’s next?</strong></h2>
<p>In the next part of this series, we’ll build on what we’ve made by <strong>changing the note over time</strong> — like playing a simple melody with just a sine wave.</p>
<p>It sounds straightforward… but we’ll run into some interesting behavior that’s worth a closer look 👀</p>
<p>Along the way, we’ll improve the math behind our <strong>waveform generation</strong> and start shaping the code into something more flexible and reusable.</p>
<p>▶️ <strong>Continue to Part 2:</strong></p>
<p><a target="_blank" href="https://blog.paramako.com/rust-audio-programming-oscillator-handle-frequency-changes-smoothly-part-2"><em>Rust Audio Programming: Oscillator – Handle frequency changes smoothly [PART 2]</em></a></p>
<p>💾 <strong>Source code from this article:</strong></p>
<p><a target="_blank" href="https://github.com/paramako-blog/oscillator/blob/main/examples/part1_sine_wave.rs">View on GitHub →</a></p>
]]></content:encoded></item><item><title><![CDATA[Rust + Docker: Easy packaging of your applications]]></title><description><![CDATA[Let's first create a simple web app with a health check endpoint by running the commands below.
cargo new rust_docker_app --bin
cd rust_docker_app
cargo add actix-web
touch Dockerfile

So what we've actually done here:

created a new binary crate, ca...]]></description><link>https://blog.paramako.com/rust-docker-easy-packaging-of-your-applications</link><guid isPermaLink="true">https://blog.paramako.com/rust-docker-easy-packaging-of-your-applications</guid><category><![CDATA[Rust]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Dockerfile]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Yurii]]></dc:creator><pubDate>Mon, 09 Jan 2023 13:59:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673258052250/48315029-8799-404b-af89-e00911bfee07.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's first create a simple web app with a health check endpoint by running the commands below.</p>
<pre><code class="lang-bash">cargo new rust_docker_app --bin
<span class="hljs-built_in">cd</span> rust_docker_app
cargo add actix-web
touch Dockerfile
</code></pre>
<p><strong>So what we've actually done here:</strong></p>
<ul>
<li><p>created a new binary crate, called <strong>rust_docker_app</strong></p>
</li>
<li><p>added web framework dependency (I prefer <a target="_blank" href="https://actix.rs/">Actix</a>, but you can choose any)</p>
</li>
<li><p>created empty <a target="_blank" href="https://docs.docker.com/engine/reference/builder/">DockerFile</a></p>
</li>
</ul>
<p>Now let's create a web server with one simple health check endpoint. To do this, you need to update your <code>main.rs</code> file with:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> actix_web::{App, HttpServer, HttpResponse, get};

<span class="hljs-meta">#[actix_web::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>() -&gt; std::io::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    HttpServer::new(|| {
        App::new()
            .service(ping)
    })
    .bind((<span class="hljs-string">"0.0.0.0"</span>, <span class="hljs-number">8080</span>))?
    .run()
    .<span class="hljs-keyword">await</span>
}

<span class="hljs-meta">#[get(<span class="hljs-meta-string">"/ping"</span>)]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">ping</span></span>() -&gt; HttpResponse {
    HttpResponse::<span class="hljs-literal">Ok</span>().body(<span class="hljs-string">"pong"</span>)
}
</code></pre>
<p>So we created an app with <code>0.0.0.0</code> address and <code>8080</code> port bindings.</p>
<p><code>0.0.0.0</code> is the special <strong>“all interfaces”</strong> address. You must set a docker container’s main process (Actix web app in our case) to bind to it, or it will be unreachable from outside the container.</p>
<p>Our app has only one endpoint, which responds with a "pong" message all the time.</p>
<p>Now let's update our <strong>Dockerfile</strong> with:</p>
<pre><code class="lang-bash">FROM rust:1.66.0 as build
COPY . /rust_docker_app
WORKDIR /rust_docker_app

RUN --mount=<span class="hljs-built_in">type</span>=cache,target=/usr/<span class="hljs-built_in">local</span>/cargo/registry --mount=<span class="hljs-built_in">type</span>=cache,target=/root/target \
    cargo build --release

FROM debian:buster-slim as runtime
COPY --from=build /rust_docker_app/target/release/rust_docker_app .
CMD [<span class="hljs-string">"./rust_docker_app"</span>]
</code></pre>
<p>We don't need any project files except compiled binary in our image, that's why we use multi-stage build.</p>
<p>You can read more about multi-stage builds here: <a target="_blank" href="https://docs.docker.com/build/building/multi-stage/">https://docs.docker.com/build/building/multi-stage/</a></p>
<p><strong>So what does this Dockerfile do step by step:</strong></p>
<ul>
<li><p>copy project files to the first (build) stage</p>
</li>
<li><p>compile the code</p>
</li>
<li><p>copy the binary executable file from the "build" stage to the "runtime" stage, leaving behind everything else we don’t want in the final image</p>
</li>
<li><p>run the compiled binary</p>
</li>
</ul>
<p>This part is needed <code>--mount=type=cache,target=/usr/local/cargo/registry</code> for caching <strong>Rust</strong> dependencies and it defines which path should be cached as a container image layer.</p>
<p>Now we are ready to build our image. Simply just run the below command in the project root directory:</p>
<pre><code class="lang-bash">docker build -t rust_docker_app .
</code></pre>
<p>And finally, let's run our web server:</p>
<pre><code class="lang-bash">docker run -p 8080:8080 rust_docker_app
</code></pre>
<p>Now you can access the health check endpoint by <a target="_blank" href="http://127.0.0.1:8080/ping">http://127.0.0.1:8080/ping</a>. Just try to get it via browser or <strong>CURL</strong> or any other <strong>HTTP</strong> client.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673271946245/a040db39-0f49-48d7-a429-5998d8d3a5e5.png" alt class="image--center mx-auto" /></p>
<p>I hope you enjoy it. As always you can find working example in my <a target="_blank" href="https://github.com/paramako-blog/rust_docker_app"><strong>GitHub</strong></a> repository :)</p>
]]></content:encoded></item><item><title><![CDATA[Running Rust on AWS Lambda. Part 2]]></title><description><![CDATA[In previous article we`ve created a simple code example of AWS lambda SQS consumer.
In this one, we will learn how to configure and run it on AWS.
This article is not about the CI/CD best practises. I just want to show you in a simple examples how to...]]></description><link>https://blog.paramako.com/running-rust-on-aws-lambda-part-2</link><guid isPermaLink="true">https://blog.paramako.com/running-rust-on-aws-lambda-part-2</guid><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[Rust]]></category><category><![CDATA[SQS]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Yurii]]></dc:creator><pubDate>Fri, 16 Sep 2022 07:34:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659007032851/eOEh_VOHG.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a target="_blank" href="https://paramako.com/running-rust-on-aws-lambda-part-1">previous article</a> we`ve created a simple code example of <strong>AWS lambda</strong> <strong>SQS</strong> consumer.</p>
<p>In this one, we will learn how to configure and run it on <strong>AWS</strong>.</p>
<p>This article is not about the CI/CD best practises. I just want to show you in a simple examples how to run and test your code on <strong>AWS lambda</strong>.</p>
<p>Let's go!</p>
<h2 id="heading-create-role">Create Role</h2>
<p>Firstly, we need to create a role, that will allow our lambda functions to pop data from <strong>SQS</strong>.</p>
<p>Enter the <strong>AWS console</strong> roles web interface and click on the <strong>Create role</strong> button.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659007875758/abthWf885.png" alt="image.png" /></p>
<p>Choose <strong>AWS service</strong> as trusted entity and <strong>lambdas</strong> as a common use case, then click on the <strong>Next</strong> button
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659008182066/KVH5s0BXI.png" alt="image.png" /></p>
<p>Attach <strong>AWSLambdaSQSQueueExecutionRole</strong> policy to your new role and click on the <strong>Next</strong> button
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659008600624/rLrIJY9tO.png" alt="image.png" />
Name your role as <strong>TestRustLambdaRole</strong>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659008703274/ap9hJrlhm.png" alt="image.png" />
Click on the <strong>Create Role</strong> button.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659008753399/eu_omrIjE.png" alt="image.png" /></p>
<p>Perfect! Our new role is created successfully!</p>
<h2 id="heading-create-aws-lambda-function">Create AWS lambda function</h2>
<p>Enter the <strong>AWS console</strong> lambdas web interface and click on the <strong>Create function</strong> button.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659007652081/a84ZULHV-.png" alt="image.png" /></p>
<p>Then just fill in the <strong>Basic information</strong> block this way</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659007738461/07BYn5wNB.png" alt="image.png" /></p>
<p>Choose <strong>TestRustLambdaRole</strong> as a execution role of our lambda function
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659009195250/QZgDp9xDi.png" alt="image.png" />
Click on <strong>Create function</strong> button
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659009234929/R9vDy7-rG.png" alt="image.png" /></p>
<h2 id="heading-test-aws-lambda">Test AWS lambda</h2>
<h3 id="heading-build-and-deploy">Build and deploy</h3>
<p>Firstly, we need to build our code.
Everything we need is to run this command</p>
<pre><code class="lang-bash">cargo lambda build --release --bin rust-lambda-example --arm64 --output-format zip
</code></pre>
<p>Our compiled binary will be stored in path: <code>target/lambda/rust-lambda-example</code>.</p>
<p>Then in your new lambda function web interface go to the <strong>Code</strong> section and click on <code>Upload from -&gt; .zip file</code> and upload our binary
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659010268580/gbekduaek.png" alt="image.png" /></p>
<h3 id="heading-test-in-aws-console">Test in AWS console</h3>
<p>Now we need to create a test event.</p>
<p>Go to the <strong>Test</strong> section, and name our new test event</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659010558537/nvUkUgWT9.png" alt="image.png" />
 Then add the SQS event sample below to Event JSON block
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659010742507/40YD962UG.png" alt="image.png" />
and click on the <strong>Save</strong> button
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659010786228/7X8gBMfck.png" alt="image.png" /></p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Records"</span>: [
      {
        <span class="hljs-attr">"messageId"</span> : <span class="hljs-string">"MessageID_1"</span>,
        <span class="hljs-attr">"receiptHandle"</span> : <span class="hljs-string">"MessageReceiptHandle"</span>,
        <span class="hljs-attr">"body"</span> : <span class="hljs-string">"Hello from message 1!"</span>,
        <span class="hljs-attr">"md5OfBody"</span> : <span class="hljs-string">"fce0ea8dd236ccb3ed9b37dae260836f"</span>,
        <span class="hljs-attr">"md5OfMessageAttributes"</span> : <span class="hljs-string">"582c92c5c5b6ac403040a4f3ab3115c9"</span>,
        <span class="hljs-attr">"eventSourceARN"</span>: <span class="hljs-string">"arn:aws:sqs:us-west-2:123456789012:SQSQueue"</span>,
        <span class="hljs-attr">"eventSource"</span>: <span class="hljs-string">"aws:sqs"</span>,
        <span class="hljs-attr">"awsRegion"</span>: <span class="hljs-string">"us-west-2"</span>,
        <span class="hljs-attr">"attributes"</span> : {
          <span class="hljs-attr">"ApproximateReceiveCount"</span> : <span class="hljs-string">"2"</span>,
          <span class="hljs-attr">"SentTimestamp"</span> : <span class="hljs-string">"1520621625029"</span>,
          <span class="hljs-attr">"SenderId"</span> : <span class="hljs-string">"AROAIWPX5BD2BHG722MW4:sender"</span>,
          <span class="hljs-attr">"ApproximateFirstReceiveTimestamp"</span> : <span class="hljs-string">"1520621634884"</span>
        },
        <span class="hljs-attr">"messageAttributes"</span> : {
          <span class="hljs-attr">"Attribute3"</span> : {
            <span class="hljs-attr">"binaryValue"</span> : <span class="hljs-string">"MTEwMA=="</span>,
            <span class="hljs-attr">"stringListValues"</span> : [<span class="hljs-string">"abc"</span>, <span class="hljs-string">"123"</span>],
            <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MA=="</span>, <span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
            <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Binary"</span>
          },
          <span class="hljs-attr">"Attribute2"</span> : {
            <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"123"</span>,
            <span class="hljs-attr">"stringListValues"</span> : [ ],
            <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
            <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Number"</span>
          },
          <span class="hljs-attr">"Attribute1"</span> : {
            <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"AttributeValue1"</span>,
            <span class="hljs-attr">"stringListValues"</span> : [ ],
            <span class="hljs-attr">"binaryListValues"</span> : [ ],
            <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"String"</span>
          }
        }
      },
      {
        <span class="hljs-attr">"messageId"</span> : <span class="hljs-string">"MessageID_2"</span>,
        <span class="hljs-attr">"receiptHandle"</span> : <span class="hljs-string">"MessageReceiptHandle"</span>,
        <span class="hljs-attr">"body"</span> : <span class="hljs-string">"Hello from message 2!"</span>,
        <span class="hljs-attr">"md5OfBody"</span> : <span class="hljs-string">"fce0ea8dd236ccb3ed9b37dae260836f"</span>,
        <span class="hljs-attr">"md5OfMessageAttributes"</span> : <span class="hljs-string">"582c92c5c5b6ac403040a4f3ab3115c9"</span>,
        <span class="hljs-attr">"eventSourceARN"</span>: <span class="hljs-string">"arn:aws:sqs:us-west-2:123456789012:SQSQueue"</span>,
        <span class="hljs-attr">"eventSource"</span>: <span class="hljs-string">"aws:sqs"</span>,
        <span class="hljs-attr">"awsRegion"</span>: <span class="hljs-string">"us-west-2"</span>,
        <span class="hljs-attr">"attributes"</span> : {
          <span class="hljs-attr">"ApproximateReceiveCount"</span> : <span class="hljs-string">"2"</span>,
          <span class="hljs-attr">"SentTimestamp"</span> : <span class="hljs-string">"1520621625029"</span>,
          <span class="hljs-attr">"SenderId"</span> : <span class="hljs-string">"AROAIWPX5BD2BHG722MW4:sender"</span>,
          <span class="hljs-attr">"ApproximateFirstReceiveTimestamp"</span> : <span class="hljs-string">"1520621634884"</span>
        },
        <span class="hljs-attr">"messageAttributes"</span> : {
          <span class="hljs-attr">"Attribute3"</span> : {
            <span class="hljs-attr">"binaryValue"</span> : <span class="hljs-string">"MTEwMA=="</span>,
            <span class="hljs-attr">"stringListValues"</span> : [<span class="hljs-string">"abc"</span>, <span class="hljs-string">"123"</span>],
            <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MA=="</span>, <span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
            <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Binary"</span>
          },
          <span class="hljs-attr">"Attribute2"</span> : {
            <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"123"</span>,
            <span class="hljs-attr">"stringListValues"</span> : [ ],
            <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
            <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Number"</span>
          },
          <span class="hljs-attr">"Attribute1"</span> : {
            <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"AttributeValue1"</span>,
            <span class="hljs-attr">"stringListValues"</span> : [ ],
            <span class="hljs-attr">"binaryListValues"</span> : [ ],
            <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"String"</span>
          }
        }
      }
    ]
  }
</code></pre>
<p>The next thing we should do to make the code from previous article work is to add environment variable</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659010910118/yjdkahCen.png" alt="image.png" /></p>
<p>After that let's move back to <strong>Code</strong> section.
Here just choose our new test event and click on the <strong>Test</strong> button
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659011008860/vtLu8O6f5.png" alt="image.png" />
As you can see, the output is the same as in local test from a first article. Our lambda is working!</p>
<pre><code class="lang-bash">Function Logs
START RequestId: 56cbfd84-3601-4c13-9da6-84b94aed972a Version: <span class="hljs-variable">$LATEST</span>
<span class="hljs-built_in">test</span>
Hello from message 1!
Hello from message 2!
END RequestId: 56cbfd84-3601-4c13-9da6-84b94aed972a
REPORT RequestId: 56cbfd84-3601-4c13-9da6-84b94aed972a    Duration: 0.99 ms    Billed Duration: 19 ms    Memory Size: 128 MB    Max Memory Used: 13 MB    Init Duration: 17.17 ms
</code></pre>
<h2 id="heading-connect-lambda-with-sqs-events">Connect lambda with SQS events</h2>
<p>Create SQS queue with default settings by filling in the name</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659011483428/Z5RhibSWM.png" alt="image.png" />
and pressing <strong>Create queue</strong> button
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659011679605/WtpqBZtKN.png" alt="image.png" /></p>
<p>Next, go back to your lambda function interface and add a new trigger</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659011822889/EF940N1L8.png" alt="image.png" /></p>
<p>Select <strong>SQS</strong> as a source</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659011904018/0BJ846LiC.png" alt="image.png" />
and our new created queue</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659011940803/hlPDaXB37.png" alt="image.png" />
Then add this trigger to our lambda function</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659012043982/DX8Ez9LzC.png" alt="image.png" /></p>
<p>To test that everything works as expected let's decrease trigger batch size to 1</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659012397639/JPRVk2Npr.png" alt="image.png" /></p>
<p>and then move back to your SQS web interface and click on 
<strong>send and receive messages</strong> button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659012434539/x-SbgV0lz.png" alt="image.png" /></p>
<p>And push a test message to the queue</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659012267836/3EoFw3peS.png" alt="image.png" /></p>
<p>Then go to the <strong>Monitor</strong> -&gt; <strong>logs</strong> section in your lambda function interface</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659012511866/xAGbE_jSl.png" alt="image.png" /></p>
<p>Here you can see that our lambda handled the new message</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659012542422/pGcvY-nCc.png" alt="image.png" /></p>
]]></content:encoded></item><item><title><![CDATA[Running Rust on AWS Lambda. Part 1]]></title><description><![CDATA[AWS Lambda is a serverless computing service provided by Amazon Web Services.
The Lambda functions can perform any kind of computing task, from serving web pages and processing streams of data to calling APIs and integrating with other AWS services, ...]]></description><link>https://blog.paramako.com/running-rust-on-aws-lambda-part-1</link><guid isPermaLink="true">https://blog.paramako.com/running-rust-on-aws-lambda-part-1</guid><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Testing]]></category><category><![CDATA[SQS]]></category><dc:creator><![CDATA[Yurii]]></dc:creator><pubDate>Thu, 28 Jul 2022 10:52:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659005007692/gH8gB4PG87.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>AWS Lambda</strong> is a serverless computing service provided by <strong>Amazon Web Services</strong>.</p>
<p>The <strong>Lambda</strong> functions can perform any kind of computing task, from serving web pages and processing streams of data to calling APIs and integrating with other <strong>AWS</strong> services, like <strong>SQS</strong>, <strong>Kinesis</strong> etc.</p>
<p>In case of this article, we will create <a target="_blank" href="https://aws.amazon.com/sqs/">SQS</a> consumer, running on <strong>AWS lambda</strong>.</p>
<p><strong>SQS</strong> stands for <strong>Simple Queue Service</strong>, which means a web service that gives you access to a message queue that can be used to store messages while waiting for a computer to process them.</p>
<p><strong>SQS</strong> can be used as a classic pub/sub queue solution, and it can support the<strong> First In First Out</strong> principle if needed.</p>
<p>More about <strong>SQS</strong> you can find on <a target="_blank" href="https://aws.amazon.com/sqs/">official amazon pages</a>.</p>
<h2 id="heading-how-to-create-a-lambda-code">How to create a lambda code</h2>
<p>Cargo gives us a beautiful helper command to deal with <strong>Rust</strong> and <strong>AWS Lambda</strong>, called <a target="_blank" href="https://github.com/cargo-lambda/cargo-lambda">cargo-lamda</a>.</p>
<p>We need to install it by running <code>cargo install cargo-lambda</code>.</p>
<p>After that let's create our first lambda project with <code>cargo lambda new rust-lambda-example</code>.</p>
<p>After running this command, you need to answer a few questions to help <strong>cargo-lambda</strong> create the needed template. </p>
<p>As I mentioned earlier, our goal is to create an <strong>SQS</strong> consumer (a <strong>rust lambda</strong> that is triggered by <strong>SQS</strong> events), so your answers should be like:</p>
<pre><code class="lang-bash">cargo lambda new rust-lambda-example
? Is this <span class="hljs-keyword">function</span> an HTTP <span class="hljs-keyword">function</span>? No
? AWS Event <span class="hljs-built_in">type</span> that this <span class="hljs-keyword">function</span> receives sqs::SqsEvent
</code></pre>
<p>Let's take a look at new template!</p>
<p>Your new template should look something like the one below.</p>
<p>I've removed all comments and annotations and some blocks of code to make the most basic example, so don't worry if your code might look a bit different.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> aws_lambda_events::event::sqs::SqsEvent;
<span class="hljs-keyword">use</span> lambda_runtime::{run, service_fn, Error, LambdaEvent};

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">function_handler</span></span>(event: LambdaEvent&lt;SqsEvent&gt;) -&gt; <span class="hljs-built_in">Result</span>&lt;(), Error&gt; {
    <span class="hljs-literal">Ok</span>(())
}

<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>() -&gt; <span class="hljs-built_in">Result</span>&lt;(), Error&gt; {
    run(service_fn(function_handler)).<span class="hljs-keyword">await</span>
}
</code></pre>
<p><strong>function_handler</strong> is a function that will handle every event, that's a "heart" of our future lambda.</p>
<p>You can easily pass additional parameters to your <strong>function_handler</strong> function by changing the code 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">function_handler</span></span>(
    event: LambdaEvent&lt;SqsEvent&gt;,
    conn: &amp;SomeConnection,
) -&gt; <span class="hljs-built_in">Result</span>&lt;(), Error&gt; {
    <span class="hljs-literal">Ok</span>(())
}

<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>() -&gt; <span class="hljs-built_in">Result</span>&lt;(), Error&gt; {
    <span class="hljs-keyword">let</span> conn = SomeConnection {}; <span class="hljs-comment">// an abstract example, replace it with the real one if needed</span>

    run(service_fn(|event: LambdaEvent&lt;SqsEvent&gt;| {
        function_handler(event, &amp;conn)
    }))
    .<span class="hljs-keyword">await</span>
}
</code></pre>
<p>Let's have a quick look at our dependencies in <strong>Cargo.toml</strong></p>
<pre><code>[dependencies]
aws_lambda_events <span class="hljs-operator">=</span> { version <span class="hljs-operator">=</span> <span class="hljs-string">"0.6.3"</span>, default<span class="hljs-operator">-</span>features <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>, features <span class="hljs-operator">=</span> [<span class="hljs-string">"sqs"</span>] }
lambda_runtime <span class="hljs-operator">=</span> <span class="hljs-string">"0.6.0"</span>
tokio <span class="hljs-operator">=</span> { version <span class="hljs-operator">=</span> <span class="hljs-string">"1"</span>, features <span class="hljs-operator">=</span> [<span class="hljs-string">"macros"</span>] }
</code></pre><p>Here we see the <a target="_blank" href="https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/lambda-runtime">awslabs lambda runtime</a>, built on <a target="_blank" href="https://tokio.rs/">tokio runtime</a> and <a target="_blank" href="https://github.com/LegNeato/aws-lambda-events">aws_lambda_events</a> crate, which provides a collection of common <strong>AWS</strong> events structs.</p>
<p>Ok, let's teach our handler to print all SQS messages bodies, by adding simple code to our handler</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">function_handler</span></span>(event: LambdaEvent&lt;SqsEvent&gt;) -&gt; <span class="hljs-built_in">Result</span>&lt;(), Error&gt; {
    event
        .payload
        .records
        .into_iter()
        .filter_map(|m| m.body) <span class="hljs-comment">// since body is optional, we want to skip all None values</span>
        .for_each(|m| <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{m}"</span>));

    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<h2 id="heading-how-to-test-it-locally">How to test it locally</h2>
<h3 id="heading-write-a-simple-test">Write a simple test</h3>
<p>First, let's add a new dependency, a well-known json library called <a target="_blank" href="https://github.com/serde-rs/json">serde-json</a>.
Add this line to our <strong>Cargo.toml</strong> dependencies block: <code>serde_json = "~1.0.59"</code>.</p>
<h4 id="heading-next-lets-create-some-test-dataset">Next. let's create some test dataset:</h4>
<ol>
<li>Create a "fixtures" folder</li>
<li>Create "example-sqs-event.json" file into this folder</li>
<li>Fill "example-sqs-event.json" file  with the data below<pre><code class="lang-json">{
 <span class="hljs-attr">"Records"</span>: [
   {
     <span class="hljs-attr">"messageId"</span> : <span class="hljs-string">"MessageID_1"</span>,
     <span class="hljs-attr">"receiptHandle"</span> : <span class="hljs-string">"MessageReceiptHandle"</span>,
     <span class="hljs-attr">"body"</span> : <span class="hljs-string">"Hello from message 1!"</span>,
     <span class="hljs-attr">"md5OfBody"</span> : <span class="hljs-string">"fce0ea8dd236ccb3ed9b37dae260836f"</span>,
     <span class="hljs-attr">"md5OfMessageAttributes"</span> : <span class="hljs-string">"582c92c5c5b6ac403040a4f3ab3115c9"</span>,
     <span class="hljs-attr">"eventSourceARN"</span>: <span class="hljs-string">"arn:aws:sqs:us-west-2:123456789012:SQSQueue"</span>,
     <span class="hljs-attr">"eventSource"</span>: <span class="hljs-string">"aws:sqs"</span>,
     <span class="hljs-attr">"awsRegion"</span>: <span class="hljs-string">"us-west-2"</span>,
     <span class="hljs-attr">"attributes"</span> : {
       <span class="hljs-attr">"ApproximateReceiveCount"</span> : <span class="hljs-string">"2"</span>,
       <span class="hljs-attr">"SentTimestamp"</span> : <span class="hljs-string">"1520621625029"</span>,
       <span class="hljs-attr">"SenderId"</span> : <span class="hljs-string">"AROAIWPX5BD2BHG722MW4:sender"</span>,
       <span class="hljs-attr">"ApproximateFirstReceiveTimestamp"</span> : <span class="hljs-string">"1520621634884"</span>
     },
     <span class="hljs-attr">"messageAttributes"</span> : {
       <span class="hljs-attr">"Attribute3"</span> : {
         <span class="hljs-attr">"binaryValue"</span> : <span class="hljs-string">"MTEwMA=="</span>,
         <span class="hljs-attr">"stringListValues"</span> : [<span class="hljs-string">"abc"</span>, <span class="hljs-string">"123"</span>],
         <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MA=="</span>, <span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
         <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Binary"</span>
       },
       <span class="hljs-attr">"Attribute2"</span> : {
         <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"123"</span>,
         <span class="hljs-attr">"stringListValues"</span> : [ ],
         <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
         <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Number"</span>
       },
       <span class="hljs-attr">"Attribute1"</span> : {
         <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"AttributeValue1"</span>,
         <span class="hljs-attr">"stringListValues"</span> : [ ],
         <span class="hljs-attr">"binaryListValues"</span> : [ ],
         <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"String"</span>
       }
     }
   },
   {
     <span class="hljs-attr">"messageId"</span> : <span class="hljs-string">"MessageID_2"</span>,
     <span class="hljs-attr">"receiptHandle"</span> : <span class="hljs-string">"MessageReceiptHandle"</span>,
     <span class="hljs-attr">"body"</span> : <span class="hljs-string">"Hello from message 2!"</span>,
     <span class="hljs-attr">"md5OfBody"</span> : <span class="hljs-string">"fce0ea8dd236ccb3ed9b37dae260836f"</span>,
     <span class="hljs-attr">"md5OfMessageAttributes"</span> : <span class="hljs-string">"582c92c5c5b6ac403040a4f3ab3115c9"</span>,
     <span class="hljs-attr">"eventSourceARN"</span>: <span class="hljs-string">"arn:aws:sqs:us-west-2:123456789012:SQSQueue"</span>,
     <span class="hljs-attr">"eventSource"</span>: <span class="hljs-string">"aws:sqs"</span>,
     <span class="hljs-attr">"awsRegion"</span>: <span class="hljs-string">"us-west-2"</span>,
     <span class="hljs-attr">"attributes"</span> : {
       <span class="hljs-attr">"ApproximateReceiveCount"</span> : <span class="hljs-string">"2"</span>,
       <span class="hljs-attr">"SentTimestamp"</span> : <span class="hljs-string">"1520621625029"</span>,
       <span class="hljs-attr">"SenderId"</span> : <span class="hljs-string">"AROAIWPX5BD2BHG722MW4:sender"</span>,
       <span class="hljs-attr">"ApproximateFirstReceiveTimestamp"</span> : <span class="hljs-string">"1520621634884"</span>
     },
     <span class="hljs-attr">"messageAttributes"</span> : {
       <span class="hljs-attr">"Attribute3"</span> : {
         <span class="hljs-attr">"binaryValue"</span> : <span class="hljs-string">"MTEwMA=="</span>,
         <span class="hljs-attr">"stringListValues"</span> : [<span class="hljs-string">"abc"</span>, <span class="hljs-string">"123"</span>],
         <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MA=="</span>, <span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
         <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Binary"</span>
       },
       <span class="hljs-attr">"Attribute2"</span> : {
         <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"123"</span>,
         <span class="hljs-attr">"stringListValues"</span> : [ ],
         <span class="hljs-attr">"binaryListValues"</span> : [<span class="hljs-string">"MQ=="</span>, <span class="hljs-string">"MA=="</span>],
         <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"Number"</span>
       },
       <span class="hljs-attr">"Attribute1"</span> : {
         <span class="hljs-attr">"stringValue"</span> : <span class="hljs-string">"AttributeValue1"</span>,
         <span class="hljs-attr">"stringListValues"</span> : [ ],
         <span class="hljs-attr">"binaryListValues"</span> : [ ],
         <span class="hljs-attr">"dataType"</span> : <span class="hljs-string">"String"</span>
       }
     }
   }
 ]
}
</code></pre>
So your project should look like
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659002555094/IJaoIxwYz.png" alt="image.png" /></li>
</ol>
<p>Now let's write a test!
Add this block of code to the end of your <strong>main</strong> file.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[cfg(test)]</span>
<span class="hljs-keyword">mod</span> tests {
    <span class="hljs-keyword">use</span> super::*;

    <span class="hljs-meta">#[tokio::test]</span>
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">test_function_handler</span></span>() {
        <span class="hljs-keyword">let</span> data = include_bytes!(<span class="hljs-string">"fixtures/example-sqs-event.json"</span>);
        <span class="hljs-keyword">let</span> parsed: SqsEvent = serde_json::from_slice(data).unwrap();
        <span class="hljs-keyword">let</span> context = lambda_runtime::Context::default();
        <span class="hljs-keyword">let</span> event = LambdaEvent::new(parsed, context);

        function_handler(event).<span class="hljs-keyword">await</span>.expect(<span class="hljs-string">"failed to handle event"</span>);
    }
}
</code></pre>
<p>After running the test, output should be:</p>
<pre><code class="lang-bash">running 1 <span class="hljs-built_in">test</span>
Hello from message 1!
Hello from message 2!
<span class="hljs-built_in">test</span> tests::test_function_handler ... ok
</code></pre>
<p>Great! Our handler is working as expected!</p>
<h3 id="heading-emulate">Emulate</h3>
<p><code>cargo lambda start</code> command emulates the <strong>AWS Lambda</strong> control plane API.</p>
<p>Run this command at the root of the project and you will see such output</p>
<pre><code class="lang-bash">INFO invoke server listening on 127.0.0.1:9000
</code></pre>
<p>Now while our lambda is working, let's try to send an event to it by running
<code>cargo lambda invoke rust-lambda-example --data-file src/fixtures/example-sqs-event.json</code> in a separate window.</p>
<p>After invoking lambda, the output should be updated by something like this</p>
<pre><code class="lang-bash"> INFO starting lambda <span class="hljs-keyword">function</span> <span class="hljs-keyword">function</span>=<span class="hljs-string">"rust-lambda-example"</span>
[Running <span class="hljs-string">'cargo run --bin rust-lambda-example'</span>]
   Compiling rust-lambda-example v0.1.0 ({your_path}/rust-lambda-example)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 2.37s
     Running `target/debug/rust-lambda-example`
Hello from message 1!
Hello from message 2!
</code></pre>
<p>Cool! That works.</p>
<h4 id="heading-aws-lambda-environment-variables">AWS lambda Environment variables</h4>
<p>Let's imagine that we need to use <strong>AWS lambda</strong> environment variables. How should we test it locally?</p>
<p>Easy! You just need to work with them like with classic Rust environment variables!</p>
<p>Let's update our <strong>main</strong> file with</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">main</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;(), Error&gt; {
    <span class="hljs-keyword">let</span> env_var = std::env::var(<span class="hljs-string">"MODE"</span>).expect(<span class="hljs-string">"Environment error"</span>);
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{env_var}"</span>);

    run(service_fn(function_handler)).<span class="hljs-keyword">await</span>
}
</code></pre>
<p>and then rerun our <strong>API emulation</strong> with <code>MODE=test cargo lambda start</code>.</p>
<p>Let's try to send an event again with <code>lambda invoke rust-lambda-example --data-file src/fixtures/example-sqs-event.json</code>.</p>
<p>The output will be</p>
<pre><code class="lang-bash">[Running <span class="hljs-string">'cargo run --bin rust-lambda-example'</span>]
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.02s
     Running `target/debug/rust-lambda-example`
<span class="hljs-built_in">test</span>
Hello from message 1!
Hello from message 2!
</code></pre>
<p>Not surprising, but it works!</p>
<p>The next step is to configure and run our code on <strong>AWS lambda</strong>, so let's move to the <a target="_blank" href="https://paramako.com/running-rust-on-aws-lambda-part-2">next article</a>.</p>
<p><strong>P.S.</strong> You can find a working example on my <a target="_blank" href="https://github.com/paramako-blog/rust-lambda-example">GitHub</a> repository :)</p>
]]></content:encoded></item><item><title><![CDATA[Async Rust: Few examples to get it right]]></title><description><![CDATA[Before we start, I hope you already know how to create a new rust project, add some dependencies and other basic stuff. If not, I recommend to read the Book first :)
OK, lets go!
In Rust to run code asynchronously you should start the block or functi...]]></description><link>https://blog.paramako.com/async-rust-few-examples-to-get-it-right</link><guid isPermaLink="true">https://blog.paramako.com/async-rust-few-examples-to-get-it-right</guid><category><![CDATA[Rust]]></category><category><![CDATA[asynchronous]]></category><category><![CDATA[async]]></category><category><![CDATA[Future]]></category><category><![CDATA[concurrency]]></category><dc:creator><![CDATA[Yurii]]></dc:creator><pubDate>Sat, 23 Apr 2022 12:29:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1650979832731/FjHWOTrMA.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before we start, I hope you already know how to create a new <strong>rust</strong> project, add some dependencies and other basic stuff. If not, I recommend to read the <a target="_blank" href="https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html">Book</a> first :)</p>
<p><strong>OK, lets go!</strong></p>
<p>In Rust to run code asynchronously you should start the block or function with <strong>async</strong> keyword. <strong>Async</strong> keyword transforms block of code into a state machine that implements a trait called <strong>Future</strong>. A <strong>future</strong> represents an asynchronous computation.
For 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">one</span></span>() -&gt; <span class="hljs-built_in">u32</span> {
   <span class="hljs-number">1</span>
}
</code></pre>
<p>is the same as</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">one</span></span>() -&gt; <span class="hljs-keyword">impl</span> Future&lt;Output=<span class="hljs-built_in">u32</span>&gt; { 
   <span class="hljs-keyword">async</span> { <span class="hljs-number">1</span> } 
}
</code></pre>
<p><strong>Async</strong> bodies are lazy: they do nothing until they are run. The most common way to run a <strong>Future</strong> is to <code>.await</code> it.
<code>.await</code> can be used inside an <strong>async</strong> function, otherwise you should use <em>thread-blocking</em> operations like <code>futures::executor::block_on</code> to run the <strong>future</strong>, but it is not important, since in this article we will work with <strong>async</strong> code only.</p>
<p>To allow <strong>async</strong> main function, you need to choose <strong>runtime</strong> for running our asynchronous program.
In this example i will use <a target="_blank" href="https://tokio.rs">Tokio runtime</a>.
So let`s start with adding this line to our <strong>Cargo.toml</strong> file into dependencies section.</p>
<pre><code>tokio <span class="hljs-operator">=</span> { version <span class="hljs-operator">=</span> <span class="hljs-string">"1.15.0"</span>, features <span class="hljs-operator">=</span> [<span class="hljs-string">"full"</span>] }
</code></pre><p>It is easy to make our main function <strong>async</strong> with <strong>tokio</strong>, we just need to mark function to be executed by selected runtime this way:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> tokio;

<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>() {}
</code></pre>
<p>Let`s write simple async function that we will use for future testing of our code</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">task</span></span>(name: &amp;<span class="hljs-built_in">str</span>, long: <span class="hljs-built_in">bool</span>) {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Executing {}"</span>, name);

    <span class="hljs-keyword">if</span> long {
        tokio::time::sleep(Duration::from_secs(<span class="hljs-number">1</span>)).<span class="hljs-keyword">await</span>;
    }

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{} executed"</span>, name);
}
</code></pre>
<p><strong>Name</strong> argument is needed here for user-friendly output of our program.</p>
<p><strong>Long</strong> argument stands for if the function gets blocked for a second during its execution.</p>
<p>Note that we will use <code>tokio::time::sleep</code> here instead of <code>std::thread::sleep</code> as <code>std::thread::sleep</code> is thread-blocking operation and will block all the thread instead of allowing other tasks to run if the future is currently unable to make progress.</p>
<p>Update main function with this code and then try to run it</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> tokio;
<span class="hljs-keyword">use</span> std::time::Duration;

<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>() {
    task(<span class="hljs-string">"Long Task 1"</span>, <span class="hljs-literal">true</span>).<span class="hljs-keyword">await</span>;
    task(<span class="hljs-string">"Short Task 1"</span>, <span class="hljs-literal">false</span>).<span class="hljs-keyword">await</span>;
    task(<span class="hljs-string">"Long Task 2"</span>, <span class="hljs-literal">true</span>).<span class="hljs-keyword">await</span>;
    task(<span class="hljs-string">"Short Task 2"</span>, <span class="hljs-literal">false</span>).<span class="hljs-keyword">await</span>;
}
</code></pre>
<p>As a result we will have such output:</p>
<pre><code>Executing <span class="hljs-built_in">Long</span> Task <span class="hljs-number">1</span>
<span class="hljs-built_in">Long</span> Task <span class="hljs-number">1</span> executed
Executing <span class="hljs-built_in">Short</span> Task <span class="hljs-number">1</span>
<span class="hljs-built_in">Short</span> Task <span class="hljs-number">1</span> executed
Executing <span class="hljs-built_in">Long</span> Task <span class="hljs-number">2</span>
<span class="hljs-built_in">Long</span> Task <span class="hljs-number">2</span> executed
Executing <span class="hljs-built_in">Short</span> Task <span class="hljs-number">2</span>
<span class="hljs-built_in">Short</span> Task <span class="hljs-number">2</span> executed
</code></pre><p>As you can see all tasks here were executed consistently, short tasks were waiting for a long ones to be executed. This is definitely not what we wanted.</p>
<p>Let`s improve our code to run the tasks concurrently. To achieve our goal, we need to add a new dependency to our <strong>Cargo.toml</strong> file.</p>
<p>Add this line to dependencies section:</p>
<pre><code><span class="hljs-attr">futures</span> = <span class="hljs-string">"0.3.5"</span>
</code></pre><p>The <strong>futures</strong> crate provides a number of core abstractions for writing asynchronous code.
In our case we will need <code>futures::future::join_all</code> functionality. <code>join_all</code> function creates a <strong>future</strong> which represents a collection of the outputs of the <strong>futures</strong> given.</p>
<p>The returned future will drive execution for all of its underlying <strong>futures</strong>, collecting the results into a destination <code>Vec&lt;T&gt;</code> in the same order as they were provided.</p>
<p>So lets rewrite our main function. Now we need to collect our tasks <strong>futures</strong> into <code>vector</code> and then execute them via <code>join_all</code> function.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> tokio;
<span class="hljs-keyword">use</span> std::time::Duration;
<span class="hljs-keyword">use</span> futures;

<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> <span class="hljs-keyword">mut</span> futures = <span class="hljs-built_in">Vec</span>::new();

    futures.push(task(<span class="hljs-string">"Long Task 1"</span>, <span class="hljs-literal">true</span>));
    futures.push(task(<span class="hljs-string">"Short Task 1"</span>, <span class="hljs-literal">false</span>));
    futures.push(task(<span class="hljs-string">"Long Task 2"</span>, <span class="hljs-literal">true</span>));
    futures.push(task(<span class="hljs-string">"Short Task 2"</span>, <span class="hljs-literal">false</span>));

    futures::future::join_all(futures).<span class="hljs-keyword">await</span>;
}
</code></pre>
<p>And if we run it, the output will be:</p>
<pre><code>Executing <span class="hljs-built_in">Long</span> Task <span class="hljs-number">1</span>
Executing <span class="hljs-built_in">Short</span> Task <span class="hljs-number">1</span>
<span class="hljs-built_in">Short</span> Task <span class="hljs-number">1</span> executed
Executing <span class="hljs-built_in">Long</span> Task <span class="hljs-number">2</span>
Executing <span class="hljs-built_in">Short</span> Task <span class="hljs-number">2</span>
<span class="hljs-built_in">Short</span> Task <span class="hljs-number">2</span> executed
<span class="hljs-built_in">Long</span> Task <span class="hljs-number">1</span> executed
<span class="hljs-built_in">Long</span> Task <span class="hljs-number">2</span> executed
</code></pre><p>As you can see, long blocked tasks yield to a small ones!</p>
<p>Our code works concurrently as we expected!</p>
<p>You can find all working examples on my <a target="_blank" href="https://github.com/paramako-blog/async-rust-examples">GitHub</a> repository :)</p>
]]></content:encoded></item></channel></rss>