<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Rajeev Edmonds — Blog</title>
  <subtitle>Short, practical notes on Rust and command-line tools by Rajeev Edmonds.</subtitle>
  <link href="https://www.rajeevedmonds.com/blog/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://www.rajeevedmonds.com/blog/" rel="alternate" type="text/html"/>
  <id>https://www.rajeevedmonds.com/blog/</id>
  <updated>2026-09-28T00:00:00.000Z</updated>
  <author>
    <name>Rajeev Edmonds</name>
    <uri>https://www.rajeevedmonds.com/</uri>
  </author>
  <entry>
    <title>Make Your Rust CLI Pipe-Friendly: stdin, stdout and Broken Pipes</title>
    <link href="https://www.rajeevedmonds.com/blog/pipe-friendly-cli-in-rust/" rel="alternate" type="text/html"/>
    <id>https://www.rajeevedmonds.com/blog/pipe-friendly-cli-in-rust/</id>
    <published>2026-09-28T00:00:00.000Z</published>
    <updated>2026-09-28T00:00:00.000Z</updated>
    <summary>Read from a file or from stdin, write efficiently, and exit quietly when someone runs your tool through head.</summary>
    <content type="html">&lt;p&gt;The best command-line tools compose. They read from a file &lt;em&gt;or&lt;/em&gt; from a pipe, and they behave when their output is piped into something else. Getting that right in Rust takes only a few lines, but there&#39;s one classic trap: the broken pipe.&lt;/p&gt;
&lt;h2&gt;Read from a file or stdin&lt;/h2&gt;
&lt;p&gt;Here&#39;s a small tool, &lt;code&gt;shout&lt;/code&gt;, that uppercases its input. With a path argument it reads that file; without one it reads stdin.&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;io&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BufRead&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BufReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BufWriter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsTerminal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;io&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;nth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; reader&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;dyn&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BufRead&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;match&lt;/span&gt; path &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;BufReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;io&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;is_terminal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token macro property&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;usage: shout &amp;lt;file&gt;  (or pipe text into stdin)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;io&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;mut&lt;/span&gt; out &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BufWriter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;io&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; reader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;writeln!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;to_uppercase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few details are worth knowing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Box&amp;lt;dyn BufRead&amp;gt;&lt;/code&gt; lets both branches share one loop, whether the source is a file or stdin.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IsTerminal&lt;/code&gt; (stable since Rust 1.70) tells you whether stdin is an interactive terminal. Without that check, running &lt;code&gt;shout&lt;/code&gt; with no arguments would sit there silently waiting for input, which looks like a hang.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stdout&lt;/code&gt; is line-buffered, so wrapping it in a &lt;code&gt;BufWriter&lt;/code&gt; cuts down on system calls when you print many lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The broken pipe trap&lt;/h2&gt;
&lt;p&gt;Now try &lt;code&gt;shout big.log | head -n 3&lt;/code&gt;. &lt;code&gt;head&lt;/code&gt; prints three lines and exits, closing the pipe, and your next write fails. Rust&#39;s runtime ignores &lt;code&gt;SIGPIPE&lt;/code&gt;, so instead of being killed silently like a typical Unix tool, your program gets a &lt;code&gt;BrokenPipe&lt;/code&gt; error. With &lt;code&gt;println!&lt;/code&gt;, that error becomes a panic. With &lt;code&gt;writeln!&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt;, it bubbles up as an &lt;code&gt;Err&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That &lt;code&gt;Err&lt;/code&gt; isn&#39;t a real failure. The reader simply got what it needed. So treat it as a normal exit in &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;io&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ErrorKind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;BrokenPipe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// downstream (e.g. `head`) closed the pipe, which is fine&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;shout: {e}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the tool works in all three modes:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;shout notes.txt
&lt;span class=&quot;token builtin class-name&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;hello&#92;nworld&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; shout
shout big.log &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading from stdin, writing through a buffer, and treating &lt;code&gt;BrokenPipe&lt;/code&gt; as a clean exit are three small habits that make a tool feel native on the command line.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Integrate Assembly and C Code in Your Rust Projects (The Practical Guide)</title>
    <link href="https://www.rajeevedmonds.com/blog/integrate-assembly-and-c-code-in-rust-projects/" rel="alternate" type="text/html"/>
    <id>https://www.rajeevedmonds.com/blog/integrate-assembly-and-c-code-in-rust-projects/</id>
    <published>2026-09-28T00:00:00.000Z</published>
    <updated>2026-09-28T00:00:00.000Z</updated>
    <summary>Learn how to call C and assembly from Rust using build.rs, the cc crate, bindgen, and inline asm. Practical examples, safe wrappers, and fixes.</summary>
    <content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Rust is great, but it doesn&#39;t live in a vacuum. Sooner or later, you&#39;ll hit a moment where you need to talk to code that isn&#39;t Rust.&lt;/p&gt;
&lt;p&gt;Maybe your company has a battle-tested C library that nobody wants to rewrite. Maybe you&#39;re working with a hardware SDK that ships only a C header. Or maybe you&#39;ve found a hot loop where a few hand-written instructions beat what the compiler generates.&lt;/p&gt;
&lt;p&gt;So how do you bring C and assembly into a Rust project without turning your build into a mess? And how do you keep Rust&#39;s safety guarantees from falling apart at the boundary?&lt;/p&gt;
&lt;p&gt;This guide answers both questions. We&#39;ll cover the main ways to mix these languages, build a working example step by step, and go through the mistakes that cause most FFI crashes. I&#39;ll assume you know basic Rust, but I&#39;ll explain the low-level parts as we go.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; All examples target x86_64 Linux, since that&#39;s where most people start. I&#39;ll flag where macOS, Windows, or ARM need changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Why Mix Rust With C and Assembly?&lt;/h2&gt;
&lt;p&gt;Before writing any code, it helps to know when this is actually worth doing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Good reasons:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusing existing C libraries.&lt;/strong&gt; OpenSSL, SQLite, zlib, and libcurl represent decades of work. Wrapping them is often smarter than rewriting them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Talking to operating systems and hardware.&lt;/strong&gt; Many drivers, SDKs, and system APIs expose C interfaces.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gradual migration.&lt;/strong&gt; You can move a C codebase to Rust one module at a time instead of in a risky big-bang rewrite.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Squeezing out performance.&lt;/strong&gt; Some CPU instructions have no clean Rust equivalent, such as special vector instructions, cycle counters, or system-specific tricks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learning.&lt;/strong&gt; Writing assembly for a Rust function teaches you a lot about how calling conventions really work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bad reasons:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;C is always faster.&amp;quot; It isn&#39;t. Rust and C compile down to similar machine code, and LLVM optimizes both well.&lt;/li&gt;
&lt;li&gt;&amp;quot;Hand-written assembly beats the compiler.&amp;quot; It rarely does for general code. Always benchmark first.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Big Picture: Ways to Integrate&lt;/h2&gt;
&lt;p&gt;Here are the main approaches you&#39;ll use:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Where the Code Lives&lt;/th&gt;
&lt;th&gt;Difficulty&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FFI with &lt;code&gt;extern &amp;quot;C&amp;quot;&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Calling C functions from Rust&lt;/td&gt;
&lt;td&gt;Separate &lt;code&gt;.c&lt;/code&gt; files or a system library&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;build.rs&lt;/code&gt; + &lt;code&gt;cc&lt;/code&gt; crate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compiling C or &lt;code&gt;.S&lt;/code&gt; files as part of &lt;code&gt;cargo build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inside your project&lt;/td&gt;
&lt;td&gt;Easy to medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inline &lt;code&gt;asm!&lt;/code&gt; / &lt;code&gt;global_asm!&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Small snippets of assembly&lt;/td&gt;
&lt;td&gt;Inside your Rust source&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;bindgen&lt;/code&gt; / &lt;code&gt;cbindgen&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auto-generating bindings in either direction&lt;/td&gt;
&lt;td&gt;Generated at build time&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Standalone &lt;code&gt;.s&lt;/code&gt;/&lt;code&gt;.S&lt;/code&gt; files&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Larger assembly routines&lt;/td&gt;
&lt;td&gt;Separate assembly files&lt;/td&gt;
&lt;td&gt;Advanced&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All of these rely on one idea: the &lt;strong&gt;C ABI&lt;/strong&gt;. It&#39;s the agreed-upon convention for how functions receive arguments and return values. Rust, C, and assembly can all speak it, and that shared language is what makes mixing them possible.&lt;/p&gt;
&lt;h2&gt;Understanding FFI in Rust&lt;/h2&gt;
&lt;p&gt;FFI stands for Foreign Function Interface. In Rust, it comes down to two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Declaring&lt;/strong&gt; foreign functions inside an &lt;code&gt;extern &amp;quot;C&amp;quot;&lt;/code&gt; block.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calling&lt;/strong&gt; them inside &lt;code&gt;unsafe&lt;/code&gt;, because Rust can&#39;t verify what happens on the other side.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{x}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That works because the C standard library is already linked into every Rust program on most platforms.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A quick syntax note:&lt;/strong&gt; Since Rust 1.82, you can write &lt;code&gt;unsafe extern &amp;quot;C&amp;quot; { ... }&lt;/code&gt;, and it&#39;s required in the 2024 edition. Older code uses plain &lt;code&gt;extern &amp;quot;C&amp;quot; { ... }&lt;/code&gt;. Both mean the same thing. The newer form lets you mark individual items as &lt;code&gt;safe&lt;/code&gt; or &lt;code&gt;unsafe&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Why &lt;code&gt;unsafe&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;The Rust compiler has no idea what a C function does. It can&#39;t check that pointers are valid, that lengths are correct, or that the function won&#39;t write past the end of a buffer. So you&#39;re making a promise: &amp;quot;I&#39;ve checked this, and it&#39;s fine.&amp;quot;&lt;/p&gt;
&lt;p&gt;The best practice is to keep that promise in &lt;strong&gt;one place&lt;/strong&gt;. Wrap each unsafe call in a small safe function, and let the rest of your program use the safe version. We&#39;ll do exactly that below.&lt;/p&gt;
&lt;h2&gt;Mapping Types Between Rust and C&lt;/h2&gt;
&lt;p&gt;Getting types wrong is the number one source of subtle FFI bugs. Here are the common mappings:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;C Type&lt;/th&gt;
&lt;th&gt;Rust Type&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;std::ffi::c_int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Don&#39;t assume it&#39;s &lt;code&gt;i32&lt;/code&gt; on every platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unsigned int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;c_uint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;c_long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32-bit on Windows, 64-bit on 64-bit Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;size_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;usize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;uint8_t&lt;/code&gt;, &lt;code&gt;uint32_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;u8&lt;/code&gt;, &lt;code&gt;u32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed-width types map cleanly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;char *&lt;/code&gt; (string)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*const c_char&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;CStr&lt;/code&gt;/&lt;code&gt;CString&lt;/code&gt; to convert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;void *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*mut c_void&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;const T *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*const T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;T *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*mut T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;struct&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#[repr(C)] struct&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Without &lt;code&gt;repr(C)&lt;/code&gt;, layout is not guaranteed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;function pointer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Option&amp;lt;extern &amp;quot;C&amp;quot; fn(...)&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Option&lt;/code&gt; allows null&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two rules to remember:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Always use &lt;code&gt;#[repr(C)]&lt;/code&gt; on structs you share with C.&lt;/strong&gt; Rust is free to reorder fields in normal structs, and C won&#39;t expect that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer fixed-width types&lt;/strong&gt; (&lt;code&gt;u32&lt;/code&gt;, &lt;code&gt;i64&lt;/code&gt;) in your own C code when you control both sides. It removes a whole class of &amp;quot;works on my machine&amp;quot; problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step-by-Step: Adding C and Assembly to a Rust Project&lt;/h2&gt;
&lt;p&gt;Let&#39;s build something real. Our small project will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Call a &lt;strong&gt;C function&lt;/strong&gt; that computes a checksum.&lt;/li&gt;
&lt;li&gt;Call an &lt;strong&gt;assembly function&lt;/strong&gt; that adds two numbers.&lt;/li&gt;
&lt;li&gt;Compile both automatically with &lt;code&gt;cargo build&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 1: Create the Project&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cargo&lt;/span&gt; new rust-ffi-demo
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; rust-ffi-demo
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; csrc asm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your layout will end up like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rust-ffi-demo/
├── Cargo.toml
├── build.rs
├── csrc/
│   ├── checksum.c
│   └── checksum.h
├── asm/
│   └── add.S
└── src/
    └── main.rs
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Write the C Code&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;csrc/checksum.h&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;CHECKSUM_H&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;CHECKSUM_H&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stddef.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdint.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;simple_checksum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;size_t&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;csrc/checksum.c&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checksum.h&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;simple_checksum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;size_t&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;uint32_t&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;size_t&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// rotate left by 1, then XOR in the next byte&lt;/span&gt;
        sum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        sum &lt;span class=&quot;token operator&quot;&gt;^=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; sum&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing fancy. It&#39;s a small function that&#39;s easy to verify by hand.&lt;/p&gt;
&lt;h3&gt;Step 3: Write the Assembly Code&lt;/h3&gt;
&lt;p&gt;We&#39;ll use a &lt;code&gt;.S&lt;/code&gt; file (capital S). That capital matters: it tells the compiler to run the C preprocessor first, and it&#39;s the file type the &lt;code&gt;cc&lt;/code&gt; crate handles well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;asm/add.S&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-asm&quot;&gt;&lt;code class=&quot;language-asm&quot;&gt;    .intel_syntax noprefix
    .text
    .globl add_asm
    .type add_asm, @function

add_asm:
    lea rax, [rdi + rsi]
    ret

    .size add_asm, .-add_asm
    .section .note.GNU-stack,&quot;&quot;,@progbits&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What&#39;s happening here?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On x86_64 Linux (the System V ABI), the first two integer arguments arrive in &lt;code&gt;rdi&lt;/code&gt; and &lt;code&gt;rsi&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The return value goes in &lt;code&gt;rax&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lea rax, [rdi + rsi]&lt;/code&gt; computes the sum without touching the flags register. It&#39;s a common trick.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.note.GNU-stack&lt;/code&gt; line tells the linker your code doesn&#39;t need an executable stack. Without it, newer linkers may warn.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Heads up for other platforms:&lt;/strong&gt; On macOS, C symbols get a leading underscore (&lt;code&gt;_add_asm&lt;/code&gt;), and Windows uses a different calling convention entirely. ARM64 uses different registers (&lt;code&gt;x0&lt;/code&gt;, &lt;code&gt;x1&lt;/code&gt;) and different syntax. Assembly is not portable, and that&#39;s normal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Step 4: Compile Everything With &lt;code&gt;build.rs&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Add the &lt;code&gt;cc&lt;/code&gt; crate as a &lt;strong&gt;build dependency&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Cargo.toml&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rust-ffi-demo&quot;&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.1.0&quot;&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;edition&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024&quot;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;build-dependencies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;cc&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now create &lt;code&gt;build.rs&lt;/code&gt; in the project root. Cargo runs this before compiling your main crate.&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Compile the C library&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;cc&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;csrc/checksum.c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;csrc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;opt_level&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;checksum&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Compile assembly only where it makes sense&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; arch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CARGO_CFG_TARGET_ARCH&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; os &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CARGO_CFG_TARGET_OS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; arch &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;x86_64&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; os &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;linux&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token namespace&quot;&gt;cc&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;asm/add.S&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;addasm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Only re-run this script when these files change&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cargo:rerun-if-changed=csrc/checksum.c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cargo:rerun-if-changed=csrc/checksum.h&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cargo:rerun-if-changed=asm/add.S&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice we check the &lt;strong&gt;target&lt;/strong&gt; architecture using &lt;code&gt;CARGO_CFG_TARGET_ARCH&lt;/code&gt;, not &lt;code&gt;cfg!(target_arch)&lt;/code&gt;. Inside &lt;code&gt;build.rs&lt;/code&gt;, &lt;code&gt;cfg!&lt;/code&gt; describes the machine running the build script, not the machine you&#39;re compiling &lt;em&gt;for&lt;/em&gt;. It makes no difference in a normal build, but it breaks silently when you cross-compile.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;cc&lt;/code&gt; crate finds a C compiler (&lt;code&gt;gcc&lt;/code&gt;, &lt;code&gt;clang&lt;/code&gt;, or MSVC), compiles your files into a static library, and tells Cargo to link it. You don&#39;t need to write any linker flags yourself.&lt;/p&gt;
&lt;h3&gt;Step 5: Call Everything From Rust&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/main.rs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;simple_checksum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[cfg(all(target_arch = &lt;span class=&quot;token string&quot;&gt;&quot;x86_64&quot;&lt;/span&gt;, target_os = &lt;span class=&quot;token string&quot;&gt;&quot;linux&quot;&lt;/span&gt;))]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;add_asm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/// Safe wrapper around the C checksum function.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;checksum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;u32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// SAFETY: the pointer and length come from a valid slice,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// and the C function only reads `len` bytes.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;simple_checksum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;as_ptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token attribute attr-name&quot;&gt;#[cfg(all(target_arch = &lt;span class=&quot;token string&quot;&gt;&quot;x86_64&quot;&lt;/span&gt;, target_os = &lt;span class=&quot;token string&quot;&gt;&quot;linux&quot;&lt;/span&gt;))]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// SAFETY: add_asm is a pure function with no memory access.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add_asm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; msg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;b&quot;hello from Rust&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;checksum = {:#010x}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checksum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[cfg(all(target_arch = &lt;span class=&quot;token string&quot;&gt;&quot;x86_64&quot;&lt;/span&gt;, target_os = &lt;span class=&quot;token string&quot;&gt;&quot;linux&quot;&lt;/span&gt;))]&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2 + 40 = {}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run it:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cargo&lt;/span&gt; run&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see the checksum printed, followed by &lt;code&gt;2 + 40 = 42&lt;/code&gt;. That&#39;s the whole loop: write C or assembly, describe it in an &lt;code&gt;extern&lt;/code&gt; block, wrap it safely, and let Cargo build it all.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Put the &lt;code&gt;extern&lt;/code&gt; block and the safe wrappers in their own module, such as &lt;code&gt;ffi.rs&lt;/code&gt;. The rest of your codebase should never see the word &lt;code&gt;unsafe&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Using Inline Assembly Directly in Rust&lt;/h2&gt;
&lt;p&gt;You don&#39;t always need a separate file. For short snippets, Rust has built-in support through the &lt;code&gt;asm!&lt;/code&gt; macro, which has been stable since Rust 1.59.&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;arch&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;asm&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token attribute attr-name&quot;&gt;#[cfg(target_arch = &lt;span class=&quot;token string&quot;&gt;&quot;x86_64&quot;&lt;/span&gt;)]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;add_inline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;u64&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;mut&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;asm!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;add {0}, {1}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;inout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pure&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nomem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nostack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    result
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s break that down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{0}&lt;/code&gt; and &lt;code&gt;{1}&lt;/code&gt; are placeholders. Rust picks the actual registers for you, which is much safer than hard-coding them.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inout(reg) result&lt;/code&gt; means &amp;quot;this value goes in and comes back out.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;in(reg) b&lt;/code&gt; means &amp;quot;read-only input.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;options(pure, nomem, nostack)&lt;/code&gt; are promises to the compiler: no side effects, no memory access, no stack use. These let it optimize aggressively, so &lt;strong&gt;only add them if they&#39;re true.&lt;/strong&gt; If you lie, you get bugs that are very hard to trace.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Inline &lt;code&gt;asm!&lt;/code&gt; vs. Separate &lt;code&gt;.S&lt;/code&gt; Files&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Inline &lt;code&gt;asm!&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Separate &lt;code&gt;.S&lt;/code&gt; file&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Register allocation&lt;/td&gt;
&lt;td&gt;Compiler handles it&lt;/td&gt;
&lt;td&gt;You handle it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inlining&lt;/td&gt;
&lt;td&gt;Can be inlined into callers&lt;/td&gt;
&lt;td&gt;Always a real function call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Needs &lt;code&gt;build.rs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;A few instructions&lt;/td&gt;
&lt;td&gt;Whole functions or routines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syntax&lt;/td&gt;
&lt;td&gt;Intel by default on x86&lt;/td&gt;
&lt;td&gt;Whatever your assembler accepts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Two More Tools Worth Knowing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;global_asm!&lt;/code&gt;&lt;/strong&gt; lets you emit a whole block of assembly at module level, which is handy for defining entire functions without a build script.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Naked functions&lt;/strong&gt; give you full control over a function&#39;s prologue and epilogue. They were stabilized in Rust 1.88 using &lt;code&gt;#[unsafe(naked)]&lt;/code&gt; and &lt;code&gt;naked_asm!&lt;/code&gt;. Check your compiler version before relying on them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Generating Bindings Automatically With bindgen&lt;/h2&gt;
&lt;p&gt;Hand-writing &lt;code&gt;extern&lt;/code&gt; blocks is fine for three functions. For a library with three hundred, it&#39;s a recipe for typos.&lt;/p&gt;
&lt;p&gt;That&#39;s where &lt;code&gt;bindgen&lt;/code&gt; comes in. It reads your C header and generates the Rust declarations for you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Cargo.toml&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;build-dependencies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;cc&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;bindgen&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.71&quot;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;# check crates.io for the latest version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;csrc/wrapper.h&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checksum.h&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;build.rs&lt;/code&gt; (bindgen part)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;path&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;PathBuf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ... cc::Build code from before ...&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; bindings &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;bindgen&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;csrc/wrapper.h&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse_callbacks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;bindgen&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CargoCallbacks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;generate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;failed to generate bindings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; out &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PathBuf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;env&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;OUT_DIR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    bindings
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;write_to_file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bindings.rs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;failed to write bindings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/ffi.rs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token attribute attr-name&quot;&gt;#![allow(non_upper_case_globals)]&lt;/span&gt;
&lt;span class=&quot;token attribute attr-name&quot;&gt;#![allow(non_camel_case_types)]&lt;/span&gt;
&lt;span class=&quot;token attribute attr-name&quot;&gt;#![allow(non_snake_case)]&lt;/span&gt;
&lt;span class=&quot;token attribute attr-name&quot;&gt;#![allow(dead_code)]&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;include!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token macro property&quot;&gt;concat!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token macro property&quot;&gt;env!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;OUT_DIR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/bindings.rs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few things to know about &lt;code&gt;bindgen&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It needs &lt;strong&gt;libclang&lt;/strong&gt; installed on your machine. On Ubuntu or Debian, that&#39;s &lt;code&gt;sudo apt install libclang-dev&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The generated code is raw and unsafe. You still need to write safe wrappers on top.&lt;/li&gt;
&lt;li&gt;For very large libraries, commit the generated file to your repo so contributors don&#39;t all need libclang.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Going the Other Way: Calling Rust From C&lt;/h2&gt;
&lt;p&gt;Integration works in both directions. If you&#39;re migrating a C project to Rust, you&#39;ll want C code to call your new Rust functions.&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token attribute attr-name&quot;&gt;#[unsafe(no_mangle)]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;rust_multiply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    a &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;extern &amp;quot;C&amp;quot;&lt;/code&gt; gives the function the C calling convention.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#[unsafe(no_mangle)]&lt;/code&gt; stops Rust from renaming the symbol, so C can find it. On editions before 2024, write it as plain &lt;code&gt;#[no_mangle]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To make C happy, you also need a header. Instead of writing it by hand, use &lt;strong&gt;&lt;code&gt;cbindgen&lt;/code&gt;&lt;/strong&gt;, which reads your Rust code and generates a &lt;code&gt;.h&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cargo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; cbindgen
cbindgen &lt;span class=&quot;token parameter variable&quot;&gt;--lang&lt;/span&gt; c &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; rust_api.h&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To build a library that C can link against, set the crate type in &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;crate-type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;staticlib&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;# or &quot;cdylib&quot; for a shared library&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The Panic Problem&lt;/h3&gt;
&lt;p&gt;What happens if Rust code panics while being called from C? Historically, unwinding across an &lt;code&gt;extern &amp;quot;C&amp;quot;&lt;/code&gt; boundary was undefined behavior. Modern Rust makes &lt;code&gt;extern &amp;quot;C&amp;quot;&lt;/code&gt; functions abort the process if a panic tries to escape. That&#39;s safer than undefined behavior, but it still kills your program.&lt;/p&gt;
&lt;p&gt;The fix is to catch panics at the boundary:&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;panic&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;catch_unwind&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token attribute attr-name&quot;&gt;#[unsafe(no_mangle)]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;rust_safe_divide&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;catch_unwind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token closure-params&quot;&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unwrap_or&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Return an error code instead of letting a panic escape. C programmers already expect that style.&lt;/p&gt;
&lt;h2&gt;Handling Strings, Memory, and Ownership&lt;/h2&gt;
&lt;p&gt;This is where most real-world FFI bugs live. The rule of thumb is simple: &lt;strong&gt;whoever allocates the memory must free it.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Passing Strings to C&lt;/h3&gt;
&lt;p&gt;Rust strings aren&#39;t null-terminated. C strings are. Use &lt;code&gt;CString&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;ffi&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c_char&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; c_char&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hello from Rust&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;no interior null bytes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;as_ptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keep &lt;code&gt;s&lt;/code&gt; alive for as long as C uses the pointer. A classic mistake is writing &lt;code&gt;CString::new(&amp;quot;hi&amp;quot;).unwrap().as_ptr()&lt;/code&gt;, which drops the &lt;code&gt;CString&lt;/code&gt; immediately and hands C a dangling pointer.&lt;/p&gt;
&lt;h3&gt;Reading Strings From C&lt;/h3&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;ffi&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CStr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c_char&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;read_c_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; c_char&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CStr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from_ptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;to_string_lossy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;into_owned&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Memory Ownership Rules&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory allocated by C&lt;/strong&gt; (with &lt;code&gt;malloc&lt;/code&gt;) must be freed by C (&lt;code&gt;free&lt;/code&gt;). Never pass it to Rust&#39;s allocator.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory allocated by Rust&lt;/strong&gt; (like a &lt;code&gt;Box&lt;/code&gt; or &lt;code&gt;Vec&lt;/code&gt;) must be freed by Rust. If you hand it to C, give C a matching &lt;code&gt;free_thing()&lt;/code&gt; function to call back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Borrowed pointers&lt;/strong&gt; should never be stored by C beyond the call unless you&#39;ve guaranteed the data lives long enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Real-World Use Cases&lt;/h2&gt;
&lt;p&gt;Here&#39;s where this kind of integration shows up in practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Wrapping system libraries&lt;/strong&gt; such as libc, libpcap, or libusb, which is how many &lt;code&gt;*-sys&lt;/code&gt; crates work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embedded and OS development&lt;/strong&gt;, where startup code and interrupt handlers are often small assembly routines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cryptography&lt;/strong&gt;, where libraries pair a Rust API with hand-tuned assembly for hot loops.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI and developer tools&lt;/strong&gt;, where you might reuse an existing C parser or compression library instead of reimplementing it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance experiments&lt;/strong&gt;, where you replace one function with an assembly version and benchmark the difference.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Best Practices&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Isolate &lt;code&gt;unsafe&lt;/code&gt;.&lt;/strong&gt; Keep FFI declarations in one module and expose only safe functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document every &lt;code&gt;unsafe&lt;/code&gt; block&lt;/strong&gt; with a &lt;code&gt;// SAFETY:&lt;/code&gt; comment explaining why it&#39;s sound.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;code&gt;#[repr(C)]&lt;/code&gt;&lt;/strong&gt; on every shared struct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never let panics cross the boundary.&lt;/strong&gt; Catch them and return error codes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check for null pointers&lt;/strong&gt; before dereferencing anything that came from C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Benchmark before writing assembly.&lt;/strong&gt; Use &lt;code&gt;cargo bench&lt;/code&gt; or Criterion, and compare against plain Rust first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gate platform-specific code&lt;/strong&gt; with &lt;code&gt;cfg&lt;/code&gt; attributes and always provide a portable fallback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test under sanitizers.&lt;/strong&gt; Tools like Valgrind and AddressSanitizer catch memory errors that Rust can&#39;t see across FFI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add &lt;code&gt;rerun-if-changed&lt;/code&gt;&lt;/strong&gt; lines so &lt;code&gt;build.rs&lt;/code&gt; doesn&#39;t recompile everything on every build.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consider a &lt;code&gt;-sys&lt;/code&gt; crate&lt;/strong&gt; if you&#39;re wrapping a library others might use. Keep raw bindings in &lt;code&gt;foo-sys&lt;/code&gt; and the safe API in &lt;code&gt;foo&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Mixing Rust with C and assembly sounds intimidating, but the workflow is quite consistent once you&#39;ve seen it. Declare the foreign functions, compile the foreign code through &lt;code&gt;build.rs&lt;/code&gt; and the &lt;code&gt;cc&lt;/code&gt; crate, wrap the unsafe parts in safe functions, and test carefully.&lt;/p&gt;
&lt;p&gt;Here are the takeaways worth remembering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;cc&lt;/code&gt; to compile C and &lt;code&gt;.S&lt;/code&gt; files during &lt;code&gt;cargo build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;bindgen&lt;/code&gt; for big headers and &lt;code&gt;cbindgen&lt;/code&gt; when C needs to call Rust.&lt;/li&gt;
&lt;li&gt;Match types carefully and add &lt;code&gt;#[repr(C)]&lt;/code&gt; to shared structs.&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;unsafe&lt;/code&gt; in one small module and document why it&#39;s sound.&lt;/li&gt;
&lt;li&gt;Never let panics cross the boundary, and always follow the &amp;quot;whoever allocates, frees&amp;quot; rule.&lt;/li&gt;
&lt;li&gt;Reach for assembly only after a benchmark tells you to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Start small. Wrap one C function, get it running, then grow from there. Once that first &lt;code&gt;cargo run&lt;/code&gt; prints the right answer, the rest is repetition.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Friendly Errors in a Rust CLI with anyhow</title>
    <link href="https://www.rajeevedmonds.com/blog/friendly-errors-with-anyhow/" rel="alternate" type="text/html"/>
    <id>https://www.rajeevedmonds.com/blog/friendly-errors-with-anyhow/</id>
    <published>2026-09-22T00:00:00.000Z</published>
    <updated>2026-09-22T00:00:00.000Z</updated>
    <summary>Use anyhow&#39;s Context to turn cryptic failures like &#39;No such file or directory&#39; into messages your users can actually act on.</summary>
    <content type="html">&lt;p&gt;The default failure message from a lot of Rust code is technically correct and completely unhelpful: &lt;code&gt;No such file or directory (os error 2)&lt;/code&gt;. Which file? Doing what? In a command-line tool, the error message &lt;em&gt;is&lt;/em&gt; the user interface, so it&#39;s worth a few extra lines.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.rs/anyhow&quot;&gt;anyhow&lt;/a&gt; crate is built for exactly this in application code. It gives you one catch-all &lt;code&gt;Result&lt;/code&gt; type, and a way to attach context as an error travels up the call stack.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cargo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; anyhow&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Add context at each step&lt;/h2&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;anyhow&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;bail&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;read_port&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;read_to_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with_context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token closure-params&quot;&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token macro property&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;could not read config file `{path}`&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; port&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;u16&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; text
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with_context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token closure-params&quot;&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token macro property&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;`{path}` does not contain a valid port number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;bail!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;port {port} is reserved; choose 1024 or higher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;port&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;read_port&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;port.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;listening on port {port}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three pieces do the work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;anyhow::Result&amp;lt;T&amp;gt;&lt;/code&gt; is shorthand for &lt;code&gt;Result&amp;lt;T, anyhow::Error&amp;gt;&lt;/code&gt;. Any error type that implements &lt;code&gt;std::error::Error&lt;/code&gt; converts into it automatically, so the &lt;code&gt;?&lt;/code&gt; operator just works.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.with_context(|| ...)&lt;/code&gt; wraps the original error with your message. The closure form only builds the string if there actually was an error.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bail!&lt;/code&gt; returns early with a brand-new error, for problems that aren&#39;t wrapping anything, like the range check above.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What the user sees&lt;/h2&gt;
&lt;p&gt;Returning &lt;code&gt;Result&lt;/code&gt; from &lt;code&gt;main&lt;/code&gt; means Rust prints the error and exits with status 1. If &lt;code&gt;port.txt&lt;/code&gt; is missing:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Error: could not read config file `port.txt`

Caused by:
    No such file or directory (os error 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if the file contains &lt;code&gt;abc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Error: `port.txt` does not contain a valid port number

Caused by:
    invalid digit found in string&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your message comes first and the underlying cause follows. Nothing was lost, and the user now knows what to fix.&lt;/p&gt;
&lt;h2&gt;A note on where to use it&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;anyhow&lt;/code&gt; is a great fit for binaries, where you mostly want to report an error and exit. If you&#39;re writing a library, callers often need to match on specific failures. That&#39;s where a typed error, usually derived with the &lt;a href=&quot;https://docs.rs/thiserror&quot;&gt;thiserror&lt;/a&gt; crate, is the better tool. Many projects use both: &lt;code&gt;thiserror&lt;/code&gt; inside the library, &lt;code&gt;anyhow&lt;/code&gt; in the &lt;code&gt;main.rs&lt;/code&gt; that calls it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Parsing CLI Arguments in Rust with clap&#39;s Derive API</title>
    <link href="https://www.rajeevedmonds.com/blog/parse-cli-arguments-with-clap/" rel="alternate" type="text/html"/>
    <id>https://www.rajeevedmonds.com/blog/parse-cli-arguments-with-clap/</id>
    <published>2026-09-15T00:00:00.000Z</published>
    <updated>2026-09-15T00:00:00.000Z</updated>
    <summary>Turn a plain struct into a full argument parser, complete with flags, options, help text and --version, in about a dozen lines.</summary>
    <content type="html">&lt;p&gt;Every command-line tool starts the same way: it needs to read some arguments. You can loop over &lt;code&gt;std::env::args()&lt;/code&gt; by hand, but you&#39;ll be rewriting help text, validation and error messages within the hour. The &lt;a href=&quot;https://docs.rs/clap&quot;&gt;clap&lt;/a&gt; crate handles all of that, and its derive API lets you describe your whole CLI as a plain struct.&lt;/p&gt;
&lt;h2&gt;Set it up&lt;/h2&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cargo&lt;/span&gt; new linecount
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; linecount
&lt;span class=&quot;token function&quot;&gt;cargo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; clap &lt;span class=&quot;token parameter variable&quot;&gt;--features&lt;/span&gt; derive&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Describe the arguments as a struct&lt;/h2&gt;
&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;PathBuf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;clap&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Parser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/// A tiny example CLI&lt;/span&gt;
&lt;span class=&quot;token attribute attr-name&quot;&gt;#[derive(Parser, Debug)]&lt;/span&gt;
&lt;span class=&quot;token attribute attr-name&quot;&gt;#[command(version)]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token type-definition class-name&quot;&gt;Cli&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/// File to read&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PathBuf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/// Print extra detail&lt;/span&gt;
    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[arg(short, long)]&lt;/span&gt;
    verbose&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/// Stop after this many lines&lt;/span&gt;
    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[arg(short = &#39;n&#39;, long, default_value_t = 1000)]&lt;/span&gt;
    limit&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; cli &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cli&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; cli&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;verbose &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;verbose mode on&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;would read up to {} lines from {}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cli&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;limit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cli&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s the whole parser. A few things are happening here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A field with no attribute (&lt;code&gt;path&lt;/code&gt;) becomes a required positional argument.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;bool&lt;/code&gt; field becomes a flag. &lt;code&gt;short&lt;/code&gt; and &lt;code&gt;long&lt;/code&gt; give you &lt;code&gt;-v&lt;/code&gt; and &lt;code&gt;--verbose&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The field&#39;s type is the validation. Pass &lt;code&gt;--limit abc&lt;/code&gt; and clap rejects it with a clear error, because &lt;code&gt;abc&lt;/code&gt; isn&#39;t a &lt;code&gt;usize&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Doc comments (&lt;code&gt;///&lt;/code&gt;) become the help text, so your documentation and your &lt;code&gt;--help&lt;/code&gt; never drift apart.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Try it&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;cargo run -- --help&lt;/code&gt; now prints something like this, with no extra code:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;A tiny example CLI

Usage: linecount [OPTIONS] &lt;PATH&gt;

Arguments:
  &lt;PATH&gt;  File to read

Options:
  -v, --verbose        Print extra detail
  -n, --limit &lt;LIMIT&gt;  Stop after this many lines [default: 1000]
  -h, --help           Print help
  -V, --version        Print version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Cli::parse()&lt;/code&gt; also handles the failure path for you: on bad input it prints the error and exits with status 2, the conventional code for a usage error. If you&#39;d rather handle that yourself, &lt;code&gt;Cli::try_parse()&lt;/code&gt; returns a &lt;code&gt;Result&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;From here, the natural next steps are subcommands (put &lt;code&gt;#[derive(Subcommand)]&lt;/code&gt; on an enum) and value validation with &lt;code&gt;value_parser&lt;/code&gt;. Both are just more attributes on the same struct.&lt;/p&gt;
</content>
  </entry>
</feed>
