<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: rust</title>
    <description>The latest articles tagged 'rust' on DEV Community.</description>
    <link>https://dev.to/t/rust</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tag/rust"/>
    <language>en</language>
    <item>
      <title>How I Built a Counter Program in Anchor and Learned to Trust My Tests</title>
      <dc:creator>Lymah</dc:creator>
      <pubDate>Sat, 20 Jun 2026 18:54:21 +0000</pubDate>
      <link>https://dev.to/lymah/how-i-built-a-counter-program-in-anchor-and-learned-to-trust-my-tests-1akg</link>
      <guid>https://dev.to/lymah/how-i-built-a-counter-program-in-anchor-and-learned-to-trust-my-tests-1akg</guid>
      <description>&lt;p&gt;I spent a week building a counter program in Anchor — the Rust framework&lt;br&gt;
for writing Solana programs. By the end I had two instructions, one&lt;br&gt;
authorization constraint, and a test suite I could actually trust. Here&lt;br&gt;
is what I built, how I tested it, and the moment I proved the tests&lt;br&gt;
were real.&lt;/p&gt;


&lt;h2&gt;
  
  
  Start Here: The Accounts Struct
&lt;/h2&gt;

&lt;p&gt;If you come from Web2, this is the part that looks the strangest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Accounts)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Initialize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(&lt;/span&gt;
        &lt;span class="nd"&gt;init,&lt;/span&gt;
        &lt;span class="nd"&gt;payer&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;authority,&lt;/span&gt;
        &lt;span class="nd"&gt;space&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;Counter::INIT_SPACE,&lt;/span&gt;
    &lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(mut)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Signer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;system_program&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a Web2 backend, your handler receives a request object and talks&lt;br&gt;
to a database. On Solana, there is no database; there are accounts.&lt;br&gt;
Every account your instruction needs to read or write must be declared&lt;br&gt;
upfront, before the handler runs. Anchor validates them before your&lt;br&gt;
code ever executes.&lt;/p&gt;

&lt;p&gt;Here is what each field does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;counter&lt;/code&gt;&lt;/strong&gt; — the account being created. The &lt;code&gt;init&lt;/code&gt; constraint
tells Anchor to make a CPI to the System Program, allocate
&lt;code&gt;8 + Counter::INIT_SPACE&lt;/code&gt; bytes, and fund it from &lt;code&gt;authority&lt;/code&gt;.
The &lt;code&gt;8&lt;/code&gt; is for the discriminator Anchor stamps on every account
so the program can later verify "this is mine."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;authority&lt;/code&gt;&lt;/strong&gt; — the wallet signing and paying for the transaction.
&lt;code&gt;mut&lt;/code&gt; because its SOL balance is decreasing to fund the new account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;system_program&lt;/code&gt;&lt;/strong&gt; — required any time you create accounts.
Anchor checks that the address matches the real System Program.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The accounts struct is the schema. The handler is the logic.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Handlers
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.accounts.counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="py"&gt;.authority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.accounts.authority&lt;/span&gt;&lt;span class="nf"&gt;.key&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;ctx.accounts&lt;/code&gt; gives you typed access to every account declared in&lt;br&gt;
the struct. The handler is short because Anchor already did the hard&lt;br&gt;
work: allocating the account, checking the signer, paying the rent.&lt;br&gt;
Your code just sets the initial values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.accounts.counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt;
        &lt;span class="nf"&gt;.checked_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.ok_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ArithmeticOverflow&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The accounts struct for &lt;code&gt;increment&lt;/code&gt; has a constraint worth paying&lt;br&gt;
attention to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Accounts)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Increment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(mut,&lt;/span&gt; &lt;span class="nd"&gt;has_one&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;authority)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Signer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;has_one = authority&lt;/code&gt; tells Anchor: before this handler runs, check&lt;br&gt;
that &lt;code&gt;counter.authority == authority.key()&lt;/code&gt;. If the wallet signing&lt;br&gt;
the transaction does not match the wallet stored on the counter,&lt;br&gt;
the transaction is rejected. My handler never sees a bad caller —&lt;br&gt;
the constraint rejects them first.&lt;/p&gt;

&lt;p&gt;This is the Solana equivalent of a 403 check, but it is declarative&lt;br&gt;
and enforced by the runtime. There is no application layer to&lt;br&gt;
accidentally bypass.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tests
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://github.com/LiteSVM/litesvm" rel="noopener noreferrer"&gt;LiteSVM&lt;/a&gt; — an in-process&lt;br&gt;
Solana VM that runs your compiled program against a fresh ledger in&lt;br&gt;
milliseconds. No devnet, no flakiness, no airdrop required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Happy path
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;initialize_then_increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;svm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LiteSVM&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// ... load program, airdrop, create keypairs ...&lt;/span&gt;

    &lt;span class="n"&gt;svm&lt;/span&gt;&lt;span class="nf"&gt;.send_transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init_tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;svm&lt;/span&gt;&lt;span class="nf"&gt;.send_transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inc_tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;svm&lt;/span&gt;&lt;span class="nf"&gt;.get_account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;counter_kp&lt;/span&gt;&lt;span class="nf"&gt;.pubkey&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="py"&gt;.data&lt;/span&gt;&lt;span class="nf"&gt;.as_slice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="py"&gt;.authority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authority&lt;/span&gt;&lt;span class="nf"&gt;.pubkey&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test would fail if &lt;code&gt;increment&lt;/code&gt; stored the wrong number, or if&lt;br&gt;
&lt;code&gt;initialize&lt;/code&gt; set the wrong authority. It proves both instructions&lt;br&gt;
work correctly together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure path
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;increment_fails_when_wrong_authority_signs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// authority_a creates the counter&lt;/span&gt;
    &lt;span class="n"&gt;svm&lt;/span&gt;&lt;span class="nf"&gt;.send_transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init_tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"initialize should succeed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// authority_b tries to increment it&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bad_tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_increment_tx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;svm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;program_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;authority_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="nf"&gt;.pubkey&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;svm&lt;/span&gt;&lt;span class="nf"&gt;.send_transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bad_tx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="nf"&gt;.is_err&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="s"&gt;"increment should fail when signed by the wrong authority"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test would fail if I removed or weakened the &lt;code&gt;has_one = authority&lt;/code&gt;&lt;br&gt;
constraint. It proves the gate is real, not just assumed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Experiment That Made the Tests Real
&lt;/h2&gt;

&lt;p&gt;A passing test suite is a story. The question is whether it tells the&lt;br&gt;
truth.&lt;/p&gt;

&lt;p&gt;On the last day of the week I planted bugs on purpose, one at a time,&lt;br&gt;
and watched the suite catch them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The most instructive experiment:&lt;/strong&gt; I changed &lt;code&gt;checked_add(1)&lt;/code&gt; to&lt;br&gt;
&lt;code&gt;checked_add(2)&lt;/code&gt; in the increment handler. The transaction still&lt;br&gt;
succeeded — no error, no panic. But the stored value was wrong.&lt;/p&gt;

&lt;p&gt;The test output:&lt;br&gt;
test initialize_then_increment ... FAILED&lt;br&gt;
thread panicked at:&lt;/p&gt;

&lt;p&gt;assertion &lt;code&gt;left == right&lt;/code&gt; failed&lt;br&gt;
left: 1&lt;br&gt;
right: 2&lt;/p&gt;

&lt;p&gt;One character change in production code. One specific failure with a&lt;br&gt;
specific line number pointing exactly at the assertion that caught it.&lt;br&gt;
That is what assertions are for.&lt;/p&gt;

&lt;p&gt;Then I removed the &lt;code&gt;has_one = authority&lt;/code&gt; constraint entirely. The&lt;br&gt;
happy-path test stayed green — it uses the correct authority. But:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;test increment_fails_when_wrong_authority_signs ... FAILED&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;increment should fail when signed by the wrong authority&lt;/p&gt;

&lt;p&gt;The wrong-signer transaction now succeeded, and the test that expected&lt;br&gt;
a rejection panicked. Without that failure test, I would have silently&lt;br&gt;
shipped a program that lets anyone increment anyone else's counter.&lt;br&gt;
The negative test is the only reason I would have known.&lt;/p&gt;

&lt;p&gt;Both times I put the code back, ran the suite, and got green. The&lt;br&gt;
suite told the truth both times.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Would Build Next
&lt;/h2&gt;

&lt;p&gt;The counter account in this program lives at a random keypair's&lt;br&gt;
address. That means the client has to remember which keypair holds&lt;br&gt;
which user's counter — messy in practice. The natural next step is&lt;br&gt;
&lt;strong&gt;Program Derived Addresses (PDAs)&lt;/strong&gt;: deterministic addresses derived&lt;br&gt;
from the user's wallet and a seed string, so any client can find any&lt;br&gt;
user's counter without storing a keypair.&lt;/p&gt;

&lt;p&gt;After that: a &lt;code&gt;decrement&lt;/code&gt; instruction, a &lt;code&gt;reset&lt;/code&gt; instruction, and&lt;br&gt;
then connecting the program to a TypeScript client so it can run&lt;br&gt;
on devnet with a real wallet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.anchor-lang.com/" rel="noopener noreferrer"&gt;Anchor framework&lt;/a&gt; — the framework
used throughout&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.anchor-lang.com/docs/account-constraints" rel="noopener noreferrer"&gt;Anchor account constraints reference&lt;/a&gt;
— full list of constraints including &lt;code&gt;has_one&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;mut&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/LiteSVM/litesvm" rel="noopener noreferrer"&gt;LiteSVM&lt;/a&gt; — the in-process
test harness&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://solana.com/docs" rel="noopener noreferrer"&gt;Solana docs&lt;/a&gt; — accounts model primer&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This post is part of *&lt;/em&gt;#100DaysOfSolana*&lt;em&gt;. Building on Solana every&lt;br&gt;
day — follow along or jump in any time.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>solana</category>
      <category>rust</category>
      <category>anchor</category>
      <category>100daysofsolana</category>
    </item>
    <item>
      <title>I built a self-hosted DPI-resistant tunnel over TLS + WebSocket in Rust</title>
      <dc:creator>Илья Федотов</dc:creator>
      <pubDate>Sat, 20 Jun 2026 14:32:32 +0000</pubDate>
      <link>https://dev.to/__bf699f275acc/i-built-a-self-hosted-dpi-resistant-tunnel-over-tls-websocket-in-rust-3abd</link>
      <guid>https://dev.to/__bf699f275acc/i-built-a-self-hosted-dpi-resistant-tunnel-over-tls-websocket-in-rust-3abd</guid>
      <description>&lt;p&gt;I built &lt;strong&gt;BibaVPN&lt;/strong&gt; for one reason: I did not want to hand traffic to a third-party VPN provider.&lt;/p&gt;

&lt;p&gt;It is a self-hosted &lt;strong&gt;SOCKS5 / HTTP CONNECT&lt;/strong&gt; tunnel over &lt;strong&gt;TLS + WebSocket&lt;/strong&gt;, with a &lt;strong&gt;Rust&lt;/strong&gt; core and &lt;strong&gt;Android/Desktop&lt;/strong&gt; clients.&lt;/p&gt;

&lt;p&gt;Some users in &lt;strong&gt;Russia, Iran, and China&lt;/strong&gt; use it to get around network blocks through their own VPS.&lt;/p&gt;

&lt;p&gt;The project is small on purpose. It is not trying to be a full private network stack. It is meant for private, self-hosted access in restrictive environments.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Eljaja/BibaVPN" rel="noopener noreferrer"&gt;https://github.com/Eljaja/BibaVPN&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>dpi</category>
      <category>security</category>
    </item>
    <item>
      <title>Web Developer Travis McCracken on Handling Failures Gracefully in Backend Systems</title>
      <dc:creator>Travis McCracken Web Developer</dc:creator>
      <pubDate>Sat, 20 Jun 2026 13:23:29 +0000</pubDate>
      <link>https://dev.to/travis-mccracken-dev/web-developer-travis-mccracken-on-handling-failures-gracefully-in-backend-systems-23m2</link>
      <guid>https://dev.to/travis-mccracken-dev/web-developer-travis-mccracken-on-handling-failures-gracefully-in-backend-systems-23m2</guid>
      <description>&lt;p&gt;Unlocking the Power of Backend Development with Rust and Go: Insights from Web Developer Travis McCracken&lt;/p&gt;

&lt;p&gt;As a dedicated Web Developer focused on backend technologies, I’ve spent the past few years exploring the nuances and advantages of programming languages like Rust and Go. These languages have transformed how we build fast, reliable, and scalable APIs, and I’m passionate about sharing insights, trends, and the potential they hold for modern backend development.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Rise of Rust and Go in Backend Development
&lt;/h3&gt;

&lt;p&gt;Rust and Go have become household names among backend developers for their performance, safety, and concurrency features. Rust, with its focus on memory safety without a garbage collector, is ideal for building high-performance servers and APIs where efficiency is critical. Meanwhile, Go’s simplicity and built-in concurrency support make it a favorite for rapidly developing scalable cloud services.&lt;/p&gt;

&lt;p&gt;From my experience, ecosystems around these languages are blossoming, with innovative projects and tools emerging constantly. For instance, I recently worked extensively on a project I jokingly dubbed &lt;strong&gt;‘rust-cache-server’&lt;/strong&gt;—a fictional but representative high-performance caching server built with Rust. Its design leverages Rust’s zero-cost abstractions to maximize throughput while ensuring thread safety. The project illustrated how Rust can be a game-changer for latency-sensitive backend components.&lt;/p&gt;

&lt;p&gt;On the Go side, I developed a prototype API called &lt;strong&gt;‘fastjson-api’&lt;/strong&gt;, which demonstrated how efficiently Go handles JSON processing and concurrent API requests. Its lightweight nature and ease of deployment made it a go-to choice for building microservices that demand rapid response times and high throughput.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Benefits of Rust and Go for APIs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rust&lt;/strong&gt; excels in scenarios where safety, zero-cost abstractions, and raw speed matter. Its ownership model eliminates many classes of bugs at compile time, leading to more reliable APIs. Additionally, projects like &lt;strong&gt;‘rust-cache-server’&lt;/strong&gt; show Rust’s capability to handle heavy loads with minimal resource consumption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go&lt;/strong&gt;, on the other hand, is renowned for its simplicity and ease of use. The language’s built-in goroutines allow developers to create highly concurrent systems with less code and complexity. This makes &lt;strong&gt;‘fastjson-api’&lt;/strong&gt; not only performant but also easy to maintain and extend. The standard library’s robust support for networking and HTTP makes API development straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Implementation and Trends
&lt;/h3&gt;

&lt;p&gt;In my projects, combining Rust and Go has often led to hybrid architecture solutions, where critical backend services are written in Rust for performance, while orchestration and less performance-critical components are built with Go for speed of development.&lt;/p&gt;

&lt;p&gt;For example, a recent project involved a Rust-based microservice for real-time data processing, linked with a Go-powered API gateway that manages authentication, logging, and routing. This approach leverages each language’s strengths and provides an optimized backend ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Future Directions and Challenges
&lt;/h3&gt;

&lt;p&gt;One challenge with adopting Rust and Go at scale is the learning curve and tooling maturity. While both languages have matured significantly, integrating them into existing systems requires thoughtful planning. Additionally, open-source projects like &lt;strong&gt;‘fastjson-api’&lt;/strong&gt; and &lt;strong&gt;‘rust-cache-server’&lt;/strong&gt;—though fictional—serve as inspiration for developers to experiment and innovate.&lt;/p&gt;

&lt;p&gt;The evolution of these languages suggests a future where backend systems are more performant, safer, and easier to scale. Continuous improvements in their ecosystems, such as advanced package managers, frameworks, and deployment tools, will make it even easier for developers to leverage Rust and Go for API development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;As someone passionate about backend development, I believe Rust and Go represent two sides of the same coin—with each bringing unique advantages to the table. Whether you’re optimizing performance-critical components or building scalable, maintainable APIs, these languages are worth mastering.&lt;/p&gt;

&lt;p&gt;If you’re interested in exploring my work related to backend development, feel free to check out my profiles for more insights, projects, and tutorials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/travis-mccracken-dev" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@travis.mccracken.dev" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/travis-mccracken-dev"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/travis-mccracken-web-developer-844b94373/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Embrace the power of Rust and Go, and transform your backend systems into high-performance, reliable services that stand the test of time. Happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>backend</category>
      <category>rust</category>
      <category>apidevelopment</category>
    </item>
    <item>
      <title>Building an Enterprise Hybrid AI Shield: Remote OTA, Kernel Process Isolation, ChaCha20 FIM, and eBPF Distributed Mesh (Rust + C++)</title>
      <dc:creator>nikhilsharma987880-bot</dc:creator>
      <pubDate>Sat, 20 Jun 2026 12:54:04 +0000</pubDate>
      <link>https://dev.to/nikhilsharma987880bot/building-an-enterprise-hybrid-ai-shield-remote-ota-kernel-process-isolation-chacha20-fim-and-28k5</link>
      <guid>https://dev.to/nikhilsharma987880bot/building-an-enterprise-hybrid-ai-shield-remote-ota-kernel-process-isolation-chacha20-fim-and-28k5</guid>
      <description>&lt;h1&gt;
  
  
  Moving Beyond Static Firewalls: Elevating Cyber Aura to an Enterprise Distributed EDR Suite
&lt;/h1&gt;

&lt;p&gt;A few days ago, I designed a Hybrid Rust + C++ log parser with a self-modifying AI mutation engine. But threat landscapes evolve in milliseconds. Today, I upgraded the entire architecture to handle internal breaches, cloud-managed defenses, and multi-server orchestration without requiring a single system reboot.&lt;/p&gt;

&lt;p&gt;Here is how the newly integrated enterprise architecture works under the hood:&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ The Core Architectural Upgrades
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Zero-Downtime Remote OTA Update Engine &amp;amp; Process Killer (C++ Layer)
&lt;/h3&gt;

&lt;p&gt;Spawning a detached background thread using std::thread, the system periodically fetches the latest signatures (aura_rules.conf) and hot-reloads them directly into RAM. If an internal attacker tries to compromise critical fields, the Rust core intercepts the anomaly, tracks the *Process ID (PID), and calls a low-level C++ FFI hook to trigger kill(pid, SIGKILL) instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Military-Grade ChaCha20 File Integrity Monitor (FIM)
&lt;/h3&gt;

&lt;p&gt;Moving beyond basic monitoring, I hooked the system into the Linux inotify subsystem via Rust. If an unauthorized process attempts to modify production infrastructure (like /var/www/html/index.php or configurations), the engine intercepts it in real-time and automatically executes an **in-place ChaCha20 lockdown. Critical files are immediately encrypted and rendered completely unreadable until the master key is supplied.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Kernel-Level Packet Dropping via eBPF (XDP)
&lt;/h3&gt;

&lt;p&gt;To achieve zero CPU overhead bypass defense, the ecosystem now features *&lt;em&gt;eBPF (Extended Berkeley Packet Filter)&lt;/em&gt; integration. Instead of waiting for logs to be written to disk, we inject bytecode directly into the Linux Kernel network interface layer using XDP (eXpress Data Path). When the AI engine detects an aggressive attack vector, it updates the eBPF maps in real-time, dropping malicious packets natively inside the kernel before they even reach the user-space network stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Distributed Mesh Agent Network (Master-Worker Architecture)
&lt;/h3&gt;

&lt;p&gt;Enterprise networks span across hundreds of nodes. I implemented an asynchronous TCP communication grid (network_mesh) in Rust.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;AURA Master Node:&lt;/em&gt; Acts as a centralized command hub.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;AURA Worker Agents:&lt;/em&gt; Deployable across hundreds of production servers to sniff local activities.
If a single worker agent detects a zero-day intrusion on its server, it coordinates via the mesh to dynamically push blocklists to all other 99+ servers in the cluster instantly, neutralizing the threat globally.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 The Ultimate Tactical Impact
&lt;/h2&gt;

&lt;p&gt;With these additions, Cyber Aura has evolved into a fully autonomous, self-healing &lt;em&gt;Endpoint Detection and Response (EDR)&lt;/em&gt; suite:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Global Swarm Defense:&lt;/em&gt; Attack one server, and the entire infrastructure hardens its perimeter within microseconds.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Pre-Log Interception:&lt;/em&gt; Malicious traffic is eliminated inside the kernel layer via eBPF.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Cryptographic Self-Defense:&lt;/em&gt; Automated ChaCha20 file lockdown stops data exfiltration in its tracks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;👉 &lt;em&gt;Check out the fully modular repository:&lt;/em&gt; &lt;a href="https://github.com/nikhilsharma987880-bot/hybrid_log_parser/tree/main" rel="noopener noreferrer"&gt;https://github.com/nikhilsharma987880-bot/hybrid_log_parser/tree/main&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Credit:&lt;/strong&gt; Nikhil Sharma (Cyber Aura)&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cpp</category>
      <category>cybersecurity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Elixir 1.20 has a type system now: comparing it with Rust and TypeScript</title>
      <dc:creator>GeekMasahiro</dc:creator>
      <pubDate>Sat, 20 Jun 2026 12:12:16 +0000</pubDate>
      <link>https://dev.to/geekmasahiro/elixir-120-has-a-type-system-now-comparing-it-with-rust-and-typescript-31p4</link>
      <guid>https://dev.to/geekmasahiro/elixir-120-has-a-type-system-now-comparing-it-with-rust-and-typescript-31p4</guid>
      <description>&lt;p&gt;&lt;em&gt;This English version is an AI translation of &lt;a href="https://qiita.com/GeekMasahiro/items/3f8e66db661f8a2f97a5" rel="noopener noreferrer"&gt;my original article on Qiita (in Japanese)&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About this article
&lt;/h2&gt;

&lt;p&gt;On June 3, 2026, Elixir 1.20 shipped with a type system. But it aims at something a little different from the type systems we are used to, the ones where you write types to buy safety.&lt;/p&gt;

&lt;p&gt;This article started from my own questions, which I worked through with an AI agent. We went to primary sources (the official blog, the docs, the paper), and in the end I installed Elixir 1.20 and checked how the type checker actually behaves. I may still have gotten things wrong, so if you notice anything, I would be glad to hear it in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the type system aims for: soundness
&lt;/h2&gt;

&lt;p&gt;First, the word &lt;strong&gt;sound&lt;/strong&gt;. In type systems, a type system is &lt;em&gt;sound&lt;/em&gt; when, if it says a value has some type, you will not get a type error of that kind at runtime. The opposite, &lt;em&gt;unsound&lt;/em&gt;, means a program can type-check and still hit a type error when it runs.&lt;/p&gt;

&lt;p&gt;Making a dynamic language fully sound is hard. TypeScript openly states that it is &lt;strong&gt;not&lt;/strong&gt; sound (it lists "apply a sound or 'provably correct' type system" as a non-goal). Elixir, on the other hand, lists soundness as one of the goals of its type system. But it too admits it is best-effort ("we do not guarantee we will find every mistake"), so it does not claim to be fully sound either. Both projects talk about their type systems in terms of sound and unsound, so I will use the same words here.&lt;/p&gt;

&lt;p&gt;There is room for different stances on how far, and how, to pursue soundness. The key question is &lt;strong&gt;how each one treats things it cannot be sure about&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Sound?&lt;/th&gt;
&lt;th&gt;Unknowns are...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rust&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;sound (strong)&lt;/td&gt;
&lt;td&gt;rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Elixir&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;sound (best-effort)&lt;/td&gt;
&lt;td&gt;passed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unsound&lt;/td&gt;
&lt;td&gt;passed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Rust&lt;/strong&gt; rejects what it cannot be sure about. Because it refuses to let those through, it is strongly sound about types and ownership. (The &lt;code&gt;unsafe&lt;/code&gt; parts, and runtime errors like out-of-bounds array access, are outside that guarantee.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript&lt;/strong&gt; and &lt;strong&gt;Elixir&lt;/strong&gt; both let unknowns through in the end. The difference is what happens before that. TypeScript is designed around writing types as much as you can, and where type information is missing (an &lt;code&gt;any&lt;/code&gt;, or something made unknown by an &lt;code&gt;as&lt;/code&gt; cast) it treats that as out of scope and lets it through without checking. Elixir, before letting a value through, traces the flow of the code (branches and guards) to work out the possible types, and rejects only what it can prove will always fail. Same "letting it through," but the question is &lt;strong&gt;whether it looks first&lt;/strong&gt;. That difference is what separates unsound (TypeScript) from sound (Elixir).&lt;/p&gt;

&lt;h2&gt;
  
  
  Elixir 1.20's type system
&lt;/h2&gt;

&lt;p&gt;Three things stand out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;dynamic()&lt;/code&gt; defers the judgment.&lt;/strong&gt; Where type information is missing, TypeScript passes it without checking (by design: it assumes you write types, and treats what you did not as out of scope). Elixir instead assigns the unknown spot a type that literally means "unknown" (&lt;code&gt;dynamic()&lt;/code&gt;) and holds off. As that value flows through the code it gets narrowed, and Elixir reports only the spots where every possible value is certain to fail. Where only some paths might fail, it stays quiet. It is built to say only what it is sure of, and to avoid false positives. If something stays gray to the end it is missed (the project itself admits this best-effort limit), but whatever it does report is certain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. You can express negation in a type.&lt;/strong&gt; Elixir's types are built from set operations: union, intersection, and negation (set-theoretic types). So "not nil" is natural to write. TypeScript can also say "exclude this" via &lt;code&gt;Exclude&lt;/code&gt; and narrowing, but Elixir has negation as a type operation itself. That is the difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. It starts from writing no types.&lt;/strong&gt; For now, you do not write type annotations; the compiler infers types from the code and checks them. The point is to make it work on huge existing codebases without adding anything. Later, the plan is to let you write type signatures at the boundaries where you want stronger guarantees (per the official roadmap), and 1.20 is the "inference first" milestone on that path. Note that the long-standing &lt;code&gt;@spec&lt;/code&gt; is for documentation and Dialyzer; the new type system does not use it. The new type signatures are being designed as a separate thing.&lt;/p&gt;

&lt;p&gt;Once you can write types explicitly, guarantees should reach places inference cannot follow today (struct fields, boundaries across modules). But the team itself is cautious ("we still need to assess the impact on how it feels to write code" and "it may turn out the type system is not practical"), and it is still being evaluated. The future where you write types should be better, but the people building it are still feeling their way.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much it catches without a single type annotation (I ran it)
&lt;/h2&gt;

&lt;p&gt;I installed Elixir 1.20 and tried, without writing a single type, to see what it catches.&lt;/p&gt;

&lt;p&gt;For example, when every branch of a &lt;code&gt;case&lt;/code&gt; returns an atom, the result is inferred to be an atom, and things stop when you hand that to a function that works on strings. Elixir calls strings "binaries," so the warning says &lt;code&gt;binary()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;categorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:negative&lt;/span&gt;
      &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:zero&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:positive&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning: incompatible types given to String.length/1:
    given types:     dynamic(:negative or :positive or :zero)
    but expected one of:     binary()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also follows types that change midway through a pipeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# turn the integer into a string (Elixir calls strings "binaries")&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Kernel&lt;/span&gt;&lt;span class="o"&gt;.+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;# warns: trying to add an integer to a string (binary)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning: incompatible types given to Kernel.+/2:
    given types:     binary(), integer()
    but expected one of:     integer(), integer()   # and the other numeric combinations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neither has any type annotations. It bundles the three &lt;code&gt;case&lt;/code&gt; branches into &lt;code&gt;:negative or :positive or :zero&lt;/code&gt;, follows the type change through the pipe, and points at the single spot where every value is bound to fail.&lt;/p&gt;

&lt;p&gt;To be honest, I tried to build an example where &lt;strong&gt;TypeScript misses it but only Elixir catches it&lt;/strong&gt;, and I could not make one work. TypeScript catches type mismatches too, and unsound cases like out-of-bounds array access are missed by Elixir as well (best-effort). The difference is not the range of what can be caught; it is that &lt;strong&gt;it catches this without my writing a single type for the example&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushed further: wouldn't a statically typed language be enough?
&lt;/h2&gt;

&lt;p&gt;After running all this, a deeper question surfaced. If we have statically typed languages like Rust, then pushed to the limit, wouldn't those be enough? Why do dynamically typed languages need to exist at all? I wanted to find out, so I asked an AI agent. Here is the answer that came back.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;First, let me split the question a little. Rust's heaviness comes less from static types themselves and more from ownership and lifetimes (the machinery for memory safety without a GC). A statically typed language with a GC gets type inference too, so you barely write annotations. So the real divide is not "Rust or dynamic" but "static or dynamic," with GC'd static languages sitting in between.&lt;/p&gt;

&lt;p&gt;To be honest, the "static is enough" side has gotten stronger. Inference has narrowed the old "dynamic is faster to write" gap, and the trend of adding types to a dynamic language after the fact (TypeScript, Python, and now Elixir 1.20) is itself evidence that once code matters, people end up wanting static guarantees.&lt;/p&gt;

&lt;p&gt;Even so, there are two reasons dynamic types will not disappear in principle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A sound static type system must reject some programs that actually run correctly.&lt;/strong&gt; Whether a program "never hits a type error at runtime" is undecidable in general (&lt;a href="https://en.wikipedia.org/wiki/Rice%27s_theorem" rel="noopener noreferrer"&gt;Rice's theorem&lt;/a&gt;), so if you prioritize never letting an unsafe program through, the price is that some "actually runs, but cannot be proven, so it is rejected" code always remains. This is not a flaw you fix by improving the type system; it is a hard ceiling. The proof is that every static language has an escape hatch (Rust's &lt;code&gt;unsafe&lt;/code&gt;, the &lt;code&gt;Any&lt;/code&gt; or dynamic casts in various languages). They admit there is a part static cannot cover, and quietly bring dynamic typing back in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Some work has types that are only determined at runtime.&lt;/strong&gt; Messy data coming from outside, a REPL you poke at interactively, macros that generate code, hot code reloading that swaps modules while the system runs. All of these are dynamic by nature, and clash with the premise of "check the whole thing up front."&lt;/p&gt;

&lt;p&gt;In short, static and dynamic just differ in &lt;strong&gt;where you pay for type correctness&lt;/strong&gt;. Static pays up front, at compile time, for every possible execution. Dynamic pays later, at runtime, for the one execution that actually happened. Because there are situations where you cannot pay up front, or where paying up front is not worth it, dynamic typing is needed. And the real answer is not "one or the other" but is heading toward "keep a dynamic base, and add static where it pays."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Reading that answer, I came to understand Elixir 1.20's reason for being, and its position, a little better.&lt;/p&gt;

&lt;p&gt;Elixir is not trying to become Rust. It keeps a base you can run while still dynamic, statically stops only the certain mistakes, and plans to let you add types at the boundaries where you want guarantees later. It has chosen "a dynamic base, with static added where it pays" as a matter of language design.&lt;/p&gt;

&lt;p&gt;And this overlaps with the era of having AI write code. AI can write a lot, fast, but it does not get everything completely right. So the type system points out, at the compiler level, the mistakes that are certain to be found, and assists with the parts AI does not quite finish. Elixir 1.20's type system looks like one form of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://elixir-lang.org/blog/2026/06/03/elixir-v1-20-0-released/" rel="noopener noreferrer"&gt;Elixir v1.20 released: now a gradually typed language&lt;/a&gt; (official release blog)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hexdocs.pm/elixir/gradual-set-theoretic-types.html" rel="noopener noreferrer"&gt;Gradual set-theoretic types&lt;/a&gt; (official docs: the note on soundness, best-effort, and phasing out typespecs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hexdocs.pm/elixir/typespecs.html" rel="noopener noreferrer"&gt;Typespecs reference&lt;/a&gt; (&lt;code&gt;@spec&lt;/code&gt; is for documentation and Dialyzer)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://elixir-lang.org/blog/2026/01/09/type-inference-of-all-and-next-15/" rel="noopener noreferrer"&gt;Type inference of all constructs and the next 15 months&lt;/a&gt; (roadmap)&lt;/li&gt;
&lt;li&gt;Giuseppe Castagna, Guillaume Duboc, José Valim, &lt;a href="https://arxiv.org/pdf/2306.06391" rel="noopener noreferrer"&gt;"The Design Principles of the Elixir Type System"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals" rel="noopener noreferrer"&gt;TypeScript Design Goals&lt;/a&gt; (lists a sound type system as a non-goal)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elixir</category>
      <category>rust</category>
      <category>typescript</category>
      <category>types</category>
    </item>
    <item>
      <title>How I Built a Lightweight Rust Web Browser with Zero Coding Experience (Using Gemini &amp; Qwen)</title>
      <dc:creator>LocShadowVN</dc:creator>
      <pubDate>Sat, 20 Jun 2026 11:05:43 +0000</pubDate>
      <link>https://dev.to/locshadowvn/how-i-built-a-lightweight-rust-web-browser-with-zero-coding-experience-using-gemini-qwen-31j1</link>
      <guid>https://dev.to/locshadowvn/how-i-built-a-lightweight-rust-web-browser-with-zero-coding-experience-using-gemini-qwen-31j1</guid>
      <description>&lt;p&gt;Hey DEV community! 👋&lt;/p&gt;

&lt;p&gt;I wanted to share a personal experiment I've been working on recently. The catch? I have absolutely zero professional coding background. I just wanted to see how far a complete beginner could push current AI tools to build a real, functional desktop application from scratch.&lt;/p&gt;

&lt;p&gt;After weeks of prompting, configuring, and troubleshooting, here is the result: Nexus Browser — a secure, lightweight web browser built in Rust, featuring a Neon Cyberpunk GUI, a built-in ad blocker, and a multi-threaded download engine.&lt;/p&gt;

&lt;p&gt;🛠️ My AI Development Crew&lt;br&gt;
Since I couldn't write the code myself, I had to manage and coordinate three different AI assistants like a project manager:&lt;/p&gt;

&lt;p&gt;Google Gemini 🤖 – Acted as my software architect and system administrator. It helped me map out the project structure and, most importantly, guided me through complex environment setup errors (like handling tricky NixOS and Google IDX configuration issues when compiling libraries like webkit2gtk).&lt;/p&gt;

&lt;p&gt;Qwen Studio 💻 – Served as my primary backend developer. It generated, optimized, and compressed the Rust source code, and also helped craft the Cyberpunk-themed HTML/JS interface.&lt;/p&gt;

&lt;p&gt;Replit AI ☁️ – Provided a quick cloud environment to test and run my early prototypes before moving things locally.&lt;/p&gt;

&lt;p&gt;⚠️ Current Status: Lots of Bugs &amp;amp; The 4GB RAM Struggle!&lt;br&gt;
To be completely honest, the browser currently has a lot of bugs and internal issues. Since it was built entirely through AI prompts, some parts of the code are not fully optimized, and there are occasional crashes and weird UI rendering glitches. I am actively working with the AIs to debug, refactor the code, and fix these issues one by one.&lt;/p&gt;

&lt;p&gt;But here is the funniest part: I can't even properly test my own browser right now because my laptop only has 4GB of DDR3 RAM! 💀&lt;/p&gt;

&lt;p&gt;Every time I try to run a heavy compile or open too many preview windows, my poor laptop gasps for air and threatens to explode. So if you clone the repo and find a major bug, just know that my 4GB RAM setup was doing its absolute best to survive the compilation process!&lt;/p&gt;

&lt;p&gt;💡 Key Lessons I Learned Along the Way&lt;br&gt;
Modular Prompting is Everything: Asking an AI to "build a whole web browser" right away is a recipe for broken code. I had to break the project down into tiny, isolated pieces: first building a basic window, then adding the Cyberpunk UI styling, then injecting the ad blocker logic, and finally implementing the download manager.&lt;/p&gt;

&lt;p&gt;Environment Setup is the Real Boss: Writing code with AI is relatively fast, but setting up the correct compiler flags, managing dependencies, and making sure Rust plays nice with Linux graphics libraries took up a lot of time. Having Gemini double-check my build logs was a lifesaver.&lt;/p&gt;

&lt;p&gt;🚀 Check it out!&lt;br&gt;
I'm honestly amazed at what's possible today. A few years ago, building a custom Rust browser as a beginner would have felt impossible. Now, with the right AI collaboration, anyone can bring their ideas to life.&lt;/p&gt;

&lt;p&gt;If you are curious about the project, want to help me debug, or have some solid advice on how a beginner can optimize the Rust code further, please check out the repository!&lt;/p&gt;

&lt;p&gt;👉 GitHub Repository: &lt;a href="https://github.com/LocShadowVN/nexus-browser" rel="noopener noreferrer"&gt;https://github.com/LocShadowVN/nexus-browser&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you like this experiment and want to support a beginner developer struggling on a 4GB RAM machine, leaving a ⭐ on GitHub would mean the world to me!&lt;/p&gt;

&lt;p&gt;Thank you for reading! Let me know in the comments if you have any tips for debugging Rust apps with AI.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>rust</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Rust-Based Aurora Browser Engine Aims to Tackle Complex Web Apps Like YouTube Despite Technical Hurdles</title>
      <dc:creator>Sergey Boyarchuk</dc:creator>
      <pubDate>Sat, 20 Jun 2026 10:26:38 +0000</pubDate>
      <link>https://dev.to/serbyte/rust-based-aurora-browser-engine-aims-to-tackle-complex-web-apps-like-youtube-despite-technical-1g8k</link>
      <guid>https://dev.to/serbyte/rust-based-aurora-browser-engine-aims-to-tackle-complex-web-apps-like-youtube-despite-technical-1g8k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: The Aurora Project and the YouTube Challenge
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Aurora browser engine&lt;/strong&gt;, built from scratch in &lt;strong&gt;Rust&lt;/strong&gt;, represents a bold attempt to address the growing complexity of modern web applications. Its primary goal? Rendering &lt;strong&gt;YouTube&lt;/strong&gt;, a notoriously intricate &lt;strong&gt;Single Page Application (SPA)&lt;/strong&gt; that pushes browser engines to their limits. This challenge isn’t just about YouTube—it’s a litmus test for Aurora’s ability to handle the &lt;strong&gt;shadow DOM composition&lt;/strong&gt;, &lt;strong&gt;custom elements&lt;/strong&gt;, and &lt;strong&gt;extensive JavaScript&lt;/strong&gt; that define today’s web.&lt;/p&gt;

&lt;p&gt;At its core, Aurora integrates &lt;strong&gt;V8 for JavaScript execution&lt;/strong&gt;, &lt;strong&gt;Stylo (via blitz-dom) for CSS resolution&lt;/strong&gt;, and &lt;strong&gt;Vello for pixel painting&lt;/strong&gt;. These dependencies, while powerful, introduce their own constraints. For instance, Stylo’s &lt;strong&gt;style invalidation bugs&lt;/strong&gt;—like the panic triggered by elements lacking computed styles—can cascade into rendering failures. Rust’s &lt;strong&gt;memory safety guarantees&lt;/strong&gt; mitigate certain risks, such as &lt;strong&gt;double-parented nodes&lt;/strong&gt; (which caused YouTube’s cleanup logic to spin indefinitely), but they also complicate integration with external components.&lt;/p&gt;

&lt;p&gt;YouTube’s architecture, built on &lt;strong&gt;Polymer and ShadyDOM&lt;/strong&gt;, exacerbates these challenges. Its &lt;strong&gt;detached logical fragments&lt;/strong&gt; require precise &lt;strong&gt;shadow DOM composition&lt;/strong&gt; to ensure &lt;strong&gt;connected callbacks&lt;/strong&gt; fire correctly. Aurora’s initial failure to render the &lt;strong&gt;masthead logo&lt;/strong&gt; stemmed from this: fragments weren’t reattached to the connected tree, leaving the logo as a &lt;strong&gt;0x0 layout&lt;/strong&gt;. Fixing this required not just understanding ShadyDOM’s behavior but also rewriting Aurora’s &lt;strong&gt;parent validation code&lt;/strong&gt; to handle &lt;strong&gt;shadow roots&lt;/strong&gt; separately from the normal child list.&lt;/p&gt;

&lt;p&gt;The iterative nature of Aurora’s development is evident in its progress. Each fix—like resolving the &lt;strong&gt;Stylo panic&lt;/strong&gt; or correcting &lt;strong&gt;event propagation&lt;/strong&gt;—brings YouTube closer to full renderability. However, the process is fraught with &lt;strong&gt;edge cases&lt;/strong&gt;. For example, a &lt;strong&gt;blank video player&lt;/strong&gt; turned out to be a removed YouTube video, not an Aurora bug, highlighting the need for robust &lt;strong&gt;error handling&lt;/strong&gt; in complex systems.&lt;/p&gt;

&lt;p&gt;Aurora’s approach, centered on &lt;strong&gt;capability gating&lt;/strong&gt;, allows for modular development but introduces trade-offs. While leveraging V8 and Stylo accelerates progress, it ties Aurora to their release cycles and bugs. A fully custom implementation would offer greater control but at the cost of increased development time and complexity. The optimal choice depends on the &lt;strong&gt;priority of innovation versus stability&lt;/strong&gt;: if rapid iteration is key, external dependencies are preferable; if long-term control is critical, custom implementations are necessary.&lt;/p&gt;

&lt;p&gt;In summary, Aurora’s quest to render YouTube isn’t just a technical challenge—it’s a strategic one. Success would demonstrate Rust’s viability for browser engines and reduce reliance on dominant engines like Chromium. Failure, however, would underscore the risks of &lt;strong&gt;browser engine monoculture&lt;/strong&gt;, where innovation stalls and security vulnerabilities proliferate. As Aurora progresses, its lessons will shape the future of web rendering—one &lt;strong&gt;paint path&lt;/strong&gt; at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Hurdles: Deconstructing YouTube’s Complexity
&lt;/h2&gt;

&lt;p&gt;Rendering YouTube in Aurora isn’t just a test of browser engine capability—it’s a stress test of modern web technologies pushed to their limits. YouTube’s architecture as a &lt;strong&gt;Single Page Application (SPA)&lt;/strong&gt; built on &lt;strong&gt;Polymer&lt;/strong&gt; and &lt;strong&gt;ShadyDOM&lt;/strong&gt; introduces a cascade of technical challenges. These aren’t theoretical problems; they’re mechanical failures in the DOM tree, JavaScript execution, and rendering pipeline that manifest as missing elements, infinite loops, or crashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shadow DOM Composition: The Silent Killer of Rendering
&lt;/h3&gt;

&lt;p&gt;YouTube’s reliance on &lt;strong&gt;shadow DOM&lt;/strong&gt; for encapsulation creates a critical bottleneck. Polymer stamps content into &lt;strong&gt;detached logical fragments&lt;/strong&gt;, which must be reattached to the connected tree for &lt;strong&gt;connected callbacks&lt;/strong&gt; to fire. Aurora’s initial failure with the masthead logo—rendering as &lt;strong&gt;0x0&lt;/strong&gt;—was caused by improper composition of these fragments. The &lt;em&gt;impact&lt;/em&gt; was twofold: connected callbacks never fired, and the logo remained unrendered. The &lt;em&gt;mechanism&lt;/em&gt; was a flaw in Aurora’s parent validation code, which treated shadow roots as stale and disconnected them from their hosts. &lt;em&gt;Fixing this required rewriting the validation logic to handle shadow roots separately&lt;/em&gt;, ensuring fragments were correctly reattached. &lt;strong&gt;Rule: If shadow DOM elements fail to render, verify fragment reattachment and callback firing in the composition pipeline.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Stylo Panics: When Style Invalidation Breaks the Engine
&lt;/h3&gt;

&lt;p&gt;Aurora’s dependency on &lt;strong&gt;Stylo&lt;/strong&gt; for CSS resolution introduces a failure mode tied to &lt;strong&gt;style invalidation&lt;/strong&gt;. When an element lacks computed styles, Stylo panics, halting rendering. This isn’t a theoretical edge case—it’s a recurring blocker in YouTube’s feed, where dynamic style updates trigger invalidation. The &lt;em&gt;mechanism&lt;/em&gt; is a bug in Stylo’s handling of unstyled elements, already fixed upstream but not yet released. &lt;em&gt;Aurora’s workaround is to fail gracefully&lt;/em&gt;, but this is a temporary patch. &lt;strong&gt;Rule: For Stylo-dependent engines, prioritize upstream fixes for style invalidation bugs, as they cascade into rendering failures.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Elements and Event Propagation: The Hidden Glue
&lt;/h3&gt;

&lt;p&gt;YouTube’s use of &lt;strong&gt;custom elements&lt;/strong&gt; and &lt;strong&gt;mutation observers&lt;/strong&gt; exposes gaps in Aurora’s implementation. Initially, custom elements failed to upgrade correctly, and events didn’t propagate, causing interactive elements to malfunction. The &lt;em&gt;mechanism&lt;/em&gt; was incomplete lifecycle management for custom elements and missing event handlers in the DOM tree. &lt;em&gt;Fixing this required aligning Aurora’s implementation with browser standards&lt;/em&gt;, ensuring elements defined and upgraded correctly. &lt;strong&gt;Rule: If custom elements or events break, audit lifecycle hooks and event propagation paths against standards.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Edge Case: The Blank Video Player
&lt;/h4&gt;

&lt;p&gt;A blank video player in Aurora was initially suspected to be a rendering bug. The &lt;em&gt;mechanism&lt;/em&gt; was simpler: the video had been removed from YouTube, but Aurora lacked robust error handling for missing media. This highlights a broader risk: &lt;em&gt;edge cases in complex systems often mimic internal failures&lt;/em&gt;. &lt;strong&gt;Rule: When debugging media rendering, verify external resource availability before assuming engine failure.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Rust’s Memory Safety: A Double-Edged Sword
&lt;/h3&gt;

&lt;p&gt;Rust’s memory safety prevents issues like &lt;strong&gt;double-parented nodes&lt;/strong&gt;, which caused YouTube’s cleanup logic to spin indefinitely. However, it complicates integration with external components like V8 and Stylo. The &lt;em&gt;mechanism&lt;/em&gt; is Rust’s strict ownership model, which conflicts with C++-based libraries’ memory management. &lt;em&gt;This introduces integration overhead but reduces undefined behavior risks.&lt;/em&gt; &lt;strong&gt;Rule: Use Rust’s safety guarantees to eliminate memory-related bugs, but budget for integration challenges with non-Rust components.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Capability Gating: Trade-offs in Design
&lt;/h3&gt;

&lt;p&gt;Aurora’s use of &lt;strong&gt;capability gating&lt;/strong&gt; accelerates development by integrating V8, Stylo, and Vello. However, this ties Aurora to their release cycles and bugs. The &lt;em&gt;mechanism&lt;/em&gt; is a dependency on external components, which introduces latency in adopting fixes. &lt;em&gt;A fully custom implementation would offer greater control but at higher development cost.&lt;/em&gt; &lt;strong&gt;Rule: If innovation is the priority, use external components; if stability is critical, invest in custom implementations.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Strategic Implications: Beyond YouTube
&lt;/h3&gt;

&lt;p&gt;Aurora’s progress with YouTube demonstrates Rust’s viability for browser engines, reducing reliance on Chromium. However, failure would underscore the risks of browser engine monoculture. The &lt;em&gt;mechanism&lt;/em&gt; is stagnation in innovation and security vulnerabilities from a single dominant engine. &lt;strong&gt;Rule: Diversify browser engine development to mitigate ecosystem risks.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust’s Role: Advantages and Limitations in Browser Engine Development
&lt;/h2&gt;

&lt;p&gt;Rust’s memory safety guarantees are a double-edged sword in Aurora’s development. On one hand, they prevent &lt;strong&gt;undefined behavior&lt;/strong&gt; like double-parented nodes, which caused YouTube’s cleanup logic to spin indefinitely. This is because Rust’s ownership model enforces strict parent-child relationships in the DOM tree, eliminating dangling references. However, this same safety introduces &lt;strong&gt;integration challenges&lt;/strong&gt; with C++-based libraries like V8 and Stylo. Rust’s strict borrowing rules clash with C++’s manual memory management, requiring unsafe code blocks or bindings like &lt;em&gt;blitz-dom&lt;/em&gt; to bridge the gap. This trade-off highlights a key rule: &lt;strong&gt;Use Rust for memory safety, but budget for integration friction with non-Rust components.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rust’s concurrency model, particularly its &lt;strong&gt;fearless concurrency&lt;/strong&gt; via ownership and borrowing, theoretically enables efficient parallelization of tasks like layout computation and painting. However, Aurora’s current bottleneck lies in &lt;strong&gt;shadow DOM composition&lt;/strong&gt;, where detached logical fragments must be reattached to the connected tree. This process is inherently sequential, as connected callbacks must fire in a specific order. Rust’s concurrency advantages are muted here, as the problem is not parallelizable without breaking the DOM’s integrity. This reveals a practical insight: &lt;strong&gt;Concurrency benefits are limited by the sequential nature of certain browser engine tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Advantage:&lt;/strong&gt; Rust’s memory safety prevents infinite loops in YouTube’s cleanup logic by eliminating double-parented nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limitation:&lt;/strong&gt; Integration with V8 and Stylo requires unsafe code or bindings, increasing complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge Case:&lt;/strong&gt; Shadow DOM composition remains sequential, limiting Rust’s concurrency benefits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Performance-wise, Rust’s zero-cost abstractions and lack of garbage collection provide a &lt;strong&gt;predictable execution profile&lt;/strong&gt;, critical for rendering-intensive applications like YouTube. However, this comes at the cost of &lt;strong&gt;development complexity&lt;/strong&gt;. For instance, fixing the masthead logo issue required rewriting parent validation code to handle shadow roots separately. While Rust’s safety caught the initial bug, the solution demanded deep understanding of both Rust and browser standards. This underscores a rule: &lt;strong&gt;Rust’s performance gains require higher developer expertise, particularly in edge cases like shadow DOM handling.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, Rust’s ecosystem limitations pose a practical challenge. Unlike C++, Rust lacks mature libraries for browser engine development, forcing reliance on external components like Stylo and Vello. This ties Aurora to their release cycles and bugs, as seen with the Stylo panic from uncomputed styles. While this accelerates development, it introduces &lt;strong&gt;dependency risks&lt;/strong&gt;. The optimal strategy here is to use external components for rapid iteration but invest in custom implementations for critical paths. Rule: &lt;strong&gt;Prioritize external dependencies for innovation; build custom solutions for stability.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trade-off:&lt;/strong&gt; Rust’s performance predictability vs. higher development complexity in edge cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk Mechanism:&lt;/strong&gt; Dependency on Stylo’s release cycle delays fixes for style invalidation bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimal Choice:&lt;/strong&gt; Use external components for non-critical paths; custom implementations for core logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Progress and Future Roadmap: From Prototype to Production
&lt;/h2&gt;

&lt;p&gt;Aurora’s journey from a Rust-based prototype to a production-ready browser engine capable of handling YouTube is a testament to both the potential and the pitfalls of modern browser engine development. The project has already achieved significant milestones, but the road ahead is paved with technical challenges that demand precision, innovation, and strategic decision-making.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Achievements: Incremental Wins in a Complex Landscape
&lt;/h2&gt;

&lt;p&gt;Aurora’s ability to render parts of YouTube—a notoriously complex SPA built on Polymer and ShadyDOM—is a &lt;strong&gt;critical proof of concept&lt;/strong&gt;. This progress hinges on several system mechanisms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shadow DOM Composition&lt;/strong&gt;: Aurora now correctly reattaches detached logical fragments created by Polymer, ensuring connected callbacks fire. This fixes issues like the masthead logo rendering as &lt;code&gt;0x0&lt;/code&gt;, where the logo’s layout was broken due to uncomposed fragments. The causal chain here is: &lt;em&gt;detached fragments → untriggered callbacks → missing elements → corrected composition → visible logo.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parent Validation Code&lt;/strong&gt;: Rewriting the validation logic to handle shadow roots separately resolved a bug where shadow roots were treated as stale, disconnecting them from their hosts. This change increased the paint path count from under 300 to over 400, indicating more accurate DOM tree traversal and rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Propagation and Custom Elements&lt;/strong&gt;: Fixing event propagation and custom element lifecycle management allowed YouTube’s interactive components to function partially. For example, the player frame now renders, though playback remains non-functional due to unresolved Stylo panics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These achievements highlight Aurora’s iterative approach, where each fix addresses a specific failure mode in the system. However, they also expose the &lt;em&gt;interdependence of browser engine components&lt;/em&gt;: a bug in one mechanism (e.g., shadow DOM composition) can cascade into failures in others (e.g., layout and painting).&lt;/p&gt;

&lt;h2&gt;
  
  
  Ongoing Milestones: Tackling the Next Layer of Complexity
&lt;/h2&gt;

&lt;p&gt;The current blocker—a Stylo panic during style invalidation—exemplifies the trade-offs of relying on external components. While Stylo accelerates CSS resolution, its bugs introduce instability. The optimal solution here is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If&lt;/strong&gt; an upstream fix is available but unreleased, &lt;strong&gt;use&lt;/strong&gt; a temporary workaround to fail gracefully, ensuring Aurora doesn’t crash. This buys time until the fix is integrated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If&lt;/strong&gt; the bug persists, &lt;strong&gt;consider&lt;/strong&gt; forking Stylo for critical paths, trading rapid iteration for stability. However, this introduces maintenance overhead and risks diverging from upstream improvements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another priority is resolving YouTube’s remaining rendering issues, such as the blank video player. While initially suspected to be an Aurora bug, this turned out to be a removed YouTube video—an &lt;em&gt;edge case in media resource handling&lt;/em&gt;. The rule here is: &lt;strong&gt;if media elements fail to render, verify external resource availability before assuming engine failure.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Long-Term Vision: Becoming a Fully Functional Browser Engine
&lt;/h2&gt;

&lt;p&gt;Aurora’s end goal is to render YouTube and other demanding web applications seamlessly. Achieving this requires addressing systemic challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency in Layout Computation&lt;/strong&gt;: Rust’s fearless concurrency is theoretically advantageous, but browser engine tasks like shadow DOM composition are inherently sequential. Attempting parallelization here risks breaking DOM integrity. The optimal strategy is to &lt;strong&gt;focus concurrency on independent tasks&lt;/strong&gt;, like JavaScript execution via V8, while keeping sequential operations optimized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Safety vs. Integration&lt;/strong&gt;: Rust’s memory safety prevents issues like double-parented nodes but complicates integration with C++ libraries (e.g., V8, Stylo). The rule is: &lt;strong&gt;use Rust for memory-critical components&lt;/strong&gt;, but budget for integration friction, possibly leveraging bindings like &lt;code&gt;blitz-dom&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capability Gating Trade-offs&lt;/strong&gt;: External dependencies accelerate development but tie Aurora to their release cycles. The optimal choice depends on the priority: &lt;strong&gt;use external components for innovation&lt;/strong&gt;; invest in custom implementations for stability. For example, replacing Stylo with a custom CSS engine would reduce dependency risks but significantly increase development time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Strategic Implications: Diversifying the Browser Engine Ecosystem
&lt;/h2&gt;

&lt;p&gt;Aurora’s success would demonstrate Rust’s viability for browser engines, reducing reliance on Chromium and WebKit. Failure, however, would underscore the risks of browser engine monoculture: stalled innovation, security vulnerabilities, and limited competition. The key mechanism here is &lt;em&gt;ecosystem diversity&lt;/em&gt;: multiple engines drive standards compliance, security, and performance improvements.&lt;/p&gt;

&lt;p&gt;In conclusion, Aurora’s progress from prototype to production is a high-stakes experiment in balancing innovation and stability. Each technical decision—whether to use external components, rewrite critical code, or prioritize memory safety—shapes its trajectory. As Aurora tackles YouTube’s complexity, it not only tests its own maturity but also charts a path for the future of browser engine development.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>browser</category>
      <category>youtube</category>
      <category>spa</category>
    </item>
    <item>
      <title>Efficient Streaming JSON Parser Solves Large File Handling with Low Memory and High Speed</title>
      <dc:creator>Pavel Kostromin</dc:creator>
      <pubDate>Sat, 20 Jun 2026 09:55:16 +0000</pubDate>
      <link>https://dev.to/pavkode/efficient-streaming-json-parser-solves-large-file-handling-with-low-memory-and-high-speed-3bac</link>
      <guid>https://dev.to/pavkode/efficient-streaming-json-parser-solves-large-file-handling-with-low-memory-and-high-speed-3bac</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: The Challenge of Large JSON Files
&lt;/h2&gt;

&lt;p&gt;Handling large JSON files efficiently is a critical yet often overlooked problem in modern software development. As data volumes explode and real-time processing becomes the norm, the limitations of traditional JSON parsing methods become painfully apparent. &lt;strong&gt;JSON.parse()&lt;/strong&gt;, the default choice in many environments, is a blocking operation that loads the entire file into memory before processing. For files in the MB or GB range, this approach is a recipe for disaster: memory consumption skyrockets, performance plummets, and systems risk crashing under the load.&lt;/p&gt;

&lt;p&gt;The root cause lies in the &lt;em&gt;structural mismatch between JSON’s hierarchical nature and the linear, in-memory processing model&lt;/em&gt;. JSON files, especially large ones, are often deeply nested or contain arrays with thousands of elements. When parsed conventionally, each layer of nesting or array element requires additional memory allocation. This allocation is not just a one-time cost—it accumulates as the parser traverses the document, leading to exponential memory growth. For example, a 10MB JSON file with nested arrays can easily consume &lt;strong&gt;100MB+ of RAM&lt;/strong&gt; when parsed with JSON.parse(), as each level of nesting duplicates memory references.&lt;/p&gt;

&lt;p&gt;Streaming parsers attempt to mitigate this by processing JSON incrementally, but existing solutions fall short in two key areas: &lt;strong&gt;memory control&lt;/strong&gt; and &lt;strong&gt;speed&lt;/strong&gt;. Most streaming libraries either lack the ability to balance memory usage dynamically or sacrifice performance to achieve it. This trade-off is unacceptable in production environments where both resources are scarce. Developers are left with a Hobson’s choice: tolerate slow performance, risk memory exhaustion, or rewrite critical components in lower-level languages—a costly and error-prone process.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Bote&lt;/strong&gt;, a streaming JSON parser designed to break this deadlock. By leveraging Rust’s memory safety and performance characteristics, Bote achieves up to &lt;strong&gt;16x lower memory usage&lt;/strong&gt; than JSON.parse() while maintaining &lt;strong&gt;1.5x faster throughput&lt;/strong&gt;. Its core innovation lies in a &lt;em&gt;structural position bitmap&lt;/em&gt; that tracks JSON elements without requiring full in-memory representation. This bitmap acts as a navigational map, allowing Bote to jump to any part of the JSON stream without buffering intermediate data. The result is a parser that scales linearly with file size, not exponentially.&lt;/p&gt;

&lt;p&gt;Bote’s design is further optimized for real-world use cases. Its &lt;strong&gt;AsyncIterator API&lt;/strong&gt; integrates seamlessly with modern JavaScript workflows, while compatibility with &lt;strong&gt;Standard Schema&lt;/strong&gt; ensures type safety. Critically, Bote’s memory footprint is user-controllable: developers can trade off memory for speed by adjusting buffer sizes, a feature absent in competing libraries. This flexibility is a game-changer for applications where resource constraints are unpredictable, such as cloud-native services or edge computing.&lt;/p&gt;

&lt;p&gt;However, Bote is not a silver bullet. Its performance gains come at the cost of increased complexity. The Rust-based core, while efficient, requires careful integration with JavaScript runtimes. Additionally, Bote’s streaming model assumes non-blocking I/O, making it less suitable for synchronous environments. Developers must also be mindful of JSON structure: highly fragmented or deeply nested documents may still strain memory, though to a far lesser degree than traditional parsers.&lt;/p&gt;

&lt;p&gt;In summary, Bote addresses a pressing need in the JSON parsing landscape by combining memory efficiency, speed, and usability. Its technical innovations—particularly the structural bitmap and Rust implementation—set a new benchmark for streaming parsers. While not without limitations, Bote represents a significant step forward for developers grappling with large JSON datasets. As data volumes continue to grow, tools like Bote will become indispensable for building scalable, resource-efficient applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem Mechanism:&lt;/strong&gt; Traditional JSON parsing causes memory bloat due to recursive allocation during nested structure traversal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bote’s Solution:&lt;/strong&gt; Structural bitmap navigation eliminates redundant memory allocation, enabling linear scaling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimal Use Case:&lt;/strong&gt; If processing JSON files &amp;gt;1MB with limited memory (e.g., serverless, edge devices), use Bote to avoid OOM errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure Condition:&lt;/strong&gt; Bote’s streaming model breaks down in synchronous environments or when JSON structure is extremely fragmented.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision Rule:&lt;/strong&gt; If memory usage is critical and JSON size exceeds available RAM, prioritize Bote over JSON.parse() or other streaming libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Challenge of Large JSON Parsing
&lt;/h2&gt;

&lt;p&gt;Parsing large JSON files is a deceptively complex task, often exposing critical weaknesses in traditional methods. At the heart of the problem is the &lt;strong&gt;structural mismatch between JSON’s hierarchical nature and linear, in-memory processing models&lt;/strong&gt;. When a parser like &lt;code&gt;JSON.parse()&lt;/code&gt; encounters a nested JSON structure, it recursively allocates memory for each layer, leading to &lt;strong&gt;exponential memory growth&lt;/strong&gt;. For example, a 10MB JSON file with deeply nested arrays can consume &lt;strong&gt;100MB+ of RAM&lt;/strong&gt; due to the overhead of intermediate object representations. This mechanism triggers &lt;strong&gt;memory exhaustion&lt;/strong&gt;, causing systems to crash or grind to a halt—a risk amplified in resource-constrained environments like serverless platforms or edge devices.&lt;/p&gt;

&lt;p&gt;Streaming parsers, while designed to mitigate this by processing data incrementally, often fail due to &lt;strong&gt;inadequate memory control or performance trade-offs&lt;/strong&gt;. Most lack the ability to balance memory usage dynamically, forcing developers into a false choice: either accept slower throughput or risk system instability. This failure is rooted in their inability to &lt;strong&gt;track structural positions without buffering intermediate data&lt;/strong&gt;, a limitation that Bote addresses through its &lt;em&gt;Structural Position Bitmap&lt;/em&gt;. This mechanism allows Bote to navigate JSON hierarchies without fully materializing them in memory, achieving a &lt;strong&gt;linear memory scaling model&lt;/strong&gt;—a critical shift from the exponential growth of traditional methods.&lt;/p&gt;

&lt;p&gt;The causal chain here is clear: &lt;strong&gt;impact (memory exhaustion) → internal process (recursive allocation during traversal) → observable effect (system crashes or slowdowns)&lt;/strong&gt;. Bote disrupts this chain by &lt;strong&gt;decoupling navigation from memory allocation&lt;/strong&gt;, ensuring that memory usage scales linearly with file size, not structure depth. This innovation is further amplified by its &lt;strong&gt;Rust implementation&lt;/strong&gt;, which leverages memory safety and zero-cost abstractions to minimize overhead, resulting in &lt;strong&gt;16x lower memory usage and 1.5x faster throughput&lt;/strong&gt; compared to &lt;code&gt;JSON.parse()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge Cases and Failure Conditions
&lt;/h2&gt;

&lt;p&gt;While Bote excels in memory-constrained, large-file scenarios, it is not universally optimal. In &lt;strong&gt;synchronous environments&lt;/strong&gt; or with &lt;strong&gt;extremely fragmented JSON structures&lt;/strong&gt;, its asynchronous, streaming design can introduce latency. The mechanism here is straightforward: synchronous workflows require immediate data availability, which Bote’s incremental processing model cannot guarantee without buffering—defeating its memory efficiency. Similarly, fragmented JSON (e.g., deeply nested objects with sparse data) forces Bote to allocate more bitmap entries, increasing memory overhead. However, these cases are edge scenarios; Bote’s &lt;strong&gt;user-controllable buffer sizes&lt;/strong&gt; allow developers to tune performance for specific trade-offs, a flexibility absent in alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision Rule: When to Use Bote
&lt;/h2&gt;

&lt;p&gt;Prioritize Bote over &lt;code&gt;JSON.parse()&lt;/code&gt; or other streaming libraries &lt;strong&gt;when memory usage is critical and JSON size exceeds available RAM&lt;/strong&gt;. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If X (JSON file &amp;gt;1MB and memory-constrained environment)&lt;/strong&gt; → &lt;strong&gt;Use Y (Bote)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Avoid Z (traditional parsers or outdated streaming libraries) due to &lt;strong&gt;exponential memory growth risk&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typical choice errors include &lt;strong&gt;overestimating available memory&lt;/strong&gt; or &lt;strong&gt;underestimating JSON complexity&lt;/strong&gt;, both of which lead to system failures. Bote’s linear scaling and adjustable buffers provide a safety net against these miscalculations, making it the optimal choice for large-scale, resource-sensitive applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bote: Features and Performance
&lt;/h2&gt;

&lt;p&gt;Bote, a new open-source streaming JSON parser, emerges as a critical tool for developers grappling with the challenges of processing large JSON files. Its design philosophy centers on &lt;strong&gt;low-memory streaming&lt;/strong&gt; and &lt;strong&gt;high-speed performance&lt;/strong&gt;, addressing the inherent limitations of traditional methods like &lt;code&gt;JSON.parse()&lt;/code&gt;. By dissecting its features and benchmarking its performance, we uncover how Bote solves real-world problems in JSON handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Features: Mechanisms and Impact
&lt;/h3&gt;

&lt;p&gt;Bote’s innovation lies in its &lt;strong&gt;Structural Position Bitmap&lt;/strong&gt;, a mechanism that decouples JSON navigation from memory allocation. Unlike traditional parsers, which recursively allocate memory for nested structures, Bote tracks JSON elements using a bitmap. This approach avoids intermediate object representations, preventing the &lt;em&gt;exponential memory growth&lt;/em&gt; that occurs when parsing deep or complex JSON hierarchies. For example, a 10MB JSON file with nested arrays might consume 100MB+ RAM with &lt;code&gt;JSON.parse()&lt;/code&gt; due to recursive allocation, whereas Bote’s bitmap-based navigation keeps memory usage linear with file size.&lt;/p&gt;

&lt;p&gt;The parser is written in &lt;strong&gt;Rust&lt;/strong&gt;, leveraging its memory safety and zero-cost abstractions to achieve &lt;strong&gt;16x lower memory usage&lt;/strong&gt; and &lt;strong&gt;1.5x faster throughput&lt;/strong&gt; than &lt;code&gt;JSON.parse()&lt;/code&gt;. Rust’s ownership model ensures that memory is managed efficiently, eliminating the risk of memory leaks or fragmentation that plague traditional parsers. This is particularly critical in resource-constrained environments like serverless functions or edge devices, where memory exhaustion can lead to system crashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmarks: Evidence of Superiority
&lt;/h3&gt;

&lt;p&gt;Benchmarks, available in the &lt;a href="https://github.com/jankdc/bote#bote" rel="noopener noreferrer"&gt;project’s README&lt;/a&gt;, demonstrate Bote’s performance advantages. When processing a 1GB JSON file, Bote consumes &lt;strong&gt;16x less memory&lt;/strong&gt; than &lt;code&gt;JSON.parse()&lt;/code&gt; while maintaining &lt;strong&gt;1.5x faster parsing speed&lt;/strong&gt;. This is achieved through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Streaming Architecture:&lt;/strong&gt; Bote processes JSON incrementally, avoiding the need to load the entire file into memory. This linearizes memory usage, preventing the exponential growth caused by recursive allocation in traditional parsers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bitmap Navigation:&lt;/strong&gt; The Structural Position Bitmap allows Bote to jump to any part of the JSON without buffering intermediate data, reducing memory overhead and improving throughput.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AsyncIterator API:&lt;/strong&gt; Bote integrates seamlessly with modern JavaScript workflows, enabling asynchronous processing that minimizes blocking and maximizes resource utilization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Edge Cases and Failure Conditions
&lt;/h3&gt;

&lt;p&gt;While Bote excels in memory-constrained, large-file scenarios, it has limitations. In &lt;strong&gt;synchronous environments&lt;/strong&gt;, the asynchronous streaming architecture introduces latency, making it suboptimal for small, simple JSON files. Additionally, &lt;strong&gt;extremely fragmented JSON structures&lt;/strong&gt; increase the number of bitmap entries, raising memory overhead. However, Bote mitigates this with &lt;strong&gt;user-controllable buffer sizes&lt;/strong&gt;, allowing developers to tune performance based on their specific use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decision Rule: When to Use Bote
&lt;/h3&gt;

&lt;p&gt;Bote is the optimal choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON file size exceeds &lt;strong&gt;1MB&lt;/strong&gt; and memory is constrained.&lt;/li&gt;
&lt;li&gt;Traditional parsers like &lt;code&gt;JSON.parse()&lt;/code&gt; risk memory exhaustion due to recursive allocation.&lt;/li&gt;
&lt;li&gt;Performance and usability are critical, and developers need an ergonomic API with modern features like &lt;strong&gt;AsyncIterator&lt;/strong&gt; and &lt;strong&gt;Standard Schema&lt;/strong&gt; integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid Bote in synchronous environments or when processing small, simple JSON files, as the overhead of asynchronous streaming may outweigh the benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Insights: Lessons from Development
&lt;/h3&gt;

&lt;p&gt;The creator’s transparency about the development process highlights key insights. Inspired by &lt;strong&gt;simdjson&lt;/strong&gt; and &lt;strong&gt;JSONSki&lt;/strong&gt;, Bote combines their performance-focused approaches with a low-memory niche. The use of Rust for performance-critical components, despite the creator’s initial inexperience, underscores the importance of leveraging specialized tools for specific problems. The &lt;strong&gt;AI-assisted development&lt;/strong&gt; and rigorous verification of the Rust code demonstrate a pragmatic approach to balancing innovation with reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion: Bote’s Role in Modern JSON Processing
&lt;/h3&gt;

&lt;p&gt;Bote disrupts the traditional JSON parsing paradigm by linearizing memory scaling and optimizing for speed. Its Structural Position Bitmap and Rust implementation address the root causes of memory inefficiency in JSON processing, making it a dominant solution for large-scale, resource-sensitive applications. By understanding its mechanisms, benchmarks, and edge cases, developers can make informed decisions to avoid common pitfalls like memory exhaustion and system crashes. If you’re handling JSON files &amp;gt;1MB in memory-constrained environments, &lt;strong&gt;Bote is the tool to use.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases and Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Real-Time Analytics in Serverless Environments
&lt;/h3&gt;

&lt;p&gt;In serverless architectures, memory and execution time are strictly limited. &lt;strong&gt;Bote’s linear memory scaling&lt;/strong&gt; prevents exponential memory growth, which would otherwise trigger &lt;em&gt;out-of-memory (OOM) errors&lt;/em&gt; when processing large JSON payloads. For example, a 10MB JSON file processed with &lt;code&gt;JSON.parse()&lt;/code&gt; might consume 100MB+ RAM due to recursive object allocation, crashing the function. Bote’s &lt;strong&gt;Structural Position Bitmap&lt;/strong&gt; decouples navigation from memory allocation, keeping memory usage under 6MB for the same file, ensuring stable operation within serverless constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Edge Device Data Processing
&lt;/h3&gt;

&lt;p&gt;Edge devices (e.g., IoT sensors) often have &lt;em&gt;limited RAM (256MB–1GB)&lt;/em&gt;. Traditional parsers fail when handling multi-megabyte JSON logs due to memory fragmentation. Bote’s &lt;strong&gt;Rust implementation&lt;/strong&gt; ensures &lt;em&gt;memory safety&lt;/em&gt; and &lt;strong&gt;zero-cost abstractions&lt;/strong&gt;, eliminating leaks. Its &lt;strong&gt;streaming architecture&lt;/strong&gt; processes JSON incrementally, avoiding full file buffering. For a 50MB JSON log, Bote uses ~3MB RAM, while &lt;code&gt;JSON.parse()&lt;/code&gt; would require 500MB+, causing system instability.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. High-Frequency API Response Parsing
&lt;/h3&gt;

&lt;p&gt;APIs returning large JSON responses (e.g., financial data feeds) require &lt;strong&gt;low-latency parsing&lt;/strong&gt;. Bote’s &lt;strong&gt;1.5x faster throughput&lt;/strong&gt; compared to &lt;code&gt;JSON.parse()&lt;/code&gt; stems from its &lt;em&gt;async processing&lt;/em&gt; and &lt;strong&gt;bitmap navigation&lt;/strong&gt;, which avoids buffering intermediate data. In a scenario with 10,000 requests/second, Bote reduces parsing time from 20ms to 13ms per request, preventing API bottlenecks and ensuring real-time data availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Log Aggregation in Distributed Systems
&lt;/h3&gt;

&lt;p&gt;Aggregating JSON logs from distributed nodes often involves &lt;em&gt;nested structures&lt;/em&gt; that trigger &lt;strong&gt;exponential memory growth&lt;/strong&gt; in traditional parsers. Bote’s &lt;strong&gt;bitmap-based tracking&lt;/strong&gt; linearizes memory usage, enabling aggregation of 1GB+ logs without OOM errors. For instance, a nested array of 1M objects would cause &lt;code&gt;JSON.parse()&lt;/code&gt; to allocate 10GB+ RAM, while Bote maintains ~64MB usage, ensuring reliable log processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Frontend Data Aggregation
&lt;/h3&gt;

&lt;p&gt;Fetching large JSON datasets for frontend rendering (e.g., dashboards) risks &lt;em&gt;browser memory exhaustion&lt;/em&gt;. Bote’s &lt;strong&gt;AsyncIterator API&lt;/strong&gt; integrates seamlessly with modern JavaScript workflows, allowing incremental processing. For a 20MB JSON payload, Bote streams data in ~1MB chunks, keeping memory usage under 10MB, whereas &lt;code&gt;JSON.parse()&lt;/code&gt; would lock up the browser with 200MB+ allocation.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. ETL Pipelines with Memory Constraints
&lt;/h3&gt;

&lt;p&gt;ETL pipelines processing GB-scale JSON files often fail due to &lt;em&gt;memory fragmentation&lt;/em&gt; or &lt;strong&gt;recursive allocation&lt;/strong&gt;. Bote’s &lt;strong&gt;user-controllable buffer sizes&lt;/strong&gt; allow tuning memory-speed trade-offs. For a 5GB JSON file, setting a 128MB buffer ensures linear memory scaling, preventing pipeline crashes. Without Bote, &lt;code&gt;JSON.parse()&lt;/code&gt; would require 50GB+ RAM, exceeding typical server capacity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Decision Rule: When to Use Bote
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Bote if:&lt;/strong&gt; JSON file size &amp;gt;1MB and memory is constrained (e.g., serverless, edge devices, browsers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Bote if:&lt;/strong&gt; JSON files are small (&amp;lt;1MB) or synchronous environments are required (asynchronous streaming introduces latency).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Common Errors and Mitigation
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Error 1:&lt;/strong&gt; Overestimating available memory → &lt;em&gt;Mechanism:&lt;/em&gt; Developers assume sufficient RAM without accounting for recursive allocation. &lt;strong&gt;Solution:&lt;/strong&gt; Use Bote’s buffer tuning to cap memory usage.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Error 2:&lt;/strong&gt; Underestimating JSON complexity → &lt;em&gt;Mechanism:&lt;/em&gt; Nested structures amplify memory growth exponentially. &lt;strong&gt;Solution:&lt;/strong&gt; Benchmark with Bote’s linear scaling to avoid surprises.&lt;/p&gt;

&lt;h4&gt;
  
  
  Edge Case Analysis
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Fragmented JSON:&lt;/strong&gt; Increases bitmap entries, raising memory overhead. &lt;em&gt;Mitigation:&lt;/em&gt; Adjust buffer size to balance memory and speed.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Synchronous Environments:&lt;/strong&gt; Asynchronous streaming introduces latency. &lt;em&gt;Mitigation:&lt;/em&gt; Use Bote only if latency is acceptable or refactor to async workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and Future Outlook
&lt;/h2&gt;

&lt;p&gt;Bote stands as a transformative solution in the realm of JSON parsing, addressing the critical need for &lt;strong&gt;fast, low-memory processing of large JSON files&lt;/strong&gt;. By leveraging a &lt;strong&gt;Structural Position Bitmap&lt;/strong&gt; and a &lt;strong&gt;Rust-based implementation&lt;/strong&gt;, it achieves &lt;strong&gt;16x lower memory usage&lt;/strong&gt; and &lt;strong&gt;1.5x faster throughput&lt;/strong&gt; compared to traditional parsers like &lt;em&gt;JSON.parse()&lt;/em&gt;. This is not just a marginal improvement—it’s a paradigm shift, enabling developers to handle &lt;strong&gt;gigabyte-scale JSON files&lt;/strong&gt; in environments where memory and speed are non-negotiable, such as &lt;strong&gt;serverless platforms&lt;/strong&gt;, &lt;strong&gt;edge devices&lt;/strong&gt;, and &lt;strong&gt;high-frequency APIs&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Bote Matters
&lt;/h3&gt;

&lt;p&gt;The core innovation lies in Bote’s ability to &lt;strong&gt;decouple JSON navigation from memory allocation&lt;/strong&gt;. Traditional parsers create intermediate object representations, leading to &lt;strong&gt;exponential memory growth&lt;/strong&gt; as JSON depth increases. For example, a &lt;strong&gt;10MB JSON file&lt;/strong&gt; can consume &lt;strong&gt;100MB+ of RAM&lt;/strong&gt;, causing &lt;strong&gt;system crashes&lt;/strong&gt; or &lt;strong&gt;slowdowns&lt;/strong&gt;. Bote’s bitmap-based approach tracks structural positions without buffering, ensuring &lt;strong&gt;linear memory scaling&lt;/strong&gt; with file size. This mechanism is particularly critical in &lt;strong&gt;memory-constrained environments&lt;/strong&gt;, where traditional parsers fail due to &lt;strong&gt;recursive memory allocation&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Insights and Edge Cases
&lt;/h3&gt;

&lt;p&gt;While Bote excels in &lt;strong&gt;asynchronous, memory-constrained scenarios&lt;/strong&gt;, it’s not a one-size-fits-all solution. In &lt;strong&gt;synchronous environments&lt;/strong&gt;, the asynchronous streaming architecture introduces &lt;strong&gt;latency&lt;/strong&gt;, reducing efficiency. Similarly, &lt;strong&gt;highly fragmented JSON structures&lt;/strong&gt; increase bitmap entries, raising memory overhead. However, these edge cases can be mitigated through &lt;strong&gt;buffer size tuning&lt;/strong&gt;, a feature unique to Bote that allows developers to balance memory usage and speed dynamically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Future Developments
&lt;/h3&gt;

&lt;p&gt;As JSON parsing continues to evolve, Bote’s open-source nature invites contributions to enhance its capabilities. Potential improvements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Schema Integration&lt;/strong&gt;: Expanding support for more complex schemas to improve type safety and validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous Mode&lt;/strong&gt;: Developing a synchronous variant to cater to environments where asynchronous processing is suboptimal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fragmentation Optimization&lt;/strong&gt;: Further refining bitmap construction to handle fragmented JSON more efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Decision Rule: When to Use Bote
&lt;/h3&gt;

&lt;p&gt;Use Bote if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your JSON file size exceeds &lt;strong&gt;1MB&lt;/strong&gt; and you’re in a &lt;strong&gt;memory-constrained environment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Traditional parsers risk &lt;strong&gt;memory exhaustion&lt;/strong&gt; or &lt;strong&gt;system crashes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You require &lt;strong&gt;modern API features&lt;/strong&gt; like &lt;em&gt;AsyncIterator&lt;/em&gt; and &lt;em&gt;Standard Schema&lt;/em&gt; integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid Bote if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your JSON file size is &lt;strong&gt;less than 1MB&lt;/strong&gt; or you’re in a &lt;strong&gt;synchronous environment&lt;/strong&gt; where latency is unacceptable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Bote is not just another JSON parser—it’s a &lt;strong&gt;purpose-built tool&lt;/strong&gt; for the modern data landscape. Its &lt;strong&gt;linear memory scaling&lt;/strong&gt;, &lt;strong&gt;bitmap navigation&lt;/strong&gt;, and &lt;strong&gt;Rust-powered performance&lt;/strong&gt; make it indispensable for large-scale, resource-sensitive applications. Whether you’re aggregating logs, processing API responses, or handling frontend data, Bote offers a &lt;strong&gt;reliable, efficient solution&lt;/strong&gt;. Explore its potential, contribute to its growth, and redefine how you handle JSON data.&lt;/p&gt;

</description>
      <category>json</category>
      <category>parsing</category>
      <category>rust</category>
      <category>streaming</category>
    </item>
    <item>
      <title>Stripping Away Abstractions: How I Built a Rust Microkernel from Scratch in 100 Hours (At Age 13)</title>
      <dc:creator>Daxo</dc:creator>
      <pubDate>Sat, 20 Jun 2026 09:27:03 +0000</pubDate>
      <link>https://dev.to/aitoolsdxglitch/stripping-away-abstractions-how-i-built-a-rust-microkernel-from-scratch-in-100-hours-at-age-13-3cik</link>
      <guid>https://dev.to/aitoolsdxglitch/stripping-away-abstractions-how-i-built-a-rust-microkernel-from-scratch-in-100-hours-at-age-13-3cik</guid>
      <description>&lt;p&gt;Most developers take the operating system for granted-treating it as an invisible, obedient foundation for browsers, Docker, and heavy IDEs. For me, this foundation was always the ultimate mystery. I wanted to understand: what actually happens on the bare metal when you strip away high-level abstractions?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's how my 15-day experiment started. I carved out 100 hours&lt;/strong&gt; from a tight schedule between school and intense martial arts training (judo and wrestling) to build a standalone, microkernel-based operating system from scratch: Daxo OS, written in Rust.&lt;/p&gt;

&lt;p&gt;In this article, I’ll share how I broke free from standard tutorials, wrote a custom PIO ATA disk driver, brought async programming into Ring 0, and why Terry Davis and his legendary TempleOS became my ultimate engineering inspiration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;![Daxo OS in Action]&lt;/strong&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/nwiom7r5gtvtviq6h6yd.jpg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/nwiom7r5gtvtviq6h6yd.jpg&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspired by Madness: Why Bare-Metal?
&lt;/h2&gt;

&lt;p&gt;If you ask a regular software engineer why they are writing their own OS, they might think you're crazy. But if you’ve ever read about Terry Davis and TempleOS, you understand that pure, unadulterated engineering excitement. Terry built his world without looking back at Linux or Windows-communicating directly with CPU registers and controllers.&lt;/p&gt;

&lt;p&gt;I didn't want to build another CLI tool running on top of a ready-made Linux kernel. I wanted a system that manages physical hardware by my own rules. The choice was obvious: Rust Nightly. Its #[no_std] attribute allows writing blazing-fast code without a garbage collector while maintaining strict memory safety.&lt;/p&gt;

&lt;p&gt;Here is the anatomy of Daxo OS:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;daxo_os/&lt;br&gt;
├── .cargo/&lt;br&gt;
│   └── config.toml           # Linker settings and build flags&lt;br&gt;
├── src/&lt;br&gt;
│   ├── allocator/            # Custom heap allocators (Bump, Fixed Size Block)&lt;br&gt;
│   ├── task/                 # Async engine (Executor, keyboard handling)&lt;br&gt;
│   ├── allocator.rs          # Heap management interface&lt;br&gt;
│   ├── ata.rs                # The custom PIO ATA hard drive driver&lt;br&gt;
│   ├── framebuffer.rs        # Graphics output management&lt;br&gt;
│   ├── gdt.rs / interrupts.rs# Descriptor tables &amp;amp; interrupt handling&lt;br&gt;
│   ├── main.rs               # Kernel entry point (kernel_main)&lt;br&gt;
│   └── vga_buffer.rs         # Good old 80x25 text output&lt;br&gt;
├── disk.bin                  # Disk image for QEMU testing&lt;br&gt;
└── x86_64-blog_os.json       # Target platform specification&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The Tutorial Illusion and My First Triple Fault&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
​Initially, like many OSdev beginners, I relied on Philipp Oppermann's amazing "Writing an OS in Rust" guide. Printing ASCII characters to the screen via direct VGA memory access at 0xb8000 is inspiring, but it's a linear experience. You are just following someone else's tracks.&lt;/p&gt;

&lt;p&gt;​Real engineering started where the guide ended. Since the modern Rust Nightly compiler moves fast, some older code broke. The rust-lld linker suddenly started throwing errors like undefined symbol: memcpy, and the kernel would plunge into a bootloop (Triple Fault) at the slightest mistake.&lt;/p&gt;

&lt;p&gt;​I realized that modern Rust editions require explicit encapsulation of raw operations inside unsafe blocks, even within unsafe fn in some contexts, alongside strict handling of compiler_builtins. Fixing this required diving into Cargo flags and manually rebuilding core libraries. It was the exact moment I transitioned from passively reading tutorials to hardcore systems research.&lt;br&gt;
**&lt;br&gt;
​Hardware with No Safety Nets: Writing a PIO ATA Driver**&lt;/p&gt;

&lt;p&gt;​My main critique of existing OSdev tutorials is that they often abandon the reader halfway through. You get text output, you get keyboard interrupts, but the system remains a "black box"-it cannot persist data.&lt;/p&gt;

&lt;p&gt;​I decided to fix this by writing a custom PIO ATA driver for hard drive interaction.&lt;/p&gt;

&lt;p&gt;​The hard part? The OS needs to read disk sectors before the Interrupt Descriptor Table (IDT) and the Programmable Interrupt Controller (PIC) are fully set up. If the drive fires a hardware signal when the kernel isn't ready to catch it, you get an immediate crash.&lt;br&gt;
​I used an architectural hack: isolated port polling right before turning on interrupts.&lt;/p&gt;

&lt;p&gt;​Here is how the boot logic looks in my main.rs:&lt;br&gt;
`#![no_std]&lt;/p&gt;

&lt;h1&gt;
  
  
  ![no_main]
&lt;/h1&gt;

&lt;h1&gt;
  
  
  ![feature(custom_test_frameworks)]
&lt;/h1&gt;

&lt;h1&gt;
  
  
  ![test_runner(daxo_os::test_runner)]
&lt;/h1&gt;

&lt;h1&gt;
  
  
  ![reexport_test_harness_main = "test_main"]
&lt;/h1&gt;

&lt;p&gt;extern crate alloc;&lt;/p&gt;

&lt;p&gt;use daxo_os::{print, println};&lt;br&gt;
use core::panic::PanicInfo;&lt;br&gt;
use bootloader::{BootInfo, entry_point};&lt;br&gt;
use x86_64::VirtAddr;&lt;br&gt;
use alloc::vec;&lt;/p&gt;

&lt;p&gt;// Import structures for async multitasking&lt;br&gt;
use daxo_os::task::{Task, keyboard};&lt;br&gt;
use daxo_os::task::executor::Executor;&lt;/p&gt;

&lt;p&gt;entry_point!(kernel_main);&lt;/p&gt;

&lt;p&gt;async fn async_number() -&amp;gt; u32 {&lt;br&gt;
    42&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;async fn example_task() {&lt;br&gt;
    let number = async_number().await;&lt;br&gt;
    println!("async number from example_task: {}", number);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;fn kernel_main(boot_info: &amp;amp;'static BootInfo) -&amp;gt; ! {&lt;br&gt;
    // 1. First, print the ASCII banner (works via VGA, interrupts are not needed yet)&lt;br&gt;
    println!("     ######      ###    ##     ##  #######     #######   ######  ");&lt;br&gt;
    println!("     ##   ##    ## ##    ##   ##  ##     ##   ##     ## ##    ## ");&lt;br&gt;
    println!("     ##    ##  ##   ##    ## ##   ##     ##   ##     ## ##       ");&lt;br&gt;
    println!("     ##    ## ##     ##    ###    ##     ##   ##     ##  ######  ");&lt;br&gt;
    println!("     ##    ## #########   ## ##   ##     ##   ##     ##       ## ");&lt;br&gt;
    println!("     ##   ##  ##     ##  ##   ##  ##     ##   ##     ## ##    ## ");&lt;br&gt;
    println!("     ######   ##     ## ##     ##  #######     #######   ######  ");&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;println!("\n[Daxo OS Multitasking Kernel Booted]");

// 2. Set up the memory mapper and heap (interrupts are still disabled)
let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset);
let mut mapper = unsafe { daxo_os::memory::init(phys_mem_offset) };
let mut frame_allocator = unsafe {
    daxo_os::memory::BootInfoFrameAllocator::init(&amp;amp;boot_info.memory_map)
};

daxo_os::allocator::init_heap(&amp;amp;mut mapper, &amp;amp;mut frame_allocator)
    .expect("heap initialization failed");

// 3. --- ATA DRIVE DRIVER TEST IN COMPLETE ISOLATION ---
// PIC controller is not enabled yet, timer isn't ticking, nothing to crash!
println!("[Testing ATA Drive Driver...]");

let mut disk_vec = vec![0u8; 512];

if let Ok(disk_buffer) = &amp;lt;&amp;amp;mut [u8; 512]&amp;gt;::try_from(&amp;amp;mut disk_vec[..]) {
    daxo_os::ata::ATA_BUS.lock().read_sector(0, disk_buffer);

    println!("Data read from LBA 0:");
    let mut data_found = false;
    for &amp;amp;byte in disk_buffer.iter().take(90) {
        if byte &amp;gt;= 32 &amp;amp;&amp;amp; byte &amp;lt;= 126 {
            print!("{}", byte as char);
            data_found = true;
        }
    }
    if !data_found {
        print!("[Sector contains binary data]");
    }
    println!("\n[ATA Test Finished]\n");
}
// ---------------------------------------------------------------------------------

// 4. NOW initialize IDT, GDT, and the PIC interrupt controller
// Any hardware signals from QEMU pending during the disk test will reset upon PIC initialization!
daxo_os::init(); 

#[cfg(test)]
test_main();

// 5. Create the task executor/scheduler
let mut executor = Executor::new();
executor.spawn(Task::new(example_task()));
executor.spawn(Task::new(keyboard::print_keypresses()));

// 6. Enable hardware interrupts on the CPU
x86_64::instructions::interrupts::enable();

// 7. Run the executor loop indefinitely
executor.run();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;h1&gt;
  
  
  [cfg(not(test))]
&lt;/h1&gt;

&lt;h1&gt;
  
  
  [panic_handler]
&lt;/h1&gt;

&lt;p&gt;fn panic(info: &amp;amp;PanicInfo) -&amp;gt; ! {&lt;br&gt;
    println!("{}", info);&lt;br&gt;
    daxo_os::hlt_loop();&lt;br&gt;
}&lt;/p&gt;

&lt;h1&gt;
  
  
  [cfg(test)]
&lt;/h1&gt;

&lt;h1&gt;
  
  
  [panic_handler]
&lt;/h1&gt;

&lt;p&gt;fn panic(info: &amp;amp;PanicInfo) -&amp;gt; ! {&lt;br&gt;
    daxo_os::test_panic_handler(info)&lt;br&gt;
}`&lt;/p&gt;

&lt;p&gt;To test the driver without a real file system, I used some Unix magic to write a test string into the first 512-byte sector of a blank disk.bin file:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;echo "Daxo OS ATA Test String" | dd of=disk.bin bs=512 count=1 conv=notrunc&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The conv=notrunc flag is critical here—it ensures dd overwrites only the initial bytes without truncating the disk image. I configured QEMU in Cargo.toml to mount this file as a hard drive on the IDE bus. When the kernel printed Daxo OS ATA Test String read directly from the controller ports, I knew it worked.&lt;/p&gt;

&lt;p&gt;​&lt;strong&gt;Async in Ring 0 Space&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​Once the disk is verified, control goes to a custom asynchronous task executor. Implementing async/await mechanics inside a custom kernel without the standard library is pure joy. There is no Tokio or async-std here.&lt;/p&gt;

&lt;p&gt;​The architecture relies heavily on raw Future and Waker types. When a task (like waiting for a keypress in keyboard::print_keypresses) cannot proceed, it yields, giving CPU cycles to other tasks. As soon as the PIC catches a keyboard interrupt, the handler wakes that specific Waker, and the executor resumes it. It runs concurrently and endlessly inside executor.run().&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;​Conclusion: Real Engineering Starts Where Tutorials End&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​This 100-hour sprint taught me the most important lesson: don't panic when facing complete darkness. When you are looking at a raw terminal crash log with a low-level error you can't Google, the only way out is to read dependency source code, look up x86_64 architecture specifications, and understand the physics of the process.&lt;/p&gt;

&lt;p&gt;​Moving forward, I plan to take Daxo OS further: shifting from Ring 0 to Ring 3 (separating kernel and user spaces), exploring process isolation, and researching microkernel security mitigations.&lt;/p&gt;

&lt;p&gt;​👉 Check out the full source code here: github.com/aitoolsdx-glitch/daxo_os&lt;br&gt;
&lt;em&gt;(Drop a star ⭐ or open an issue if you want to roast my unsafe code or contribute!)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>osdev</category>
      <category>showdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>SQLite riscritta in Rust? Perché qualcuno sta provando a toccare il codice “più affidabile” che abbiamo</title>
      <dc:creator>frontendfacile.it</dc:creator>
      <pubDate>Sat, 20 Jun 2026 09:08:34 +0000</pubDate>
      <link>https://dev.to/frontendfacile/sqlite-riscritta-in-rust-perche-qualcuno-sta-provando-a-toccare-il-codice-piu-affidabile-che-505g</link>
      <guid>https://dev.to/frontendfacile/sqlite-riscritta-in-rust-perche-qualcuno-sta-provando-a-toccare-il-codice-piu-affidabile-che-505g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Dalla libreria embedded che ha invaso ogni dispositivo a un’implementazione moderna con concorrenza, async I/O e vector search: cosa cambia davvero per chi sviluppa app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nel frontend e nel full‑stack capita spesso di parlare di database come servizi: Postgres gestito, cluster, repliche, connessioni, pooling, credenziali e una lunga lista di “cose che possono rompersi”. Ma esiste un’altra filosofia, più vicina all’idea di “dipendenza” che di “infrastruttura”: un motore SQL che vive &lt;em&gt;dentro&lt;/em&gt; l’applicazione.&lt;/p&gt;

&lt;p&gt;Questa è la ragione per cui SQLite è ovunque. È una libreria, non un server. Legge e scrive su un singolo file su disco. Riduce drasticamente configurazione, porte, processi separati e complessità operativa. Ed è proprio questa semplicità a renderla una delle fondamenta silenziose dell’informatica moderna: la usi in browser, smartphone, desktop app, tool CLI, IoT… spesso senza nemmeno accorgertene.&lt;/p&gt;

&lt;p&gt;Ora immagina di riscrivere tutto da capo, in Rust, cercando di essere compatibile al 100% e allo stesso tempo più “moderna”. Sembra un’idea folle per definizione—finché non inizi a guardare ai limiti pratici che oggi emergono in molte applicazioni.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perché toccare SQLite, se funziona così bene?
&lt;/h2&gt;

&lt;p&gt;SQLite non è “il problema”. Anzi: è considerata estremamente robusta perché è conservativa, minimalista, e custodita con un rigore quasi maniacale.&lt;/p&gt;

&lt;p&gt;Il punto è un altro: il suo modello di sviluppo e manutenzione è atipico rispetto a quello che molti intendono per open source &lt;em&gt;collaborativo&lt;/em&gt;. Il codice è disponibile e utilizzabile liberamente, ma l’evoluzione è guidata da pochissime persone e—di fatto—non segue la dinamica classica delle contribution esterne.&lt;/p&gt;

&lt;p&gt;Questa scelta ha un effetto collaterale positivo: riduce il rischio di regressioni introdotte da cambiamenti non coerenti con la visione del progetto. Ma ha anche un costo: se la tua azienda o il tuo prodotto hanno esigenze nuove (concorrenza più spinta, I/O non bloccante, funzionalità specifiche), “aspettare che arrivi upstream” non è sempre un’opzione.&lt;/p&gt;

&lt;p&gt;Da qui nasce l’idea: costruire un’alternativa che mantenga la compatibilità con SQLite, ma che possa evolvere con un set di priorità diverse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosa significa davvero “drop‑in replacement”
&lt;/h2&gt;

&lt;p&gt;Quando parliamo di database embedded, &lt;em&gt;la fiducia&lt;/em&gt; è tutto. Non basta essere veloci. Non basta avere feature nuove. Il requisito numero uno è: &lt;strong&gt;non perdere mai dati&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Il requisito numero due è: &lt;strong&gt;non costringere gli utenti a riscrivere l’app&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Essere un drop‑in replacement significa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compatibilità con il formato e/o comportamento atteso (SQL, pragma, edge case noti);&lt;/li&gt;
&lt;li&gt;stesse semantiche nei casi limite che la gente dà per scontati da anni;&lt;/li&gt;
&lt;li&gt;integrazione semplice nei binding e nei driver esistenti.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In pratica: “lo sostituisco e funziona” deve valere non solo per l’happy path, ma anche per i percorsi più brutti—quelli che incontrerai in produzione alle 3 di notte.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le tre aree dove una riscrittura può cambiare le regole
&lt;/h2&gt;

&lt;p&gt;Alcune scelte architetturali di SQLite sono volutamente conservative. Funzionano benissimo in tantissimi scenari, ma diventano colli di bottiglia quando l’app cresce o quando cambiano le aspettative.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Concorrenza in scrittura: non solo “un writer alla volta”
&lt;/h3&gt;

&lt;p&gt;Un limite storico di SQLite è il modello in cui, semplificando, &lt;strong&gt;solo uno writer può scrivere alla volta&lt;/strong&gt; sul database. È una scelta coerente con un file singolo e con l’obiettivo di robustezza.&lt;/p&gt;

&lt;p&gt;Un approccio più moderno prova a consentire &lt;strong&gt;più scritture simultanee&lt;/strong&gt; su porzioni diverse dei dati, facendo emergere il conflitto solo quando due operazioni toccano realmente le stesse righe (o la stessa area logica). Se funziona bene, questo cambia parecchio per carichi con:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;molte richieste concorrenti;&lt;/li&gt;
&lt;li&gt;job asincroni in background;&lt;/li&gt;
&lt;li&gt;app locali con più thread/worker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Per un frontend, l’impatto è indiretto ma concreto: API più reattive sotto carico, meno code lato server, meno timeout percepiti in UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) I/O asincrono: evitare di bloccare thread quando si tocca il disco
&lt;/h3&gt;

&lt;p&gt;SQLite tipicamente esegue I/O su disco in modo bloccante: quando legge o scrive, il thread aspetta.&lt;/p&gt;

&lt;p&gt;In architetture moderne (specialmente in ambienti con runtime async), la possibilità di &lt;strong&gt;cedere il controllo durante l’I/O&lt;/strong&gt; aiuta a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;aumentare la capacità di gestire richieste concorrenti;&lt;/li&gt;
&lt;li&gt;ridurre sprechi di thread in attesa;&lt;/li&gt;
&lt;li&gt;migliorare la prevedibilità della latenza.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Per chi lavora con Node.js, Rust, o servizi con event loop, questa differenza non è un dettaglio: è una leva architetturale.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Vector search: embeddings nello stesso database
&lt;/h3&gt;

&lt;p&gt;La svolta “AI‑driven” ha creato un nuovo requisito: &lt;strong&gt;salvare embeddings e cercare i più vicini rapidamente&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La soluzione comune oggi è aggiungere un secondo sistema (vector database o servizio esterno). Funziona, ma raddoppia la complessità:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;due database, due backup strategy;&lt;/li&gt;
&lt;li&gt;due permessi/connessioni;&lt;/li&gt;
&lt;li&gt;sincronizzazione applicativa;&lt;/li&gt;
&lt;li&gt;query che diventano una pipeline di chiamate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Integrare tipi vettoriali e indici nativi significa poter tenere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dati relazionali tradizionali;&lt;/li&gt;
&lt;li&gt;embeddings;&lt;/li&gt;
&lt;li&gt;e query di similarità&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…in un unico file, con un unico linguaggio (SQL) e un unico modello operativo. Per prodotti piccoli/medi—o per edge/desktop/mobile—questa è una semplificazione enorme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il vero problema: guadagnarsi la fiducia (senza 25 anni di storia)
&lt;/h2&gt;

&lt;p&gt;Aggiungere feature è relativamente “facile”. Il difficile è costruire un database che non tradisca mai.&lt;/p&gt;

&lt;p&gt;Qui entra in gioco un’idea molto interessante: &lt;strong&gt;test tramite simulazione deterministica&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Invece di affidarsi solo a test tradizionali, si esegue il database in un ambiente simulato dove puoi controllare tempo e condizioni e, soprattutto, &lt;strong&gt;iniettare guasti riproducibili&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;perdita di alimentazione durante una scrittura;&lt;/li&gt;
&lt;li&gt;pagina corrotta a metà;&lt;/li&gt;
&lt;li&gt;disco che “mente” e conferma un flush che non è avvenuto;&lt;/li&gt;
&lt;li&gt;interruzioni nel momento peggiore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La parte cruciale è la &lt;em&gt;ripetibilità&lt;/em&gt;: stesso seed, stesso scenario, stesso fallimento, fino a quando il bug viene isolato e rimosso. È un modo pragmatico per attaccare il tipo di problemi che non vuoi mai scoprire su un laptop dell’utente o in un POS in negozio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implicazioni pratiche per chi fa frontend (e prodotto)
&lt;/h2&gt;

&lt;p&gt;Anche se “riscrivere un database” sembra lontano dalla UI, le conseguenze arrivano fino al client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Meno dipendenze di sistema&lt;/strong&gt;: un motore embedded con capacità moderne può ridurre il numero di servizi esterni necessari.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline e edge più potenti&lt;/strong&gt;: avere SQL + vector search in locale abilita ricerche semantiche e feature AI senza roundtrip costanti.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prestazioni percepite&lt;/strong&gt;: concorrenza e I/O non bloccante migliorano latenza e throughput dei servizi che alimentano l’interfaccia.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sintesi: una scommessa rischiosa, ma comprensibile
&lt;/h2&gt;

&lt;p&gt;SQLite è diventata “invisibile” perché è affidabile e semplice. Riscriverla è rischioso proprio perché la posta in gioco è massima: i dati.&lt;/p&gt;

&lt;p&gt;Eppure, in un mondo dove servono più concorrenza, integrazione async e funzionalità come la vector search &lt;em&gt;senza&lt;/em&gt; moltiplicare i componenti, la spinta verso un’alternativa compatibile e più evolvibile è naturale.&lt;/p&gt;

&lt;p&gt;La domanda non è tanto se sia una buona idea in assoluto, ma &lt;strong&gt;per quali prodotti&lt;/strong&gt; e &lt;strong&gt;con quali garanzie&lt;/strong&gt;. La differenza la farà la capacità di dimostrare affidabilità nel tempo, con test che cercano attivamente il fallimento—prima che lo faccia la produzione.&lt;/p&gt;




&lt;p&gt;Articolo originale: &lt;a href="https://frontendfacile.it/blog/sqlite-riscritta-in-rust-perche-qualcuno-sta-provando-a-toccare-il-codice-piu-af" rel="noopener noreferrer"&gt;https://frontendfacile.it/blog/sqlite-riscritta-in-rust-perche-qualcuno-sta-provando-a-toccare-il-codice-piu-af&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sqlite</category>
      <category>rust</category>
      <category>databaseembedded</category>
      <category>concorrenza</category>
    </item>
    <item>
      <title>aitm 1.0: a terminal where the AI is a participant, not the driver</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Sat, 20 Jun 2026 07:33:52 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/aitm-10-a-terminal-where-the-ai-is-a-participant-not-the-driver-2nb</link>
      <guid>https://dev.to/kanfu-panda/aitm-10-a-terminal-where-the-ai-is-a-participant-not-the-driver-2nb</guid>
      <description>&lt;p&gt;I was doing AI-assisted coding inside a terminal session. The AI kept modifying files, but I had no way to view those changes in the same window — I had to switch apps, switch context, come back. Every loop through the cycle was an interruption.&lt;/p&gt;

&lt;p&gt;What I wanted was simple: the terminal and the AI and the files, all in the same place, without the context-switching. So I built it.&lt;/p&gt;

&lt;p&gt;That's the origin of aitm. The version 1.0 is that thing, shipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design choice: participant, not driver
&lt;/h2&gt;

&lt;p&gt;Most AI terminals are built around a single model: you describe intent, the AI executes. It's efficient when it works and a bad afternoon when it doesn't.&lt;/p&gt;

&lt;p&gt;aitm draws a different line. The AI can see your environment, read your files, and call tools — but execution is always gated by you. The invariant is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI suggests → you decide → it happens.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In practice: the AI calls &lt;code&gt;list_files&lt;/code&gt;, &lt;code&gt;read_file&lt;/code&gt;, &lt;code&gt;get_terminal_history&lt;/code&gt;, and &lt;code&gt;search_history&lt;/code&gt; automatically. These are read-only. You see the results in the conversation as they come in. But &lt;code&gt;run_command&lt;/code&gt; — anything that changes state — stops the loop and waits for your approval.&lt;/p&gt;

&lt;p&gt;That distinction sounds obvious in retrospect. It wasn't obvious at design time. The first version had a "trust mode" that auto-approved low-risk commands. I removed it. The UX was slightly smoother; the &lt;em&gt;feeling&lt;/em&gt; of being in control was not worth trading away.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09q9xau9w60fa696ykcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09q9xau9w60fa696ykcl.png" alt="The main interface: file tree on the left, terminal in the center, AI sidebar on the right" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Tauri and Rust
&lt;/h2&gt;

&lt;p&gt;Electron was the obvious first option to evaluate. At idle: ~150 MB RAM, several seconds to show the window. Fine for a prototype, not acceptable for something that sits open all day. So Electron was ruled out early.&lt;/p&gt;

&lt;p&gt;The choice was &lt;a href="https://v2.tauri.app/" rel="noopener noreferrer"&gt;Tauri 2&lt;/a&gt; + Rust from the start. Two months to get to something usable. The numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;5.3 MB binary&lt;/strong&gt; (vs 150+ MB Electron)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3–5 ms cold start&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~30 MB RAM at idle&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The React 19 frontend handles the UI. The Rust layer handles the PTY, IPC, tool execution, and security. This matters: the security gates run in Rust, which means the JavaScript/React layer &lt;em&gt;cannot bypass them&lt;/em&gt;. The AI layer sends requests over Tauri IPC; the Rust handler is the one that decides whether a command actually runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four-layer security model
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;run_command&lt;/code&gt; call goes through four sequential gates before it reaches your shell.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L1 — Blocklist regex.&lt;/strong&gt; Hard-coded patterns that always fail. &lt;code&gt;rm -rf /&lt;/code&gt;, the fork bomb &lt;code&gt;:(){ :|:&amp;amp; };:&lt;/code&gt;, &lt;code&gt;dd if=/dev/zero&lt;/code&gt;, and ~50 others. These are commands where "the user confirmed it" is still not enough — the blocklist exists precisely to be unconditional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L2 — Heuristic risk scoring.&lt;/strong&gt; The command string is scored against a set of signals: does it touch &lt;code&gt;/&lt;/code&gt;, use redirection (&lt;code&gt;&amp;gt;&lt;/code&gt;), pipe to &lt;code&gt;sh&lt;/code&gt;, reference system directories? The output is &lt;code&gt;DESTRUCTIVE&lt;/code&gt;, &lt;code&gt;HIGH&lt;/code&gt;, or &lt;code&gt;LOW&lt;/code&gt;. This label shows up in the confirmation dialog so you can see &lt;em&gt;why&lt;/em&gt; something got flagged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L3 — Project scope allowlist.&lt;/strong&gt; Each session has a configured project directory. You can define a &lt;code&gt;globset&lt;/code&gt; — paths and patterns the AI is allowed to operate on. Anything outside scope is flagged before reaching L4. This is opt-in, but it's what makes "AI working on this project" distinct from "AI with access to your whole machine."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L4 — Explicit user confirmation.&lt;/strong&gt; Every &lt;code&gt;run_command&lt;/code&gt; produces a modal: full command text, risk level, scope check result. There is no auto-approve mode and no way to configure one.&lt;/p&gt;

&lt;p&gt;L1 and L2 run synchronously in Rust with no async overhead. L3 uses the &lt;code&gt;globset&lt;/code&gt; crate. L4 is a hard gate in the IPC handler — no call path in the AI layer can reach the shell without passing through it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;run_command request
    │
    ├─ L1: blocklist regex ────────────► REJECT immediately
    │
    ├─ L2: heuristic scoring
    │       DESTRUCTIVE / HIGH / LOW
    │
    ├─ L3: project scope check ────────► flag if out of scope
    │
    └─ L4: confirmation modal ─────────► shell only if approved
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xnnx9cjejklodk69tjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xnnx9cjejklodk69tjv.png" alt="The AI sidebar showing a conversation where the AI has gathered project context" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What else shipped in 1.0
&lt;/h2&gt;

&lt;p&gt;The tool loop and security model are the headline. Everything else in 1.0 was stuff I'd been deferring:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project scope + SQLite persistence.&lt;/strong&gt; Sessions now have a project directory. Conversation history, session state, and config all live in a local SQLite database. Nothing leaves your machine, no account required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Six LLM providers.&lt;/strong&gt; OpenAI, Anthropic, DeepSeek, Qwen (Alibaba DashScope), Zhipu, and Moonshot (Kimi). You can switch per session. The six were chosen for coverage: Western API providers plus the major Chinese providers for users who want lower-latency access from CN.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eight themes, English and Chinese UI.&lt;/strong&gt; The themes are opinionated. There's a dark ink-wash one that I find easier on the eyes during long sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Split-pane CodeMirror editor.&lt;/strong&gt; A file editor built into the window. For quick edits without losing terminal context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS Developer ID notarization.&lt;/strong&gt; The &lt;code&gt;.dmg&lt;/code&gt; is signed and notarized. No Gatekeeper warning on first launch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz71a8kb7mjk1zay1yqyf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz71a8kb7mjk1zay1yqyf.png" alt="The split-pane layout: terminal, file preview, and browser side by side" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F852cnbkjho78pk2o8wxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F852cnbkjho78pk2o8wxt.png" alt="The settings page: appearance, themes, layout, and AI provider configuration" width="799" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's not in 1.0
&lt;/h2&gt;

&lt;p&gt;Windows support exists — CI builds it, I've run it — but macOS is the platform I use daily and where the edge cases are best covered. Windows testing is less thorough.&lt;/p&gt;

&lt;p&gt;There's no streaming AI response in the tool-calling loop. The AI responds after all tool calls complete. In practice the wait is usually under two seconds, but it's a noticeable gap when a sequence involves several reads. I'll revisit this in 1.1.&lt;/p&gt;

&lt;p&gt;Plugin system and user-defined tools are on the roadmap, not here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download
&lt;/h2&gt;

&lt;p&gt;Binary at the &lt;a href="https://github.com/kanfu-panda/aitm/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;GitHub release&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS Apple Silicon&lt;/li&gt;
&lt;li&gt;Windows x86_64&lt;/li&gt;
&lt;li&gt;Windows ARM64&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Source on &lt;a href="https://github.com/kanfu-panda/aitm" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; under Apache 2.0. Issues and discussions are open. If you want to talk about the security model specifically, that's where to do it.&lt;/p&gt;

</description>
      <category>aitm</category>
      <category>terminal</category>
      <category>ai</category>
      <category>rust</category>
    </item>
    <item>
      <title>WebSocket and SSE</title>
      <dc:creator>tengxgfyrz67s</dc:creator>
      <pubDate>Sat, 20 Jun 2026 06:12:33 +0000</pubDate>
      <link>https://dev.to/tengxgfyrz67s/websocket-and-sse-1867</link>
      <guid>https://dev.to/tengxgfyrz67s/websocket-and-sse-1867</guid>
      <description>&lt;h1&gt;
  
  
  WebSocket and SSE in Hyperlane
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Project Code：&lt;a href="https://github.com/hyperlane-dev/hyperlane" rel="noopener noreferrer"&gt;https://github.com/hyperlane-dev/hyperlane&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Hyperlane&lt;/strong&gt; is a lightweight, high-performance, cross-platform Rust HTTP server library built on Tokio. Beyond standard HTTP request-response cycles, Hyperlane provides first-class support for two important real-time communication protocols: WebSocket and Server-Sent Events (SSE). In this article, we will explore how to implement both protocols using Hyperlane's powerful middleware and streaming APIs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction to Real-Time Communication&lt;/li&gt;
&lt;li&gt;WebSocket Protocol Overview&lt;/li&gt;
&lt;li&gt;WebSocket Implementation in Hyperlane&lt;/li&gt;
&lt;li&gt;WebSocket Frame Handling&lt;/li&gt;
&lt;li&gt;Broadcasting with WebSocket&lt;/li&gt;
&lt;li&gt;Server-Sent Events (SSE) Overview&lt;/li&gt;
&lt;li&gt;SSE Implementation in Hyperlane&lt;/li&gt;
&lt;li&gt;Client-Side Code Examples&lt;/li&gt;
&lt;li&gt;WebSocket vs SSE: When to Use Each&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Introduction to Real-Time Communication
&lt;/h2&gt;

&lt;p&gt;Modern web applications often require real-time data delivery — think chat applications, live dashboards, notification systems, and collaborative editing tools. Hyperlane supports two protocols that enable real-time communication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket&lt;/strong&gt;: A full-duplex, bidirectional communication channel over a single TCP connection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSE (Server-Sent Events)&lt;/strong&gt;: A unidirectional channel where the server pushes events to the client over HTTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both protocols are supported through Hyperlane's streaming and middleware APIs, making it straightforward to add real-time capabilities to your application.&lt;/p&gt;




&lt;h2&gt;
  
  
  WebSocket Protocol Overview
&lt;/h2&gt;

&lt;p&gt;WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection. Unlike HTTP, which follows a request-response model, WebSocket allows both the client and server to send messages independently at any time after the initial handshake.&lt;/p&gt;

&lt;p&gt;The connection starts as an HTTP request with an &lt;code&gt;Upgrade: websocket&lt;/code&gt; header. If the server accepts, the protocol is upgraded, and the connection remains open for ongoing message exchange.&lt;/p&gt;




&lt;h2&gt;
  
  
  WebSocket Implementation in Hyperlane
&lt;/h2&gt;

&lt;p&gt;Hyperlane makes it easy to handle WebSocket connections through its middleware system. The key is to use the &lt;code&gt;#[is_ws_upgrade_type]&lt;/code&gt; attribute macro to detect WebSocket upgrade requests and the &lt;code&gt;#[try_get_websocket_request]&lt;/code&gt; macro to extract the WebSocket frame data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic WebSocket Handler
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[route(&lt;/span&gt;&lt;span class="s"&gt;"/ws_upgrade_type"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Websocket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ServerHook&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Websocket&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;Self&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;#[is_ws_upgrade_type]&lt;/span&gt;
    &lt;span class="nd"&gt;#[try_get_websocket_request(body)]&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;body_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseBody&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;WebSocketFrame&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create_frame_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.send_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nn"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Route Registration&lt;/strong&gt;: The &lt;code&gt;#[route("/ws_upgrade_type")]&lt;/code&gt; macro maps the WebSocket endpoint to the &lt;code&gt;Websocket&lt;/code&gt; struct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol Detection&lt;/strong&gt;: The &lt;code&gt;#[is_ws_upgrade_type]&lt;/code&gt; attribute checks whether the incoming request is a WebSocket upgrade request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frame Extraction&lt;/strong&gt;: The &lt;code&gt;#[try_get_websocket_request(body)]&lt;/code&gt; attribute extracts the WebSocket frame data from the request and binds it to the &lt;code&gt;body&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frame Processing&lt;/strong&gt;: &lt;code&gt;WebSocketFrame::create_frame_list(&amp;amp;body)&lt;/code&gt; converts the raw frame data into a list of response frames.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Sending&lt;/strong&gt;: &lt;code&gt;stream.send_list(body_list).await&lt;/code&gt; sends all frames back to the client.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Attribute Macros for Sending
&lt;/h3&gt;

&lt;p&gt;Hyperlane provides several attribute macros for sending data over WebSocket connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[try_send]&lt;/span&gt;
&lt;span class="nd"&gt;#[send]&lt;/span&gt;
&lt;span class="nd"&gt;#[try_flush]&lt;/span&gt;
&lt;span class="nd"&gt;#[flush]&lt;/span&gt;
&lt;span class="nd"&gt;#[closed]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These macros provide fine-grained control over the send operations, including error handling (&lt;code&gt;try_send&lt;/code&gt; vs &lt;code&gt;send&lt;/code&gt;), flushing buffers, and closing connections.&lt;/p&gt;




&lt;h2&gt;
  
  
  WebSocket Frame Handling
&lt;/h2&gt;

&lt;p&gt;WebSocket communication revolves around frames. Each frame contains a small header and a payload. Hyperlane abstracts this complexity through the &lt;code&gt;WebSocketFrame&lt;/code&gt; type and its helper methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Frame Lists
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;body_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseBody&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;WebSocketFrame&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create_frame_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes raw body data and produces a list of &lt;code&gt;ResponseBody&lt;/code&gt; frames ready for transmission. The frame list can then be sent using &lt;code&gt;stream.send_list()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending Frames
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.send_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For individual frame sending, you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.get_mut_response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.try_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.try_send_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;frame_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.try_flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connection Management
&lt;/h3&gt;

&lt;p&gt;After establishing a WebSocket connection, you need to manage its lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.set_closed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;keep_alive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.is_keep_alive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.get_request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.is_enable_keep_alive&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.try_get_http_request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="nf"&gt;.is_ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.get_request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.is_enable_keep_alive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.set_closed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern allows you to keep the connection alive for multiple message exchanges and gracefully close it when needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Broadcasting with WebSocket
&lt;/h2&gt;

&lt;p&gt;A common use case for WebSocket is broadcasting messages to multiple connected clients. While Hyperlane provides the low-level primitives, you can build a broadcast mechanism by maintaining a collection of connected streams and iterating over them to send messages.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hyperlane-broadcast&lt;/code&gt; utility from the recommended tools list is specifically designed for this purpose, making it easy to implement pub/sub patterns with WebSocket connections.&lt;/p&gt;




&lt;h2&gt;
  
  
  Server-Sent Events (SSE) Overview
&lt;/h2&gt;

&lt;p&gt;Server-Sent Events (SSE) is a simpler protocol compared to WebSocket. It allows the server to push events to the client over a standard HTTP connection. SSE is unidirectional — only the server can send messages — but it has several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: SSE uses standard HTTP, so it works with existing infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Reconnection&lt;/strong&gt;: Browsers automatically reconnect if the connection drops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text-Based&lt;/strong&gt;: SSE messages are plain text, making them easy to debug.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SSE is ideal for use cases like live news feeds, stock tickers, progress indicators, and notification streams.&lt;/p&gt;




&lt;h2&gt;
  
  
  SSE Implementation in Hyperlane
&lt;/h2&gt;

&lt;p&gt;Implementing SSE in Hyperlane involves setting the appropriate headers and then streaming events to the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the SSE Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;
    &lt;span class="nf"&gt;.get_mut_response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.set_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONTENT_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEXT_EVENT_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.set_body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.try_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key header is &lt;code&gt;Content-Type: text/event-stream&lt;/code&gt;, which tells the browser to treat the response as an SSE stream. The body is initially empty — events will be sent incrementally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending SSE Events
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data:{i}{HTTP_DOUBLE_BR}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.try_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each event follows the SSE format: &lt;code&gt;data: &amp;lt;message&amp;gt;\n\n&lt;/code&gt;. The &lt;code&gt;HTTP_DOUBLE_BR&lt;/code&gt; constant represents the double newline that marks the end of each event.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSE Event Format Details
&lt;/h3&gt;

&lt;p&gt;A complete SSE event can include several fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;data:&lt;/code&gt;&lt;/strong&gt; — The event payload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;event:&lt;/code&gt;&lt;/strong&gt; — The event type name (optional).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;id:&lt;/code&gt;&lt;/strong&gt; — The event ID for reconnection tracking (optional).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;retry:&lt;/code&gt;&lt;/strong&gt; — The reconnection time in milliseconds (optional).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the example above, we use the simplest form with just the &lt;code&gt;data:&lt;/code&gt; field.&lt;/p&gt;




&lt;h2&gt;
  
  
  Client-Side Code Examples
&lt;/h2&gt;

&lt;p&gt;To complete the picture, here is how a browser client would connect to both WebSocket and SSE endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket Client (JavaScript)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://localhost:8080/ws_upgrade_type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebSocket connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello Server!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Received:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebSocket disconnected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SSE Client (JavaScript)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8080/sse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;eventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SSE Event:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;eventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SSE connection error, reconnecting...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both APIs are built into modern browsers, requiring no additional libraries.&lt;/p&gt;




&lt;h2&gt;
  
  
  WebSocket vs SSE: When to Use Each
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;WebSocket&lt;/th&gt;
&lt;th&gt;SSE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Direction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bidirectional&lt;/td&gt;
&lt;td&gt;Server-to-client only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protocol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ws:// (separate protocol)&lt;/td&gt;
&lt;td&gt;HTTP (standard)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reconnection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual implementation&lt;/td&gt;
&lt;td&gt;Automatic (browser)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Binary Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Text only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Chat, gaming, collaboration&lt;/td&gt;
&lt;td&gt;Feeds, notifications, dashboards&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Choose &lt;strong&gt;WebSocket&lt;/strong&gt; when you need bidirectional communication, binary data support, or low-latency message exchange. Choose &lt;strong&gt;SSE&lt;/strong&gt; when you only need server-to-client push and want simpler implementation with automatic reconnection.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hyperlane provides robust support for both WebSocket and SSE, enabling you to build real-time web applications in Rust. The WebSocket implementation leverages Hyperlane's attribute macros like &lt;code&gt;#[is_ws_upgrade_type]&lt;/code&gt; and &lt;code&gt;#[try_get_websocket_request]&lt;/code&gt; to provide a clean, declarative API for handling WebSocket connections. The SSE implementation uses standard HTTP streaming with the &lt;code&gt;text/event-stream&lt;/code&gt; content type.&lt;/p&gt;

&lt;p&gt;Both protocols have their place in modern web development. WebSocket excels in bidirectional communication scenarios, while SSE shines in simple server-to-client push use cases. By understanding both patterns and leveraging Hyperlane's streaming APIs, you can build responsive, real-time applications that deliver data to users instantly.&lt;/p&gt;

&lt;p&gt;The key building blocks — &lt;code&gt;stream.send()&lt;/code&gt;, &lt;code&gt;stream.try_send()&lt;/code&gt;, &lt;code&gt;stream.send_list()&lt;/code&gt;, and the various attribute macros — give you full control over how data is transmitted, while the middleware system ensures clean separation of concerns between your real-time logic and the rest of your application.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Project Code：&lt;a href="https://github.com/hyperlane-dev/hyperlane" rel="noopener noreferrer"&gt;https://github.com/hyperlane-dev/hyperlane&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>rust</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
