<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://www.yellowduck.be/pretty-atom-feed-v3.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>🐥 YellowDuck.be</title>
  <id>https://www.yellowduck.be/posts/feed</id>
  <updated>2026-11-14T18:00:00Z</updated>
  <author>
    <name>Pieter Claerhout</name>
    <email>pieter@yellowduck.be</email>
  </author>
  <link rel="self" href="https://www.yellowduck.be/posts/feed"/>
  <link rel="alternate" href="https://www.yellowduck.be"/>
  <entry>
    <id>https://www.yellowduck.be/posts/calling-a-rust-crate-from-elixir-with-rustler-and-getting-it-through-ci</id>
    <title>🐥 Calling a Rust crate from Elixir with Rustler (and getting it through CI)</title>
    <updated>2026-11-14T18:00:00Z</updated>
    <published>2026-11-14T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/calling-a-rust-crate-from-elixir-with-rustler-and-getting-it-through-ci"/>
    <content type="html">&lt;p&gt;I wanted a proper &amp;quot;reader mode&amp;quot; for the articles I link to on this blog: fetch a page, strip the navigation, ads, and cookie banners, and keep only the article. In Rust, there's a crate for this called &lt;a href=&quot;https://crates.io/crates/readex&quot;&gt;&lt;code&gt;readex&lt;/code&gt;&lt;/a&gt;, which does exactly that and can even output Markdown.&lt;/p&gt;
&lt;p&gt;My app is Elixir/Phoenix, so the obvious question was: how do I use a Rust crate from Elixir? The answer is &lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;Rustler&lt;/a&gt;, which lets you write NIFs (Native Implemented Functions) in Rust with safe, ergonomic bindings.&lt;/p&gt;
&lt;p&gt;In this post, I'll walk through the whole process, from &lt;code&gt;mix.exs&lt;/code&gt; to a green GitHub Actions pipeline, including the mistakes I made along the way.&lt;/p&gt;
&lt;h1&gt;Prerequisites: Rust and Rustler&lt;/h1&gt;
&lt;p&gt;Rustler compiles your Rust code as part of &lt;code&gt;mix compile&lt;/code&gt;, so you need a Rust toolchain on every machine that builds the project. The easiest way is &lt;a href=&quot;https://rustup.rs&quot;&gt;rustup&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;--proto&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;#39;=https&amp;#39;&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;--tlsv1.2&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;-sSf&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;https://sh.rustup.rs&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;l-function-call&quot;&gt;sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;rustc&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;--version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;cargo&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;--version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add Rustler to your dependencies in &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-comment&quot;&gt;# ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;~&amp;gt; 0.38.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;runtime: &lt;/span&gt;&lt;span class=&quot;l-boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;  &lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;runtime: false&lt;/code&gt; is the right choice here: Rustler is only needed at compile time. The compiled library is loaded by your own module, not by the Rustler application.&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;mix&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;deps.get&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Scaffolding the NIF with &lt;code&gt;mix rustler.new&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Rustler ships with a generator that creates the Cargo project for you:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;mix&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;rustler.new&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It asks for the name of the Elixir module that will host the NIF and the name of the crate. I used &lt;code&gt;YellowduckBe.ArticleExtractor.Native&lt;/code&gt; and &lt;code&gt;article_extractor&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This generates the following:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-plaintext&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;native/article_extractor/&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;├── Cargo.toml&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;├── README.md&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;└── src/&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    └── lib.rs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated &lt;code&gt;Cargo.toml&lt;/code&gt; is where we add the &lt;code&gt;readex&lt;/code&gt; crate:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-toml&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-property&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-property&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;article_extractor&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-property&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;0.1.0&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-property&quot;&gt;authors&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-property&quot;&gt;edition&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;2021&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-property&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;&lt;span class=&quot;l-property&quot;&gt;crate-type&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;cdylib&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-property&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;&lt;span class=&quot;l-property&quot;&gt;rustler&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;0.39.0&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;&lt;span class=&quot;l-property&quot;&gt;readex&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;0.19&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;crate-type = [&amp;quot;cdylib&amp;quot;]&lt;/code&gt; makes Cargo produce a shared library that the BEAM can load.&lt;/p&gt;
&lt;p&gt;You also don't want build artifacts in Git, so add this to &lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-gitignore&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-comment&quot;&gt;# Rust / Rustler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;l-string-special-path&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;l-string-special-path&quot;&gt;native&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;l-character-special&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;l-string-special-path&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;l-string-special-path&quot;&gt;priv&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;l-string-special-path&quot;&gt;native&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;priv/native/&lt;/code&gt; is where Rustler copies the compiled library so that it ends up in your release.&lt;/p&gt;
&lt;h1&gt;Implementing &lt;code&gt;extract_article&lt;/code&gt; in Rust&lt;/h1&gt;
&lt;p&gt;The first version of the NIF was a straightforward mapping of everything &lt;code&gt;readex&lt;/code&gt; returns. Here's the core idea:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;readex&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;extract_with&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Options&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifStruct&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifStruct&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;YellowduckBe.ArticleExtractor.Article&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;14&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;15&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;published_time&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;16&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;17&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;18&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;schedule&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;DirtyCpu&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;19&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;extract_article&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Article&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;20&quot;&gt;    &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Options&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;21&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;include_html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;22&quot;&gt;        &lt;span class=&quot;l-operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Options&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;23&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;24&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;25&quot;&gt;    &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-function-call&quot;&gt;extract_with&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;26&quot;&gt;        &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_err&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;l-keyword-exception&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;{error:?}&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;27&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;28&quot;&gt;    &lt;span class=&quot;l-constant-builtin&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;29&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;30&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;31&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;32&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;33&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;34&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;35&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;36&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;37&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;published_time&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;published_time&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;38&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;39&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;40&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;41&quot;&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;init!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Elixir.YellowduckBe.ArticleExtractor.Native&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few details are worth noting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;#[derive(NifStruct)]&lt;/code&gt;&lt;/strong&gt; with &lt;code&gt;#[module = &amp;quot;...&amp;quot;]&lt;/code&gt; converts the Rust struct into an Elixir struct of that module. No manual encoding or decoding is needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Option&amp;lt;String&amp;gt;&lt;/code&gt;&lt;/strong&gt; becomes either a string or &lt;code&gt;nil&lt;/code&gt; on the Elixir side.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Result&amp;lt;Article, String&amp;gt;&lt;/code&gt;&lt;/strong&gt; becomes &lt;code&gt;{:ok, %Article{}}&lt;/code&gt; or &lt;code&gt;{:error, &amp;quot;reason&amp;quot;}&lt;/code&gt;, so it works with &lt;code&gt;with&lt;/code&gt; and &lt;code&gt;case&lt;/code&gt; as you'd expect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;schedule = &amp;quot;DirtyCpu&amp;quot;&lt;/code&gt;&lt;/strong&gt; is important. Parsing and scoring an HTML document can take a while. A normal NIF that runs for more than about a millisecond blocks a scheduler and hurts the whole VM's latency. Marking it as a dirty CPU NIF runs it on a separate scheduler pool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rustler::init!&lt;/code&gt;&lt;/strong&gt; registers the module the NIF is loaded into. The &lt;code&gt;Elixir.&lt;/code&gt; prefix is how Elixir module names are represented in Erlang.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Exposing it to Elixir&lt;/h1&gt;
&lt;p&gt;On the Elixir side, you need three small pieces. First, the struct that &lt;code&gt;NifStruct&lt;/code&gt; maps to:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;YellowduckBe.ArticleExtractor.Article&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword-function&quot;&gt;defstruct&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:published_time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;  &lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Second, the module that loads the native library and declares the stubs:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;YellowduckBe.ArticleExtractor.Native&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;Rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;otp_app: :yellowduck_be&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;crate: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;article_extractor&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;  &lt;span class=&quot;l-comment&quot;&gt;# Replaced by the NIF once it&amp;#39;s loaded.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;  &lt;span class=&quot;l-keyword-function&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;extract_article&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-comment&quot;&gt;_html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-comment&quot;&gt;_url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;do: &lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;:erlang&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;nif_error&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:nif_not_loaded&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The stub is overridden when the library loads. If you ever see &lt;code&gt;:nif_not_loaded&lt;/code&gt;, the library didn't compile or load.&lt;/p&gt;
&lt;p&gt;And third, a small public module, so the rest of the app doesn't need to know there's a NIF involved:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;YellowduckBe.ArticleExtractor&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;YellowduckBe.ArticleExtractor.Native&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;  &lt;span class=&quot;l-keyword-function&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-module&quot;&gt;Native&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;extract_article&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;  &lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to swap out the implementation or mock it in tests, this is the seam to do it at.&lt;/p&gt;
&lt;h1&gt;Using it from Elixir&lt;/h1&gt;
&lt;p&gt;Using it from a LiveView is a matter of fetching the HTML with &lt;a href=&quot;https://hexdocs.pm/req&quot;&gt;Req&lt;/a&gt; and passing it along:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;body: &lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}}&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;Req&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;       &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;ArticleExtractor&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;page: &lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;  &lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or in an &lt;code&gt;iex -S mix&lt;/code&gt; session:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;body: &lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}}&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;Req&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;https://example.com/some-article&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;YellowduckBe.ArticleExtractor&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;https://example.com/some-article&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;title&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Some article&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;word_count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-number&quot;&gt;1234&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Passing the URL is useful: &lt;code&gt;readex&lt;/code&gt; uses it to resolve relative links and images.&lt;/p&gt;
&lt;h1&gt;Compiling it in CI/CD&lt;/h1&gt;
&lt;p&gt;Everything worked locally, so I pushed it, and the pipeline immediately failed. The GitHub runner didn't know it had to build Rust.&lt;/p&gt;
&lt;p&gt;The fix is to install a Rust toolchain before the Elixir build. I use &lt;a href=&quot;https://github.com/dtolnay/rust-toolchain&quot;&gt;&lt;code&gt;dtolnay/rust-toolchain&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-yaml&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;Install Rust&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-property&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;dtolnay/rust-toolchain@stable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My first attempt added this to the wrong job. My workflow has two jobs that compile the app (one to run the tests, one to build and deploy), and both need Rust. I added it to one, moved it to the other, and finally had to put it in both before the pipeline went green.&lt;/p&gt;
&lt;p&gt;The lesson: &lt;strong&gt;every job that runs &lt;code&gt;mix compile&lt;/code&gt; needs the Rust toolchain.&lt;/strong&gt; Remember this when you add a job later.&lt;/p&gt;
&lt;h1&gt;Caching the Rust build&lt;/h1&gt;
&lt;p&gt;A cold build of a Rust crate with its dependencies takes minutes, far longer than the rest of my pipeline. &lt;a href=&quot;https://github.com/Swatinem/rust-cache&quot;&gt;&lt;code&gt;Swatinem/rust-cache&lt;/code&gt;&lt;/a&gt; caches the Cargo registry and the &lt;code&gt;target&lt;/code&gt; directory, keyed on your &lt;code&gt;Cargo.lock&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-yaml&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;Install Rust&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-property&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;dtolnay/rust-toolchain@stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;Setup Rust cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;  &lt;span class=&quot;l-property&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;Swatinem/rust-cache@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;  &lt;span class=&quot;l-property&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;    &lt;span class=&quot;l-property&quot;&gt;workspaces&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;native/article_extractor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;workspaces&lt;/code&gt; option matters: by default, the action looks for &lt;code&gt;Cargo.toml&lt;/code&gt; in the repository root. Since the crate lives in &lt;code&gt;native/article_extractor&lt;/code&gt;, I have to tell it where to look.&lt;/p&gt;
&lt;p&gt;While I was there, I also added &lt;code&gt;restore-keys&lt;/code&gt; to the existing caches for &lt;code&gt;_build&lt;/code&gt; and &lt;code&gt;deps&lt;/code&gt;. Without them, a changed &lt;code&gt;mix.lock&lt;/code&gt; means a full cache miss. With them, the most recent cache with the same prefix is restored, and only what changed gets rebuilt:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-yaml&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;Cache compiled build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-property&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;actions/cache@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;  &lt;span class=&quot;l-property&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-property&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;_build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;${{ runner.os }}-mix-build-${{ hashFiles(&amp;#39;**/mix.lock&amp;#39;) }}-${{ hashFiles(&amp;#39;**/.tool-versions&amp;#39;) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-property&quot;&gt;restore-keys&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-string&quot;&gt;      ${{ runner.os }}-mix-build-&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also replaced the &lt;code&gt;UBUNTU_VERSION&lt;/code&gt; variable in the cache keys with &lt;code&gt;runner.os&lt;/code&gt;, the built-in way to key a cache by platform.&lt;/p&gt;
&lt;h1&gt;The gotcha: force a recompile so the NIF is rebuilt&lt;/h1&gt;
&lt;p&gt;This one cost me the most time. The pipeline was green, the caches worked, and then the app crashed at runtime with &lt;code&gt;:nif_not_loaded&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here's what happens:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Rustler compiles the crate and copies the library into &lt;code&gt;priv/native/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priv/native/&lt;/code&gt; is in &lt;code&gt;.gitignore&lt;/code&gt;, so it isn't in the checkout.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_build&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; restored from cache, including the compiled &lt;code&gt;.beam&lt;/code&gt; file for &lt;code&gt;YellowduckBe.ArticleExtractor.Native&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Mix sees that nothing changed in the Elixir sources, concludes the app is up to date, and skips compiling it. The Rust compiler never runs, so &lt;code&gt;priv/native/&lt;/code&gt; stays empty.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The cache gave me stale Elixir bytecode without the native library it needs. The fix is to delete the compiled output of just &lt;em&gt;my&lt;/em&gt; app (not the dependencies, which are the expensive part) before compiling:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-yaml&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;Force recompile of the app (rebuilds the Rust NIF into priv/native)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-property&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-function-call&quot;&gt;&lt;span class=&quot;l-string&quot;&gt;rm&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;_build/&lt;/span&gt;${{ env.MIX_ENV &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;/lib/yellowduck_be&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now Mix has to recompile the app, which invokes the Rustler compiler. The Rust build is already cached by &lt;code&gt;rust-cache&lt;/code&gt;, and Rustler copies the library into &lt;code&gt;priv/native/&lt;/code&gt;. You get the caching benefits and a correct build.&lt;/p&gt;
&lt;h1&gt;Adding Markdown support&lt;/h1&gt;
&lt;p&gt;Once everything was running, I considered what I actually wanted to display. Plain text loses all the structure, and raw HTML needs sanitising. &lt;code&gt;readex&lt;/code&gt; has &lt;code&gt;extract_to_markdown&lt;/code&gt;, which returns the clean article as Markdown, making it easy to render with an Elixir Markdown library.&lt;/p&gt;
&lt;p&gt;I also simplified the struct: I dropped the fields I wasn't using (&lt;code&gt;canonical_url&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;categories&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;), replaced the optional &lt;code&gt;html&lt;/code&gt; with the &lt;code&gt;original_html&lt;/code&gt; I was handed, and added &lt;code&gt;markdown&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;readex&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;extract_to_markdown&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extract_with&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Options&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifStruct&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifStruct&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;YellowduckBe.ArticleExtractor.Article&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;original_html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;14&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;15&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;16&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;published_time&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;17&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;18&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;19&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;schedule&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;DirtyCpu&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;20&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;extract_article&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Article&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;21&quot;&gt;    &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Options&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;22&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;23&quot;&gt;    &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-function-call&quot;&gt;extract_with&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;24&quot;&gt;        &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_err&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;l-keyword-exception&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;{error:?}&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;25&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;26&quot;&gt;    &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-function-call&quot;&gt;extract_to_markdown&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;27&quot;&gt;        &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_err&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;l-keyword-exception&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;{error:?}&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;28&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;29&quot;&gt;    &lt;span class=&quot;l-constant-builtin&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;30&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;31&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;original_html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;32&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;33&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;34&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;35&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;36&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;37&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;38&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;39&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;published_time&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;extracted&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;published_time&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;40&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;41&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;42&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;43&quot;&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;init!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Elixir.YellowduckBe.ArticleExtractor.Native&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Elixir struct must match, since &lt;code&gt;NifStruct&lt;/code&gt; expects the fields to match:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;YellowduckBe.ArticleExtractor.Article&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword-function&quot;&gt;defstruct&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:original_html&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:markdown&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:text&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:word_count&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:language&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:byline&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:excerpt&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:site_name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;    &lt;span class=&quot;l-string-special-symbol&quot;&gt;:published_time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;  &lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;14&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the LiveView template, I can render it with &lt;a href=&quot;https://hexdocs.pm/mdex&quot;&gt;MDEx&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-heex&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-tag-delimiter&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-tag&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;l-tag-attribute&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;&lt;span class=&quot;l-string&quot;&gt;readability-content&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-tag-attribute&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;&lt;span class=&quot;l-string&quot;&gt;prose max-w-none dark:prose-invert&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-tag-delimiter&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-tag-delimiter&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;safe_html&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MDEx&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;to_html!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;l-tag-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-tag-delimiter&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;l-tag&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;l-tag-delimiter&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this extracts the article twice (once for the metadata, once for the Markdown). For my use case, the cost is negligible, and the code stays simple. If this ever shows up in a profile, it's the first thing I'd look at.&lt;/p&gt;
&lt;p&gt;The Rust part was the easy bit. Rustler's derive macros make the boundary between Rust and Elixir nearly invisible, and dirty schedulers keep long-running work from hurting the VM.&lt;/p&gt;
&lt;p&gt;The real work was in the pipeline:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every job that compiles the app needs a &lt;strong&gt;Rust toolchain&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;rust-cache&lt;/code&gt;&lt;/strong&gt; with &lt;code&gt;workspaces&lt;/code&gt; pointing at your crate.&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;&lt;code&gt;restore-keys&lt;/code&gt;&lt;/strong&gt; to your Mix caches so a small change doesn't trigger a full rebuild.&lt;/li&gt;
&lt;li&gt;When you cache &lt;code&gt;_build&lt;/code&gt;, &lt;strong&gt;force a recompile of your own app&lt;/strong&gt;, or the NIF never gets built into &lt;code&gt;priv/native&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the result is a dependable article extractor in about 40 lines of Rust, running inside my Phoenix app with no extra services to run.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/rust&quot;&gt;#rust&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/elixir&quot;&gt;#elixir&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/phoenix&quot;&gt;#phoenix&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/github&quot;&gt;#github&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/human-pr-review-is-next</id>
    <title>🔗 Human PR review is next</title>
    <updated>2026-11-14T14:00:00Z</updated>
    <published>2026-11-14T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/human-pr-review-is-next"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Writing code went first. Reviewing it looks like it's going the same way. William Martin articulates the evolving landscape of code review, drawing parallels with the shift from manual coding to AI-assisted writing. He suggests that the future of review may lie in utilizing AI tools to automate the process, drastically reducing the need for line-by-line scrutiny. Current practices, traditionally grounded in human oversight, are being challenged as developers adapt to more advanced models. Martin counters common objections about AI-generated code, emphasizing that iterative improvements and automated checks can lead to better outcomes than solely relying on human reviewers. The article concludes by urging engineers to rethink review methodologies, highlighting the importance of rules and guardrails before the code, to maintain quality amidst increasing speed.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://scienceisneato.substack.com/p/human-pr-review-is-next&quot;&gt;Continue reading on &lt;strong&gt;scienceisneato.substack.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/ai&quot;&gt;#ai&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/portman-your-friendly-port-manager</id>
    <title>🔗 Portman: Your friendly port manager</title>
    <updated>2026-11-14T09:00:00Z</updated>
    <published>2026-11-14T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/portman-your-friendly-port-manager"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Portman gives macOS users a straightforward way to manage their local TCP ports. With a single command, &lt;code&gt;portman &amp;lt;port&amp;gt;&lt;/code&gt;, it identifies which process is using a specific port, letting developers quickly resolve conflicts. This tool, built in Go, can be installed easily via Homebrew, and it works by utilizing &lt;code&gt;lsof&lt;/code&gt; to retrieve process details. Whether working with Apple Silicon or Intel Macs, Portman is designed to streamline the troubleshooting of port issues in development environments. The initial release, v0.1.0, already sets the groundwork, with future updates planned for more capabilities, including JSON output and Linux support. This project not only demonstrates practical development but also enhances CLI design knowledge for the creator.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://arps18.github.io/portman/&quot;&gt;Continue reading on &lt;strong&gt;arps18.github.io&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/golang&quot;&gt;#golang&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/tools&quot;&gt;#tools&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/terminal&quot;&gt;#terminal&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/mac&quot;&gt;#mac&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/why-i-think-we-should-write-our-own-pr-descriptions</id>
    <title>🔗 Why I think we should write our own PR descriptions</title>
    <updated>2026-11-13T18:00:00Z</updated>
    <published>2026-11-13T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/why-i-think-we-should-write-our-own-pr-descriptions"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Writing pull request descriptions should be a responsibility of developers, even when agents handle most of the implementation. It encourages understanding of the changes being reviewed and provides necessary context for human reviewers. The article argues that while tools like Claude and Codex can generate comprehensive descriptions, they can lack the personal touch and insights that come from the developer directly involved with the code.&lt;/p&gt;
&lt;p&gt;The author emphasizes that a PR description should clarify why a change exists and how it fits into the broader project, rather than just detailing what was changed. By taking ownership of the PR description, developers not only ensure clarity for reviewers but also maintain a connection to the code being produced. This approach fosters a better understanding of the work being done and reinforces individual accountability in the development process.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://laravel.com/blog/why-i-think-we-should-write-our-own-pr-descriptions&quot;&gt;Continue reading on &lt;strong&gt;laravel.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/ai&quot;&gt;#ai&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/git&quot;&gt;#git&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/git-mastery-intermediate-and-professional-workflows</id>
    <title>🔗 Git mastery: Intermediate and professional workflows</title>
    <updated>2026-11-13T14:00:00Z</updated>
    <published>2026-11-13T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/git-mastery-intermediate-and-professional-workflows"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;You push a feature branch on Friday, and by Monday, the history looks like a shuffled deck of cards. Git transitions from simply being a tool for &lt;code&gt;git commit&lt;/code&gt; and &lt;code&gt;git push&lt;/code&gt; to something that requires real understanding. This article by Arpan Patel delves into advanced Git concepts crucial for maintaining a clean workflow. It covers key techniques like interactive rebase for cleaning up history, the importance of reflog for recovery, effective branching strategies, and how to utilize &lt;code&gt;git bisect&lt;/code&gt; for regression debugging. By mastering these workflows, developers can regain control over their commits and work seamlessly in collaborative environments. This guide encapsulates the essentials for elevating one's Git skills from basic to expert.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://arps18.github.io/posts/git-mastery-intermediate-professional-workflows/&quot;&gt;Continue reading on &lt;strong&gt;arps18.github.io&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/git&quot;&gt;#git&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/misconceptions-about-rss</id>
    <title>🔗 Misconceptions about RSS</title>
    <updated>2026-11-13T09:00:00Z</updated>
    <published>2026-11-13T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/misconceptions-about-rss"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Are misconceptions about RSS causing it to be underestimated in today’s digital landscape? Robert Alexander attempts to clarify common misconceptions regarding RSS, highlighting its significant presence across platforms like YouTube, Reddit, and podcasting. He addresses myths such as RSS being niche or dying, as well as the false belief in its poor discoverability. The article argues that RSS remains powerful, proving essential for timely updates across various content types, from job listings to weather reports. Alexander points out the ongoing evolution and innovation within the RSS ecosystem, challenging the notion that RSS has stagnated. The piece invites readers to recognize the value of RSS as a tool that empowers users in a media landscape often dominated by companies prioritizing advertisements over genuine content.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://alexsci.com/blog/misconceptions-about-rss/&quot;&gt;Continue reading on &lt;strong&gt;alexsci.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/tools&quot;&gt;#tools&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/passing-maps-and-enums-with-rust-nifs-in-elixir</id>
    <title>🐥 Passing Maps and Enums with Rust NIFs in Elixir</title>
    <updated>2026-11-12T18:00:00Z</updated>
    <published>2026-11-12T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/passing-maps-and-enums-with-rust-nifs-in-elixir"/>
    <content type="html">&lt;p&gt;In addition to structs, you can pass &lt;strong&gt;maps&lt;/strong&gt; and &lt;strong&gt;enums&lt;/strong&gt; between Elixir and Rust when writing Native Implemented Functions (NIFs) with Rustler. This gives you flexibility when working with more dynamic or variant data.&lt;/p&gt;
&lt;h1&gt;Passing maps from Elixir to Rust&lt;/h1&gt;
&lt;p&gt;Elixir maps can be received in Rust as &lt;code&gt;MapIterator&lt;/code&gt;s or &lt;code&gt;HashMap&lt;/code&gt;s, or decoded into Rust structs.&lt;/p&gt;
&lt;h2&gt;Example: reading keys from a map&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;MapIterator&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifResult&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifResult&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-type&quot;&gt;MapIterator&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;        &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;ok_or&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;BadArg&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;        &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-character-special&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;        &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;b&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Example: decoding into a Rust struct&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifMap&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifResult&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifMap&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;GreetUser&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;user_term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifResult&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;    &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;GreetUser&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;user_term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;    &lt;span class=&quot;l-constant-builtin&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-keyword-exception&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Hello, {} (age {})&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Alice&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Hello, Alice (age 30)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Passing enums from Elixir to Rust&lt;/h1&gt;
&lt;p&gt;Enums can be passed using tagged maps or atoms.&lt;/p&gt;
&lt;h2&gt;Rust enum:&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifMap&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifMap&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Rectangle&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;    &lt;span class=&quot;l-constant&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;14&quot;&gt;    &lt;span class=&quot;l-constant&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;15&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;16&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;17&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Decoder&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;18&quot;&gt;    &lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifResult&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;19&quot;&gt;        &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Atom&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;from_str&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;get_env&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;20&quot;&gt;        &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;ty&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_get&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;21&quot;&gt;        &lt;span class=&quot;l-keyword-conditional&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;ty&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;as_str&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;22&quot;&gt;            &lt;span class=&quot;l-string&quot;&gt;&amp;quot;Circle&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Shape&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;23&quot;&gt;            &lt;span class=&quot;l-string&quot;&gt;&amp;quot;Rectangle&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Shape&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;24&quot;&gt;            &lt;span class=&quot;l-character-special&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;BadArg&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;25&quot;&gt;        &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;26&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;27&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Function using the enum:&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Shape&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;f64&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-keyword-conditional&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;shape&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;        &lt;span class=&quot;l-type&quot;&gt;Shape&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;consts&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;        &lt;span class=&quot;l-type&quot;&gt;Shape&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Rectangle&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Elixir usage:&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Circle&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;radius: &lt;/span&gt;&lt;span class=&quot;l-number-float&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-number-float&quot;&gt;28.274333882308138&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Rectangle&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;width: &lt;/span&gt;&lt;span class=&quot;l-number-float&quot;&gt;4.0&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;height: &lt;/span&gt;&lt;span class=&quot;l-number-float&quot;&gt;5.0&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-number-float&quot;&gt;20.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Returning maps and enums from Rust to Elixir&lt;/h1&gt;
&lt;p&gt;To return dynamic structures like maps from Rust, construct them using &lt;code&gt;Env&lt;/code&gt; and Rustler's term constructors.&lt;/p&gt;
&lt;h2&gt;Returning a map:&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Env&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifResult&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;status_map&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Env&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifResult&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-keyword-conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;ok&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;l-keyword-conditional&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_new&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_put&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;status_map&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;status&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Returning an enum as a tagged map&lt;/h2&gt;
&lt;p&gt;You can define a Rust enum and implement &lt;code&gt;Encoder&lt;/code&gt; for it:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Encoder&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Env&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Response&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-constant&quot;&gt;Success&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;    &lt;span class=&quot;l-constant&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;&lt;span class=&quot;l-comment&quot;&gt;// Elixir side:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;&lt;span class=&quot;l-comment&quot;&gt;//   %{&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;success&amp;quot;, &amp;quot;result&amp;quot; =&amp;gt; &amp;quot;done&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;&lt;span class=&quot;l-comment&quot;&gt;//   %{&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;error&amp;quot;, &amp;quot;reason&amp;quot; =&amp;gt; &amp;quot;...&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Encoder&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Response&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;    &lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-variable-builtin&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Env&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-attribute&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;        &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;pairs&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-type-builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;l-type-builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-keyword-conditional&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;l-variable-builtin&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;14&quot;&gt;            &lt;span class=&quot;l-type&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Success&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-keyword-exception&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;success&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;15&quot;&gt;            &lt;span class=&quot;l-type&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;reason&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-keyword-exception&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;16&quot;&gt;        &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;17&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;18&quot;&gt;        &lt;span class=&quot;l-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;l-keyword-modifier&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_new&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;19&quot;&gt;        &lt;span class=&quot;l-keyword-repeat&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-keyword-repeat&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;pairs&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;20&quot;&gt;            &lt;span class=&quot;l-comment&quot;&gt;// String keys/values encode to Elixir binaries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;21&quot;&gt;            &lt;span class=&quot;l-variable&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;map_put&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;22&quot;&gt;        &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;23&quot;&gt;        &lt;span class=&quot;l-variable&quot;&gt;map&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;24&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;25&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;26&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;27&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;28&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;status_map&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Response&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;29&quot;&gt;    &lt;span class=&quot;l-keyword-conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;30&quot;&gt;        &lt;span class=&quot;l-type&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Success&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;to_string&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;31&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;l-keyword-conditional&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;32&quot;&gt;        &lt;span class=&quot;l-type&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-constant&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;l-variable-member&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-keyword-exception&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;unexpected code {}&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;33&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;34&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows you to return tagged maps like:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;success&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;result&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;status_map&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;result&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;success&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;status_map&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;reason&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;unexpected code 500&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Handling invalid input&lt;/h1&gt;
&lt;p&gt;Instead of calling &lt;code&gt;.unwrap()&lt;/code&gt;, return a safe error from your NIF:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Atom&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;NifMap&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;atoms!&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-variable&quot;&gt;invalid_user_struct&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifMap&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;GreetUser&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;safe_greet&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;user_term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Atom&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;14&quot;&gt;    &lt;span class=&quot;l-keyword-conditional&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;user_term&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;GreetUser&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;&amp;gt;()&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;15&quot;&gt;        &lt;span class=&quot;l-constant-builtin&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-keyword-exception&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Hello, {}&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;16&quot;&gt;        &lt;span class=&quot;l-constant-builtin&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-character-special&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-constant-builtin&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;invalid_user_struct&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;17&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;18&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Elixir:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;safe_greet&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Bob&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:ok&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;Hello, Bob&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;safe_greet&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;bad: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;input&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:error&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;:invalid_user_struct&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/rust&quot;&gt;#rust&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/elixir&quot;&gt;#elixir&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/the-system-around-the-code</id>
    <title>🔗 The system around the code</title>
    <updated>2026-11-12T14:00:00Z</updated>
    <published>2026-11-12T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/the-system-around-the-code"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Many organizations experience an enthusiasm deflation when it comes to implementing the latest AI solutions. Zarar Siddiqi highlights that while dazzling demos captivate many, the harder truth involves the systems surrounding code rather than the code itself. Years of experience remind us that the path to deployment is often clouded by structural and organizational issues. A key example cited is an incident in which a developer's mistake was mischaracterized as an AI problem when in fact, the issue stemmed from poor engineering practices. This article emphasizes the importance of understanding these systems and structures to avoid repeating past mistakes. Siddiqi addresses how the transition to AI requires a focus on building robust systems that can manage increased complexity rather than merely implementing AI tools without consideration for their context and impact.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://bitbytebit.substack.com/p/the-system-around-the-code&quot;&gt;Continue reading on &lt;strong&gt;bitbytebit.substack.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/ai&quot;&gt;#ai&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/stop-resolving-the-same-git-conflict-twice</id>
    <title>🔗 Stop resolving the same Git conflict twice</title>
    <updated>2026-11-12T09:00:00Z</updated>
    <published>2026-11-12T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/stop-resolving-the-same-git-conflict-twice"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;A merge conflict is annoying once. Resolving the same one again on the next rebase feels like Git charging rent on a decision already made.&lt;/p&gt;
&lt;p&gt;Git has a little-known feature for this: &lt;code&gt;rerere&lt;/code&gt;, short for “reuse recorded resolution.” When enabled, it can remember how a conflict was resolved and reuse that fix when that conflict arises again. Simply turn it on by using &lt;code&gt;git config --global rerere.enabled true&lt;/code&gt;. After resolving a conflict and committing it, &lt;code&gt;rerere&lt;/code&gt; can automatically apply the previously recorded fix the next time the same conflict comes up, which is particularly useful when merging upstream changes frequently.&lt;/p&gt;
&lt;p&gt;However, it’s crucial to inspect the result of any automatic resolution, as &lt;code&gt;rerere&lt;/code&gt; only remembers the textual resolution, not the intent. If a remembered fix is inappropriate, you can use &lt;code&gt;git rerere forget file_to_add.py&lt;/code&gt; to erase that resolution and resolve the conflict anew.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://code.geohack.top/post/stop-resolving-the-same-git-conflict-twice&quot;&gt;Continue reading on &lt;strong&gt;code.geohack.top&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/git&quot;&gt;#git&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/mapsets-a-set-thats-secretly-a-map</id>
    <title>🔗 MapSets: A set that's secretly a map</title>
    <updated>2026-11-11T18:00:00Z</updated>
    <published>2026-11-11T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/mapsets-a-set-thats-secretly-a-map"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;What if a set could be more than just a collection of items? In the article, Bruce Tate sheds light on &lt;code&gt;MapSet&lt;/code&gt;, revealing its hidden map structure and how it utilizes maps for efficient membership checks. He explains that &lt;code&gt;MapSet&lt;/code&gt; allows for quick lookups like traditional maps, but provides set functionality where order doesn't matter and duplicates are ignored. Readers learn how to create sets, check for membership, and effectively manage expected behaviors when working with &lt;code&gt;MapSet&lt;/code&gt;, all while emphasizing the importance of the underlying map data structure. By understanding these concepts, developers can choose better data structures for various scenarios, enhancing both performance and clarity in their Elixir applications.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://grox.io/blog/55-mapsets-a-set-that-s-secretly-a-map/&quot;&gt;Continue reading on &lt;strong&gt;grox.io&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/database&quot;&gt;#database&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/elixir&quot;&gt;#elixir&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/a-modern-web-app-in-c</id>
    <title>🔗 A modern web app in C</title>
    <updated>2026-11-11T14:00:00Z</updated>
    <published>2026-11-11T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/a-modern-web-app-in-c"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;The decline of CGI in web development seemed set in stone in 2004, but in 2026 it's being reconsidered. Corey Prophitt highlights how he successfully built and launched a modern web application using C and CGI, showcasing a minimalistic stack including OpenBSD, SQLite, and essential libraries like &lt;code&gt;libcurl&lt;/code&gt; and &lt;code&gt;libsodium&lt;/code&gt;. This approach emphasizes the advantages of simplicity, low overhead, and fewer dependencies, making it possible to deliver a robust product without the complexities of modern frameworks. Prophitt argues that writing a CGI application today is feasible and effective, allowing developers to lean on their knowledge of HTTP without the burden of additional APIs. The article offers a glimpse into how leveraging timeless technologies can yield practical, less risky solutions in contemporary development.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://prophitt.me/writing/a-modern-web-app-in-c&quot;&gt;Continue reading on &lt;strong&gt;prophitt.me&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/database&quot;&gt;#database&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/tools&quot;&gt;#tools&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/http&quot;&gt;#http&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/my-ai-policy</id>
    <title>🔗 My AI policy</title>
    <updated>2026-11-11T09:00:00Z</updated>
    <published>2026-11-11T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/my-ai-policy"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;What happens when developers grapple with LLMs and community standards? This article tackles the challenges of expressing a personal stance on AI, balancing professional tools with ethical concerns. The author shares his journey and reflections on using LLMs to complement his work while confronting the larger issues of AI company practices. He questions the morality behind mass training on public content, highlighting the disconnect between content creators and the companies that profit from their work. As the web community faces increasing scrutiny over technology choices, he advocates for building a supportive environment instead of shaming others for their decisions. Whether discussing the ethics of AI or the pressures of public opinion, the piece provides a candid insight into the current landscape of development and AI integration.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://remysharp.com/2026/10/12/my-ai-policy&quot;&gt;Continue reading on &lt;strong&gt;remysharp.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/ai&quot;&gt;#ai&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/passing-structs-with-a-rust-nif-in-elixir</id>
    <title>🐥 Passing Structs with a Rust NIF in Elixir</title>
    <updated>2026-11-10T18:00:00Z</updated>
    <published>2026-11-10T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/passing-structs-with-a-rust-nif-in-elixir"/>
    <content type="html">&lt;p&gt;When using Rust NIFs in Elixir via the &lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;Rustler&lt;/a&gt; crate, it's often useful to pass structured data, not just integers and strings. This post shows how to pass an Elixir struct to Rust, manipulate it, and return a new struct to Elixir.&lt;/p&gt;
&lt;h1&gt;Define a struct in Elixir&lt;/h1&gt;
&lt;p&gt;Start by creating a simple struct, such as &lt;code&gt;User&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif.User&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword-function&quot;&gt;defstruct&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;:age&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Define the same struct in Rust&lt;/h1&gt;
&lt;p&gt;In your NIF crate (&lt;code&gt;native/my_nif/src/lib.rs&lt;/code&gt;), define a matching Rust struct using Rustler's &lt;code&gt;NifStruct&lt;/code&gt; derive macro:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifStruct&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;NifStruct&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;MyNif.User&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;    &lt;span class=&quot;l-variable-member&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;#[module = &amp;quot;MyNif.User&amp;quot;]&lt;/code&gt; attribute tells Rustler how to map the Elixir struct to the Rust struct.&lt;/p&gt;
&lt;h1&gt;Write a NIF function that uses the struct&lt;/h1&gt;
&lt;p&gt;Here's a Rust NIF that increases a user's age:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;birthday&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-type&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;        &lt;span class=&quot;l-variable-member&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-variable-member&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;        &lt;span class=&quot;l-operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Register the function:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;init!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Elixir.MyNif&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Wire it up in Elixir&lt;/h1&gt;
&lt;p&gt;In your wrapper module:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;Rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;otp_app: :my_nif_app&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;crate: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;my_nif&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;  &lt;span class=&quot;l-keyword-function&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;birthday&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-comment&quot;&gt;_user&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;do: &lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;:erlang&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;nif_error&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:nif_not_loaded&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Call it from IEx&lt;/h1&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;$ &lt;span class=&quot;l-function-call&quot;&gt;iex&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;S&lt;/span&gt; mix&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;iex&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;MyNif.User&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Alice&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;29&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-variable&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;birthday&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;MyNif.User&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Alice&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;age: &lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Notes&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Fields must match exactly between Elixir and Rust.&lt;/li&gt;
&lt;li&gt;Rustler will raise a badarg error if field names or types don't match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NifStruct&lt;/code&gt; automatically handles encoding and decoding using &lt;code&gt;serde&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/rust&quot;&gt;#rust&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/elixir&quot;&gt;#elixir&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/im-sorry-but-you-still-have-to-think</id>
    <title>🔗 I'm sorry, but you still have to think.</title>
    <updated>2026-11-10T14:00:00Z</updated>
    <published>2026-11-10T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/im-sorry-but-you-still-have-to-think"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;DHH, the creator of Ruby on Rails, chose to rewrite Campfire Once from Ruby on Rails to Rust, relying on a developer to handle the Rust code due to his discomfort with it. This decision, along with rewrites in languages like Elixir and Go, offers insight into the challenges faced by those using AI agents for coding without understanding the code themselves. The results weren't promising; they highlighted the necessity of specificity in prompts, as many programming decisions come down to subjective choices. While Elixir's version stayed closer to the original Rails architecture, both rewrites exhibited significant trade-offs. Rust payments weak performance in certain aspects, including a low new post delivery rate under heavy load due to its limited broadcast channel capacity. The comparative analysis emphasizes that programming decisions are complex and a single metric doesn’t tell the whole story. Ultimately, it reinforces the importance of thoughtful coding practices and understanding the nuances of each programming language's features and limitations.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://itsallaboutthebit.com/i-am-sorry-but-you-still-have-to-think/&quot;&gt;Continue reading on &lt;strong&gt;itsallaboutthebit.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/rust&quot;&gt;#rust&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/ai&quot;&gt;#ai&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/ive-been-the-sole-developer-of-a-healthcare-membership-platform-for-6-years-heres-what-it-looks-like</id>
    <title>🔗 I've been the sole developer of a healthcare membership platform for 6+ years. Here's what it looks like.</title>
    <updated>2026-11-10T09:00:00Z</updated>
    <published>2026-11-10T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/ive-been-the-sole-developer-of-a-healthcare-membership-platform-for-6-years-heres-what-it-looks-like"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;What does a healthcare membership platform look like after six years of sole development? Tim Kamanin shares insights from building a system that integrates member applications, payments, event management, and more using Django and Wagtail CMS. Initially created to address a pressing need, the platform has grown into a robust tool handling memberships, communications, and exams seamlessly. Key features include automatic status tracking, an internal email system, and independent management of events—allowing non-technical staff to efficiently handle operations. This article explains how Kamanin maintains a monolithic codebase with a simple frontend while staying attuned to every line of code and business rule. He highlights the advantages of being the sole developer: quick adaptations, clean code, and deep familiarity with the platform's architecture. A testament to streamlined software development in the healthcare sector, his experience illustrates the value of dedicated ownership in tech projects.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://timonweb.com/case-study/ive-been-the-sole-developer-of-a-healthcare-membership-platform-for-6-years-heres-what-it-looks-like/&quot;&gt;Continue reading on &lt;strong&gt;timonweb.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/database&quot;&gt;#database&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/django&quot;&gt;#django&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/wagtail&quot;&gt;#wagtail&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/review-fatigue-is-real-heres-what-my-team-did-about-it</id>
    <title>🔗 Review fatigue is real. Here's what my team did about it</title>
    <updated>2026-11-09T18:00:00Z</updated>
    <published>2026-11-09T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/review-fatigue-is-real-heres-what-my-team-did-about-it"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Reviewing pull requests (PRs) can often take longer than writing the code itself. This phenomenon, highlighted by Ivan Pelivanovic, emphasizes that even as AI tools facilitate quicker coding, they don't necessarily streamline the review process. The increasing speed of code deployment can lead to an overwhelming volume of reviews, resulting in a state of review fatigue that teams struggle to manage. This article explores strategies some teams have implemented to tackle this issue, ensuring that code quality and thoroughness don't suffer in the rush to deliver results.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://shiftmag.dev/review-fatigue-12276/&quot;&gt;Continue reading on &lt;strong&gt;shiftmag.dev&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/git&quot;&gt;#git&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/why-mcp-was-always-a-bad-idea</id>
    <title>🔗 Why MCP was always a bad idea</title>
    <updated>2026-11-09T14:00:00Z</updated>
    <published>2026-11-09T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/why-mcp-was-always-a-bad-idea"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;MCP was hailed as a necessary protocol when released by Anthropic in 2024, but the landscape has drastically changed. As LLMs became adept at executing code and autonomously calling APIs, MCP began to feel redundant. While it facilitated early integrations between AI models and external services, the evolution of these models means they can now interact directly with APIs without reliance on MCP, which often wraps existing services. The recent emergence of Cloudflare's Code Mode exemplifies how LLMs have outpaced the capabilities offered by MCP, composing scripts directly and omitting the need for intermediary servers. The article argues for a shift towards direct use of HTTP APIs and standard practices. Standardization could streamline interactions, making agents more efficient than ever before. Thus, embracing closure on MCP may very well be a strategic step forward in AI development.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://maharship.com/blog/why-mcp-was-always-a-bad-idea/&quot;&gt;Continue reading on &lt;strong&gt;maharship.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/http&quot;&gt;#http&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/ai&quot;&gt;#ai&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/how-i-built-tjommis-backend</id>
    <title>🔗 How I built Tjommi's backend</title>
    <updated>2026-11-09T09:00:00Z</updated>
    <published>2026-11-09T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/how-i-built-tjommis-backend"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Tjommi's backend integrates sophisticated data handling for tracking purchased products and claims. It processes varied formats like emails, PDFs, and screenshots into structured records. The article dives into the iterative development of this backend, documenting architectural choices and technological advancements spanning from 2019 to 2023. Key components include the use of receipt extraction, retailer integrations, and the introduction of AI for processing formats. The evolving modular architecture within a Laravel application ensures smooth functionality, while managing complexities tied to retailer behaviors. Overall, it highlights how continuous refinement and innovative technologies enhanced the claims process and improved customer experience.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://helgesver.re/articles/how-i-built-tjommi&quot;&gt;Continue reading on &lt;strong&gt;helgesver.re&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/pdf&quot;&gt;#pdf&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/development&quot;&gt;#development&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/laravel&quot;&gt;#laravel&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/database&quot;&gt;#database&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/ai&quot;&gt;#ai&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/creating-a-simple-elixir-nif-using-rust</id>
    <title>🐥 Creating a Simple Elixir NIF Using Rust</title>
    <updated>2026-11-08T18:00:00Z</updated>
    <published>2026-11-08T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/creating-a-simple-elixir-nif-using-rust"/>
    <content type="html">&lt;p&gt;Elixir is great for many things, but sometimes you need raw speed or access to native libraries. That’s where &lt;strong&gt;Native Implemented Functions (NIFs)&lt;/strong&gt; come in. This post walks through creating a simple Elixir NIF using Rust with the help of the &lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;&lt;code&gt;rustler&lt;/code&gt;&lt;/a&gt; crate.&lt;/p&gt;
&lt;h1&gt;Set up your Elixir project&lt;/h1&gt;
&lt;p&gt;Start with a basic Elixir application:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;mix&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;my_nif_app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-function-builtin&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;my_nif_app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add &lt;code&gt;:rustler&lt;/code&gt; as a dependency in &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;quot;~&amp;gt; 0.38.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;  &lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fetch the dependencies:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;mix&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;deps.get&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Generate the Rust NIF scaffold&lt;/h1&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;mix&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;rustler.new&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;Elixir&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;NIF&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;will&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;be&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;registered&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;to.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;Module&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string-special-path&quot;&gt;MyNif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;used&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;generated&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;Rust&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;crate.&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;most&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;likely&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;fine.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;Library&lt;/span&gt; name &lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;mynif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-string-special-path&quot;&gt;my_nif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;Fetched&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;latest&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;rustler&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;crate&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;0.39.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;creating&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;native/my_nif/README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;creating&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;native/my_nif/Cargo.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;creating&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;native/my_nif/src/lib.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;10&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;creating&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;Cargo.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;11&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;Updating&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;.gitignore&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;12&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;13&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;Ready&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;go!&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;See&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;native/my_nif/README.md&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;further&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;instructions.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;native/&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;Scaffold a Rust crate&lt;/li&gt;
&lt;li&gt;Link it into your Elixir project&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Choose a crate name when prompted, such as &lt;code&gt;my_nif&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Write a simple NIF in Rust&lt;/h1&gt;
&lt;p&gt;Open the generated &lt;code&gt;native/my_nif/src/lib.rs&lt;/code&gt; file and replace its contents with:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-rust&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-punctuation-special&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-variable-parameter&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;l-punctuation-delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;    &lt;span class=&quot;l-variable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;l-variable&quot;&gt;b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-module&quot;&gt;rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-macro&quot;&gt;init!&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;Elixir.MyNif&amp;quot;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This defines a basic &lt;code&gt;add/2&lt;/code&gt; function exposed to Elixir.&lt;/p&gt;
&lt;h1&gt;Define the Elixir wrapper&lt;/h1&gt;
&lt;p&gt;In &lt;code&gt;lib/my_nif.ex&lt;/code&gt;, wire up the NIF:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-keyword-function&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;  &lt;span class=&quot;l-keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;Rustler&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;otp_app: :my_nif_app&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;crate: &lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;quot;my_nif&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;  &lt;span class=&quot;l-comment&quot;&gt;# Fallback when the NIF is not loaded&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;  &lt;span class=&quot;l-keyword-function&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-comment&quot;&gt;_a&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-comment&quot;&gt;_b&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-string-special-symbol&quot;&gt;do: &lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;:erlang&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;nif_error&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-string-special-symbol&quot;&gt;:nif_not_loaded&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-keyword&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Build and test&lt;/h1&gt;
&lt;p&gt;Compile the NIF:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;mix&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;compile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then try it out in &lt;code&gt;iex&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-elixir&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;$ &lt;span class=&quot;l-function-call&quot;&gt;iex&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;S&lt;/span&gt; mix&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;iex&lt;span class=&quot;l-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;MyNif&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;l-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-number&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You've created a simple Elixir NIF using Rust. This lets you use Rust's performance and ecosystem while retaining Elixir's productivity.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/rust&quot;&gt;#rust&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/elixir&quot;&gt;#elixir&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/why-we-started-building-on-the-django-6-1-alpha</id>
    <title>🔗 Why we started building on the Django 6.1 alpha</title>
    <updated>2026-11-08T14:00:00Z</updated>
    <published>2026-11-08T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/why-we-started-building-on-the-django-6-1-alpha"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Divio chose to adopt the Django 6.1 alpha long before its official release to actively contribute to its development. This decision was driven by their commitment to the Django community and the compelling new features Django 6.1 promised, such as database-level delete options and enhancements in the admin interface. By testing the pre-release daily, they not only utilized its advancements but also identified and reported several bugs, aiding the refinement of the framework. Their hands-on approach ensured they were at the forefront of developments and equipped them with insights into the new functionalities. As a result, Divio can now encourage others to explore Django 6.1, showcasing the readiness and potential of the framework for production use.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://www.divio.com/blog/why-we-started-building-on-the-django-6-1-alpha/&quot;&gt;Continue reading on &lt;strong&gt;www.divio.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/database&quot;&gt;#database&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/django&quot;&gt;#django&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/testing&quot;&gt;#testing&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/shadcn-datatable-filtering</id>
    <title>🔗 Shadcn datatable filtering</title>
    <updated>2026-11-08T09:00:00Z</updated>
    <published>2026-11-08T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/shadcn-datatable-filtering"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;A good datatable filter is essential for improving user experience by allowing for quick and easy access to specific data within large datasets. The Shadcn datatable filtering blocks combine search boxes, condition builders, and category filters to enhance the usability of data tables. These features allow users to narrow down their search through options like free-text search, stackable condition-based filters, and date range selectors, all while maintaining a seamless front-end experience using React and Tailwind CSS.&lt;/p&gt;
&lt;p&gt;Additionally, the blocks work harmoniously with both Base UI and Radix UI, making integration straightforward. Users can employ the Shadcn Builder to effortlessly drag and drop these blocks into their projects, streamlining the layout process without the need for manual coding. The article thoroughly outlines the capabilities and use cases of these filtering blocks, which are a standout in the Shadcn studio library for efficient data handling.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://shadcnstudio.com/blocks/datatable/datatable-filtering&quot;&gt;Continue reading on &lt;strong&gt;shadcnstudio.com&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/javascript&quot;&gt;#javascript&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/frontend&quot;&gt;#frontend&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/css&quot;&gt;#css&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/home-django-absurd</id>
    <title>🔗 django-absurd: ceci n'est pas un queue</title>
    <updated>2026-11-07T18:00:00Z</updated>
    <published>2026-11-07T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/home-django-absurd"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;django-absurd&lt;/code&gt; integrates a Postgres-native workflow engine into Django, allowing developers to run background tasks and durable workflows seamlessly. It utilizes Django's existing database connection, minimizing overhead and setup complexity. To get started, developers must ensure compatibility with Python 3.12+, Django 6.0+, and use the psycopg driver. After adding &lt;code&gt;django_absurd&lt;/code&gt; to the &lt;code&gt;INSTALLED_APPS&lt;/code&gt;, the database schema is migrated, and tasks can be written using Django's &lt;code&gt;@task&lt;/code&gt; decorator. The article outlines a straightforward task loop, from enqueuing to result retrieval, and highlights the use of workflow contexts for reliable task execution with checkpoints and retries. Key functionalities include tasks, workflows, cron jobs, worker management, and monitoring, making it a versatile solution for task management in Django applications.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://lincolnloop.github.io/django-absurd/&quot;&gt;Continue reading on &lt;strong&gt;lincolnloop.github.io&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/python&quot;&gt;#python&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/database&quot;&gt;#database&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/django&quot;&gt;#django&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/django-and-deployments</id>
    <title>🔗 Django and deployments</title>
    <updated>2026-11-07T14:00:00Z</updated>
    <published>2026-11-07T14:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/django-and-deployments"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;What if Django had a streamlined &lt;code&gt;deploy&lt;/code&gt; command? This article contemplates the future of Django deployments, building on insights from Will Vincent's recent talks and suggestions from the community. The author, who is also the maintainer of &lt;code&gt;django-prodserver&lt;/code&gt;, proposes conceptual stages for deployment, breaking them down into manageable commands. Key commands might include &lt;code&gt;manage.py init_deploy_env&lt;/code&gt; and &lt;code&gt;manage.py productionize&lt;/code&gt;. While there are myriad deployment strategies, the focus is on establishing a common API in Django that can aid in automating essential processes. By examining existing packages like &lt;code&gt;django-production&lt;/code&gt;, the author suggests a pathway toward simplifying deployment in Django projects, inviting community feedback on the potential for such innovations.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://softwarecrafts.co.uk/100-words/day-311&quot;&gt;Continue reading on &lt;strong&gt;softwarecrafts.co.uk&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/django&quot;&gt;#django&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/devops&quot;&gt;#devops&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/django-serve-a-security-txt-file</id>
    <title>🔗 Django: Serve a security.txt file</title>
    <updated>2026-11-07T09:00:00Z</updated>
    <published>2026-11-07T09:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/django-serve-a-security-txt-file"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;When a vulnerability is found on a site, security researchers often struggle to find a reliable way to report it. The solution? A &lt;code&gt;security.txt&lt;/code&gt; file, standardized in April 2022, which lays out how to communicate security issues. This article provides a comprehensive guide on implementing a &lt;code&gt;security.txt&lt;/code&gt; file in Django, serving it over HTTPS, and ensuring it remains current through unit tests and a custom system check. A thorough implementation is demonstrated, including the required content fields like &lt;code&gt;Contact&lt;/code&gt; and &lt;code&gt;Expires&lt;/code&gt;, as well as the code needed to serve the file and validate its integrity. Maintaining an updated &lt;code&gt;security.txt&lt;/code&gt; file not only aids communication but is crucial for any web application’s security protocol. Adam Johnson expertly covers these aspects to ensure your site is prepared for researchers looking to communicate vulnerabilities effectively.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://adamj.eu/tech/2026/10/01/django-security-txt/&quot;&gt;Continue reading on &lt;strong&gt;adamj.eu&lt;/strong&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/reading-list&quot;&gt;#reading-list&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/best-practice&quot;&gt;#best-practice&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/django&quot;&gt;#django&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/testing&quot;&gt;#testing&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://www.yellowduck.be/posts/giving-a-laravel-artisan-command-an-alias</id>
    <title>🐥 Giving a Laravel Artisan Command an Alias</title>
    <updated>2026-11-06T18:00:00Z</updated>
    <published>2026-11-06T18:00:00Z</published>
    <author><name>Pieter Claerhout</name><email>pieter@yellowduck.be</email></author>
    <link rel="alternate" href="https://www.yellowduck.be/posts/giving-a-laravel-artisan-command-an-alias"/>
    <content type="html">&lt;p&gt;Sooner or later, every codebase has a command whose name you can't remember. Say you have &lt;code&gt;reports:generate-monthly&lt;/code&gt;. Half the team types &lt;code&gt;reports:monthly&lt;/code&gt; from muscle memory and gets &amp;quot;Command not defined&amp;quot;. You don't want to rename the command because runbooks, scripts, and Slack history all reference the old name. So you give it a second name.&lt;/p&gt;
&lt;h1&gt;The short version&lt;/h1&gt;
&lt;p&gt;Aliases are a Symfony Console feature, and Artisan is built on Symfony Console. Laravel supports them in three ways.&lt;/p&gt;
&lt;h2&gt;1. The &lt;code&gt;$aliases&lt;/code&gt; property&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-php&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;GenerateMonthlyReportCommand&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-keyword-modifier&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;$signature&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;#39;reports:generate-monthly {reportId}&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-keyword-modifier&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;$description&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-string&quot;&gt;&amp;#39;Generates the monthly report for the given id&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;    &lt;span class=&quot;l-keyword-modifier&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;l-property&quot;&gt;$aliases&lt;/span&gt; &lt;span class=&quot;l-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;l-punctuation-bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;#39;reports:monthly&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;9&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Laravel's &lt;code&gt;Command&lt;/code&gt; constructor reads this property and calls Symfony's &lt;code&gt;setAliases()&lt;/code&gt; for you. This is the approach we use.&lt;/p&gt;
&lt;h2&gt;2. The &lt;code&gt;#[Aliases]&lt;/code&gt; attribute&lt;/h2&gt;
&lt;p&gt;Laravel 13 also has class attributes for command metadata:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-php&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-import&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;l-module&quot;&gt;Illuminate&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;l-module&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;l-type&quot;&gt;Aliases&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;&lt;span class=&quot;l-attribute&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;#[&lt;/span&gt;Aliases&lt;span class=&quot;l-punctuation-bracket&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;#39;reports:monthly&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;])]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;span class=&quot;l-keyword-type&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;GenerateMonthlyReportCommand&lt;/span&gt; &lt;span class=&quot;l-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;l-type&quot;&gt;Command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;    &lt;span class=&quot;l-comment&quot;&gt;// ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;8&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;#[Signature]&lt;/code&gt; attribute also accepts an &lt;code&gt;aliases&lt;/code&gt; argument, so the signature and its aliases can sit together. Use whichever style your commands already use.&lt;/p&gt;
&lt;h2&gt;3. Overriding &lt;code&gt;configure()&lt;/code&gt;&lt;/h2&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-php&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-keyword-modifier&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;l-keyword-function&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;l-function&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-type-builtin&quot;&gt;void&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;3&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;4&quot;&gt;    &lt;span class=&quot;l-variable-builtin&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;l-function-call&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;5&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;6&quot;&gt;    &lt;span class=&quot;l-variable-builtin&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;l-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;l-function-method-call&quot;&gt;setAliases&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;l-string&quot;&gt;&amp;#39;reports:monthly&amp;#39;&lt;/span&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;l-punctuation-delimiter&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;7&quot;&gt;&lt;span class=&quot;l-punctuation-bracket&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works on any Laravel version because it uses plain Symfony. On recent versions, you rarely need it.&lt;/p&gt;
&lt;h1&gt;What you get&lt;/h1&gt;
&lt;p&gt;Both names run the same command with the same arguments and options:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-bash&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;artisan&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;reports:generate-monthly&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;123&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;&lt;span class=&quot;l-function-call&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;artisan&lt;/span&gt; &lt;span class=&quot;l-variable-parameter&quot;&gt;reports:monthly&lt;/span&gt; &lt;span class=&quot;l-number&quot;&gt;123&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;php artisan list&lt;/code&gt; shows the alias as its own entry and marks the canonical command with the alias in brackets, so people can see that the two names belong together:&lt;/p&gt;
&lt;pre class=&quot;lumis&quot;&gt;&lt;code class=&quot;language-plaintext&quot; translate=&quot;no&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;l-line&quot; data-line=&quot;1&quot;&gt;reports:monthly            Generates the monthly report for the given id&lt;/span&gt;
&lt;span class=&quot;l-line&quot; data-line=&quot;2&quot;&gt;reports:generate-monthly   [reports:monthly] Generates the monthly report for the given id&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Gotchas&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;An alias is only a name.&lt;/strong&gt; Don't put arguments or options in it. The signature (&lt;code&gt;{reportId}&lt;/code&gt;) belongs to the command and is shared by every name. If you write &lt;code&gt;'reports:monthly {reportId}'&lt;/code&gt; as an alias, Symfony takes the whole string as the name, including the placeholder.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aliases must be unique.&lt;/strong&gt; Run &lt;code&gt;php artisan list&lt;/code&gt; after adding one to check that it doesn't collide with another command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduling and queues.&lt;/strong&gt; &lt;code&gt;Schedule::command('reports:monthly')&lt;/code&gt;, &lt;code&gt;$this-&amp;gt;call()&lt;/code&gt;, and &lt;code&gt;Artisan::call()&lt;/code&gt; all resolve aliases. Still, use the canonical name in code so a grep for the command finds every use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decide which name is canonical.&lt;/strong&gt; The alias is a convenience. If you want people to move to the new name, make it the &lt;code&gt;$signature&lt;/code&gt; name and keep the old one as the alias. That gives you a painless rename.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test it.&lt;/strong&gt; Run the command through its alias once in a test so a typo in the alias doesn't go unnoticed.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;a href=&quot;https://www.yellowduck.be/tags/laravel&quot;&gt;#laravel&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/php&quot;&gt;#php&lt;/a&gt; &lt;a href=&quot;https://www.yellowduck.be/tags/tools&quot;&gt;#tools&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
</feed>
