<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>liam's blog</title>
    <link>https://liam.rs</link>
    <description>programming, software, books</description>
    <atom:link href="https://liam.rs/index.xml" rel="self" type="application/rss+xml" />
    <language>en-us</language>
    <copyright>Creative Commons BY-NC-SA 4.0</copyright>
    <item>
<title>Python-in-the-browser</title>
<description>&lt;p&gt;I recently wrote and distributed a &lt;a
href="https://pypi.org/project/pqg/" target="_blank"&gt;Python package&lt;/a&gt;
for a project, and I wanted a &lt;a
href="https://dislmcgill.github.io/pandas-query-generator/"
target="_blank"&gt;web interface&lt;/a&gt; to go with it. Naturally, I chose &lt;a
href="https://react.dev/" target="_blank"&gt;React&lt;/a&gt; to build it, but I
had never called Python from a React app before, so I had to figure
things out.&lt;/p&gt;
&lt;p&gt;After a quick search, I stumbled across &lt;a
href="https://pyodide.org/en/stable/" target="_blank"&gt;Pyodide&lt;/a&gt;, which
is a port of &lt;a
href="https://en.wikipedia.org/wiki/CPython?useskin=vector"
target="_blank"&gt;CPython&lt;/a&gt; to &lt;a href="https://webassembly.org/"
target="_blank"&gt;WebAssembly&lt;/a&gt;/&lt;a href="https://emscripten.org/"
target="_blank"&gt;Emscripten&lt;/a&gt;. It allows users to install and use any
pure Python package with a wheel on &lt;a href="https://pypi.org/"
target="_blank"&gt;PyPI&lt;/a&gt; via &lt;a
href="https://micropip.pyodide.org/en/stable/project/api.html"
target="_blank"&gt;micropip&lt;/a&gt;. This sounded like something that could be
useful, so I decided to try it out.&lt;/p&gt;
&lt;p&gt;Since my package was already distributed, all I needed to do,
according to the Pyodide &lt;a
href="https://pyodide.org/en/stable/usage/loading-packages.html"
target="_blank"&gt;documentation&lt;/a&gt;, was:&lt;/p&gt;
&lt;ol type="1"&gt;
&lt;li&gt;&lt;code&gt;npm install pyodide&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install my package with micropip&lt;/li&gt;
&lt;li&gt;Run arbitrary Python code using my package with Pyodide’s &lt;a
href="https://pyodide.org/en/stable/usage/api/js-api.html#pyodide.runPythonAsync"
target="_blank"&gt;API&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Turns out this worked for my use case, let’s dive deeper into each
step!&lt;/p&gt;
&lt;h3 id="i.-installation"&gt;I. Installation&lt;/h3&gt;
&lt;p&gt;This is straightforward. I used &lt;a href="https://bun.sh/"
target="_blank"&gt;bun&lt;/a&gt; as my package manager, so all I had to do was
run &lt;code&gt;bun add pyodide&lt;/code&gt;. Other package managers should follow a
similar command. You can check out the official Pyodide package &lt;a
href="https://www.npmjs.com/package/pyodide" target="_blank"&gt;on the npm
registry&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="ii.-loading-the-package"&gt;II. Loading the package&lt;/h3&gt;
&lt;p&gt;Getting Pyodide up and running involves a few steps that need to
happen in the right order. First, we need to load the core Pyodide
runtime from a &lt;a
href="https://en.wikipedia.org/wiki/Content_delivery_network"
target="_blank"&gt;CDN&lt;/a&gt;. Then we can use Pyodide’s package manager,
micropip, to install our Python package. This is similar to how you
might use &lt;a href="https://pip.pypa.io/en/stable/installation/"
target="_blank"&gt;pip&lt;/a&gt; in a regular Python environment, but it’s all
happening in the browser.&lt;/p&gt;
&lt;p&gt;One nice thing about Pyodide’s CDN distribution is that it includes
many common Python packages pre-built and ready to use. However, for
packages that aren’t included by default (like my &lt;code&gt;pqg&lt;/code&gt;
package), we need to install them explicitly using micropip. Here’s the
complete initialization sequence:&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
class="sourceCode typescript"&gt;&lt;code class="sourceCode typescript"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; { PyodideInterface&lt;span class="op"&gt;,&lt;/span&gt; loadPyodide } &lt;span class="im"&gt;from&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;pyodide&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Initialize Pyodide with the specified CDN URL&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// This loads the core Python runtime environment into the browser&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-5"&gt;&lt;a href="#cb1-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; client &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="cf"&gt;await&lt;/span&gt; &lt;span class="fu"&gt;loadPyodide&lt;/span&gt;({&lt;/span&gt;
&lt;span id="cb1-6"&gt;&lt;a href="#cb1-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  indexURL&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;https://cdn.jsdelivr.net/pyodide/v0.26.3/full&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-7"&gt;&lt;a href="#cb1-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;})&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-9"&gt;&lt;a href="#cb1-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Load the micropip package, which is Pyodide&amp;#39;s package installer&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-10"&gt;&lt;a href="#cb1-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// This is similar to pip for regular Python, but works in the browser&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-11"&gt;&lt;a href="#cb1-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;await&lt;/span&gt; pyodide&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;loadPackage&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;micropip&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-12"&gt;&lt;a href="#cb1-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-13"&gt;&lt;a href="#cb1-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Import the micropip module into the JavaScript environment&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-14"&gt;&lt;a href="#cb1-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// This allows us to use micropip&amp;#39;s functions from JavaScript&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-15"&gt;&lt;a href="#cb1-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; micropip &lt;span class="op"&gt;=&lt;/span&gt; pyodide&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;pyimport&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;micropip&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-16"&gt;&lt;a href="#cb1-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-17"&gt;&lt;a href="#cb1-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Use micropip to install the &amp;#39;pqg&amp;#39; package from PyPI&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-18"&gt;&lt;a href="#cb1-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// This downloads and installs the pure Python package in the browser environment&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-19"&gt;&lt;a href="#cb1-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;await&lt;/span&gt; micropip&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;install&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;pqg&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s worth noting that this initialization process can take a few
seconds, especially on slower connections. The Pyodide runtime itself is
about &lt;a
href="https://pyodide.org/en/stable/project/roadmap.html#reducing-download-sizes-and-initialization-times"
target="_blank"&gt;6MB&lt;/a&gt;, and any additional packages you install will
add to that. In my case, I found that showing a loading indicator during
this initialization was essential for a good user experience.&lt;/p&gt;
&lt;p&gt;Also, because these operations are asynchronous, you need to be
careful about when you start trying to execute Python code. I learned
the hard way that trying to run code before Pyodide is fully initialized
will fail. This is one of the reasons I eventually moved all of this
into a web worker, which we’ll discuss later.&lt;/p&gt;
&lt;h3 id="iii.-running-code"&gt;III. Running code&lt;/h3&gt;
&lt;p&gt;Now that we have Pyodide and our package loaded, we need to actually
run some Python code. In my case, I needed to generate pandas queries
based on user-defined schemas and settings. One early challenge I
encountered was that Pyodide doesn’t support multiprocessing due to
browser limitations - I had to explicitly disable it in my package’s
configuration to ensure compatibility. Here’s how I structured the code
generation (abridged):&lt;/p&gt;
&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
class="sourceCode typescript"&gt;&lt;code class="sourceCode typescript"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Generate Python code that creates and configures the query generator&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; generateQueryGenerationCode &lt;span class="op"&gt;=&lt;/span&gt; (schema&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; settings&lt;span class="op"&gt;:&lt;/span&gt; Settings) &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vs"&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  import json&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-5"&gt;&lt;a href="#cb2-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  from pqg import Generator, QueryStructure, Schema, QueryPool, GenerateOptions&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-6"&gt;&lt;a href="#cb2-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-7"&gt;&lt;a href="#cb2-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  # Parse the schema from JSON&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  schema = Schema.from_dict(json.loads(&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="sc"&gt;${&lt;/span&gt;schema&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="vs"&gt;&amp;#39;&amp;#39;&amp;#39;))&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-10"&gt;&lt;a href="#cb2-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  # Configure query structure based on user settings&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-11"&gt;&lt;a href="#cb2-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  query_structure = QueryStructure(&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-12"&gt;&lt;a href="#cb2-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    groupby_aggregation_probability=&lt;/span&gt;&lt;span class="sc"&gt;${&lt;/span&gt;settings&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;groupbyProbability&lt;/span&gt;&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="vs"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-13"&gt;&lt;a href="#cb2-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    max_groupby_columns=&lt;/span&gt;&lt;span class="sc"&gt;${&lt;/span&gt;settings&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;maxGroupbyColumns&lt;/span&gt;&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="vs"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-14"&gt;&lt;a href="#cb2-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    # ... other settings&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-15"&gt;&lt;a href="#cb2-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-16"&gt;&lt;a href="#cb2-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-17"&gt;&lt;a href="#cb2-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  generator = Generator(schema, query_structure)&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-18"&gt;&lt;a href="#cb2-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-19"&gt;&lt;a href="#cb2-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  generate_options = GenerateOptions(&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-20"&gt;&lt;a href="#cb2-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    ensure_non_empty=&lt;/span&gt;&lt;span class="sc"&gt;${&lt;/span&gt;settings&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;enforceNonEmptyResults&lt;/span&gt; &lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;True&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;False&amp;#39;&lt;/span&gt;&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="vs"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-21"&gt;&lt;a href="#cb2-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    multi_line=&lt;/span&gt;&lt;span class="sc"&gt;${&lt;/span&gt;settings&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;multiLine&lt;/span&gt; &lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;True&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;False&amp;#39;&lt;/span&gt;&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="vs"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-22"&gt;&lt;a href="#cb2-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    multi_processing=False,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-23"&gt;&lt;a href="#cb2-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    num_queries=&lt;/span&gt;&lt;span class="sc"&gt;${&lt;/span&gt;settings&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;numQueries&lt;/span&gt;&lt;span class="sc"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-24"&gt;&lt;a href="#cb2-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-25"&gt;&lt;a href="#cb2-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-26"&gt;&lt;a href="#cb2-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  query_pool = generator.generate(generate_options)&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-27"&gt;&lt;a href="#cb2-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-28"&gt;&lt;a href="#cb2-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  # Return results as JSON&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-29"&gt;&lt;a href="#cb2-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  json.dumps({&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-30"&gt;&lt;a href="#cb2-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    &amp;#39;queries&amp;#39;: [str(query) for query in query_pool],&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-31"&gt;&lt;a href="#cb2-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;    # ... other keys&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-32"&gt;&lt;a href="#cb2-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-33"&gt;&lt;a href="#cb2-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="vs"&gt;`&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-34"&gt;&lt;a href="#cb2-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-35"&gt;&lt;a href="#cb2-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Execute the code using Pyodide&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-36"&gt;&lt;a href="#cb2-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; response &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="cf"&gt;await&lt;/span&gt; client&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;runPythonAsync&lt;/span&gt;(&lt;span class="fu"&gt;generateQueryGenerationCode&lt;/span&gt;(schema&lt;span class="op"&gt;,&lt;/span&gt; settings))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The key here is that we’re generating a Python code string that will
be executed by Pyodide. We interpolate JavaScript values (the schema and
settings) into the Python code string. This allows us to pass
configuration from our React UI to the Python runtime.&lt;/p&gt;
&lt;p&gt;One important detail is that we need to handle the data serialization
carefully. Since we’re crossing the JavaScript-Python boundary, we use
JSON as our data format. The Python code parses the JSON schema and
returns its results as JSON, which can then be parsed back into
JavaScript objects.&lt;/p&gt;
&lt;h3 id="iv.-inside-a-web-worker"&gt;IV. Inside a web worker&lt;/h3&gt;
&lt;p&gt;When I first implemented this, I quickly realized that loading and
running Python in the main thread wasn’t ideal - it would freeze the UI
during initialization and execution. The solution was to move all
Pyodide-related code into a &lt;a
href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"
target="_blank"&gt;web worker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here’s how I built the worker interface (abridged):&lt;/p&gt;
&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
class="sourceCode typescript"&gt;&lt;code class="sourceCode typescript"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; { useEffect&lt;span class="op"&gt;,&lt;/span&gt; useRef&lt;span class="op"&gt;,&lt;/span&gt; useState } &lt;span class="im"&gt;from&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;react&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; { useToast } &lt;span class="im"&gt;from&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;./use-toast&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; WorkerStatus &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;idle&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;loading&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;ready&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; WorkerResponse &lt;span class="op"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; payload&lt;span class="op"&gt;:&lt;/span&gt; WorkerStatus }&lt;/span&gt;
&lt;span id="cb3-9"&gt;&lt;a href="#cb3-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt; }&lt;/span&gt;
&lt;span id="cb3-10"&gt;&lt;a href="#cb3-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;result&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt; }&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-11"&gt;&lt;a href="#cb3-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-12"&gt;&lt;a href="#cb3-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;export&lt;/span&gt; &lt;span class="kw"&gt;const&lt;/span&gt; usePyodideWorker &lt;span class="op"&gt;=&lt;/span&gt; () &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb3-13"&gt;&lt;a href="#cb3-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;const&lt;/span&gt; [status&lt;span class="op"&gt;,&lt;/span&gt; setStatus] &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;useState&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;WorkerStatus&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;idle&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-14"&gt;&lt;a href="#cb3-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-15"&gt;&lt;a href="#cb3-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;const&lt;/span&gt; workerRef &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;useRef&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="bu"&gt;Worker&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-16"&gt;&lt;a href="#cb3-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-17"&gt;&lt;a href="#cb3-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;const&lt;/span&gt; { toast } &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;useToast&lt;/span&gt;()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-18"&gt;&lt;a href="#cb3-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-19"&gt;&lt;a href="#cb3-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;useEffect&lt;/span&gt;(() &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb3-20"&gt;&lt;a href="#cb3-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    workerRef&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;current&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="bu"&gt;Worker&lt;/span&gt;(&lt;/span&gt;
&lt;span id="cb3-21"&gt;&lt;a href="#cb3-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="fu"&gt;URL&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;../workers/pyodide.worker.ts&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; import&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;meta&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;url&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-22"&gt;&lt;a href="#cb3-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;module&amp;#39;&lt;/span&gt; }&lt;/span&gt;
&lt;span id="cb3-23"&gt;&lt;a href="#cb3-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-24"&gt;&lt;a href="#cb3-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-25"&gt;&lt;a href="#cb3-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    workerRef&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;current&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;onmessage&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; (event&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="bu"&gt;MessageEvent&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;WorkerResponse&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb3-26"&gt;&lt;a href="#cb3-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="kw"&gt;const&lt;/span&gt; { &lt;span class="kw"&gt;type&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; payload } &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="bu"&gt;event&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;data&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-27"&gt;&lt;a href="#cb3-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-28"&gt;&lt;a href="#cb3-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="cf"&gt;switch&lt;/span&gt; (&lt;span class="kw"&gt;type&lt;/span&gt;) {&lt;/span&gt;
&lt;span id="cb3-29"&gt;&lt;a href="#cb3-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-30"&gt;&lt;a href="#cb3-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="fu"&gt;setStatus&lt;/span&gt;(payload)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-31"&gt;&lt;a href="#cb3-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="cf"&gt;break&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-32"&gt;&lt;a href="#cb3-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-33"&gt;&lt;a href="#cb3-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="co"&gt;// ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-34"&gt;&lt;a href="#cb3-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="fu"&gt;setStatus&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-35"&gt;&lt;a href="#cb3-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="cf"&gt;break&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-36"&gt;&lt;a href="#cb3-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      }&lt;/span&gt;
&lt;span id="cb3-37"&gt;&lt;a href="#cb3-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-38"&gt;&lt;a href="#cb3-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-39"&gt;&lt;a href="#cb3-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    workerRef&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;current&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;postMessage&lt;/span&gt;({ type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;init&amp;#39;&lt;/span&gt; })&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-40"&gt;&lt;a href="#cb3-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-41"&gt;&lt;a href="#cb3-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; () &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb3-42"&gt;&lt;a href="#cb3-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      workerRef&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;current&lt;/span&gt;&lt;span class="op"&gt;?.&lt;/span&gt;&lt;span class="fu"&gt;terminate&lt;/span&gt;()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-43"&gt;&lt;a href="#cb3-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-44"&gt;&lt;a href="#cb3-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;span class="op"&gt;,&lt;/span&gt; [toast])&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-45"&gt;&lt;a href="#cb3-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-46"&gt;&lt;a href="#cb3-46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;const&lt;/span&gt; runPython &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;async&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;(code&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt;)&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="bu"&gt;Promise&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb3-47"&gt;&lt;a href="#cb3-47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="bu"&gt;Promise&lt;/span&gt;((resolve&lt;span class="op"&gt;,&lt;/span&gt; reject) &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb3-48"&gt;&lt;a href="#cb3-48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="co"&gt;// ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-49"&gt;&lt;a href="#cb3-49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    })&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-50"&gt;&lt;a href="#cb3-50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-51"&gt;&lt;a href="#cb3-51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-52"&gt;&lt;a href="#cb3-52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb3-53"&gt;&lt;a href="#cb3-53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    error&lt;span class="op"&gt;:&lt;/span&gt; status &lt;span class="op"&gt;===&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-54"&gt;&lt;a href="#cb3-54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    loading&lt;span class="op"&gt;:&lt;/span&gt; status &lt;span class="op"&gt;===&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;loading&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-55"&gt;&lt;a href="#cb3-55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ready&lt;span class="op"&gt;:&lt;/span&gt; status &lt;span class="op"&gt;===&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;ready&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-56"&gt;&lt;a href="#cb3-56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runPython&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-57"&gt;&lt;a href="#cb3-57" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-58"&gt;&lt;a href="#cb3-58" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;}&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I created this as a React &lt;a
href="https://react.dev/learn#using-hooks" target="_blank"&gt;hook&lt;/a&gt; that
manages the worker lifecycle. The hook creates the worker when the
component mounts and provides a &lt;a
href="https://github.com/DISLMcGill/pandas-query-generator/blob/303251c5f4ae4bdcdc945caac0c0f21a22fda56f/www/src/hooks/use-pyodide-worker.ts#L52"
target="_blank"&gt;&lt;code&gt;runPython&lt;/code&gt;&lt;/a&gt; function that components can
use to execute Python code. The status updates help the UI show loading
states while Pyodide initializes or executes code.&lt;/p&gt;
&lt;p&gt;The worker implementation itself is relatively straightforward:&lt;/p&gt;
&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
class="sourceCode typescript"&gt;&lt;code class="sourceCode typescript"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; { PyodideInterface&lt;span class="op"&gt;,&lt;/span&gt; loadPyodide } &lt;span class="im"&gt;from&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;pyodide&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; pyodide&lt;span class="op"&gt;:&lt;/span&gt; PyodideInterface&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; WorkerMessage &lt;span class="op"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-6"&gt;&lt;a href="#cb4-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;init&amp;#39;&lt;/span&gt; }&lt;/span&gt;
&lt;span id="cb4-7"&gt;&lt;a href="#cb4-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;run&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; payload&lt;span class="op"&gt;:&lt;/span&gt; { code&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt; } }&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-8"&gt;&lt;a href="#cb4-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; WorkerResponse &lt;span class="op"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;loading&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;ready&amp;#39;&lt;/span&gt; }&lt;/span&gt;
&lt;span id="cb4-11"&gt;&lt;a href="#cb4-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt; }&lt;/span&gt;
&lt;span id="cb4-12"&gt;&lt;a href="#cb4-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; { type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;result&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt; }&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-13"&gt;&lt;a href="#cb4-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-14"&gt;&lt;a href="#cb4-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;self&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;onmessage&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;async&lt;/span&gt; (event&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="bu"&gt;MessageEvent&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;WorkerMessage&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="kw"&gt;=&amp;gt;&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb4-15"&gt;&lt;a href="#cb4-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;const&lt;/span&gt; { &lt;span class="kw"&gt;type&lt;/span&gt; } &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="bu"&gt;event&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;data&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-16"&gt;&lt;a href="#cb4-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-17"&gt;&lt;a href="#cb4-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;try&lt;/span&gt; {&lt;/span&gt;
&lt;span id="cb4-18"&gt;&lt;a href="#cb4-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;switch&lt;/span&gt; (&lt;span class="kw"&gt;type&lt;/span&gt;) {&lt;/span&gt;
&lt;span id="cb4-19"&gt;&lt;a href="#cb4-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;init&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-20"&gt;&lt;a href="#cb4-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;if&lt;/span&gt; (&lt;span class="op"&gt;!&lt;/span&gt;pyodide) {&lt;/span&gt;
&lt;span id="cb4-21"&gt;&lt;a href="#cb4-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          self&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;postMessage&lt;/span&gt;({&lt;/span&gt;
&lt;span id="cb4-22"&gt;&lt;a href="#cb4-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-23"&gt;&lt;a href="#cb4-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;loading&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-24"&gt;&lt;a href="#cb4-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          } satisfies WorkerResponse)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-25"&gt;&lt;a href="#cb4-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-26"&gt;&lt;a href="#cb4-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          pyodide &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="cf"&gt;await&lt;/span&gt; &lt;span class="fu"&gt;loadPyodide&lt;/span&gt;({&lt;/span&gt;
&lt;span id="cb4-27"&gt;&lt;a href="#cb4-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            indexURL&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;https://cdn.jsdelivr.net/pyodide/v0.26.3/full&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-28"&gt;&lt;a href="#cb4-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          })&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-29"&gt;&lt;a href="#cb4-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-30"&gt;&lt;a href="#cb4-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="cf"&gt;await&lt;/span&gt; pyodide&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;loadPackage&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;micropip&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-31"&gt;&lt;a href="#cb4-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-32"&gt;&lt;a href="#cb4-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="kw"&gt;const&lt;/span&gt; micropip &lt;span class="op"&gt;=&lt;/span&gt; pyodide&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;pyimport&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;micropip&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-33"&gt;&lt;a href="#cb4-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="cf"&gt;await&lt;/span&gt; micropip&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;install&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;pqg&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-34"&gt;&lt;a href="#cb4-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-35"&gt;&lt;a href="#cb4-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          self&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;postMessage&lt;/span&gt;({&lt;/span&gt;
&lt;span id="cb4-36"&gt;&lt;a href="#cb4-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-37"&gt;&lt;a href="#cb4-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;ready&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-38"&gt;&lt;a href="#cb4-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          } satisfies WorkerResponse)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-39"&gt;&lt;a href="#cb4-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="cb4-40"&gt;&lt;a href="#cb4-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;break&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-41"&gt;&lt;a href="#cb4-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;run&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-42"&gt;&lt;a href="#cb4-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;if&lt;/span&gt; (&lt;span class="op"&gt;!&lt;/span&gt;pyodide) &lt;span class="cf"&gt;throw&lt;/span&gt; &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt;(&lt;span class="st"&gt;&amp;#39;Pyodide not initialized&amp;#39;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-43"&gt;&lt;a href="#cb4-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-44"&gt;&lt;a href="#cb4-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        self&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;postMessage&lt;/span&gt;({&lt;/span&gt;
&lt;span id="cb4-45"&gt;&lt;a href="#cb4-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;result&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-46"&gt;&lt;a href="#cb4-46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          payload&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="cf"&gt;await&lt;/span&gt; pyodide&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;runPythonAsync&lt;/span&gt;(&lt;span class="bu"&gt;event&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;data&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;payload&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;code&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-47"&gt;&lt;a href="#cb4-47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        } satisfies WorkerResponse)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-48"&gt;&lt;a href="#cb4-48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-49"&gt;&lt;a href="#cb4-49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;break&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-50"&gt;&lt;a href="#cb4-50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="cf"&gt;default&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-51"&gt;&lt;a href="#cb4-51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;throw&lt;/span&gt; &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt;(&lt;span class="vs"&gt;`Unknown message type: &lt;/span&gt;&lt;span class="sc"&gt;${&lt;/span&gt;&lt;span class="kw"&gt;type&lt;/span&gt; satisfies &lt;span class="dt"&gt;never&lt;/span&gt;&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="vs"&gt;`&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-52"&gt;&lt;a href="#cb4-52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="cb4-53"&gt;&lt;a href="#cb4-53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  } &lt;span class="cf"&gt;catch&lt;/span&gt; (error) {&lt;/span&gt;
&lt;span id="cb4-54"&gt;&lt;a href="#cb4-54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    self&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;postMessage&lt;/span&gt;({&lt;/span&gt;
&lt;span id="cb4-55"&gt;&lt;a href="#cb4-55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      type&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-56"&gt;&lt;a href="#cb4-56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      payload&lt;span class="op"&gt;:&lt;/span&gt; error &lt;span class="kw"&gt;instanceof&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;?&lt;/span&gt; error&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="at"&gt;message&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;Unknown error&amp;#39;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-57"&gt;&lt;a href="#cb4-57" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } satisfies WorkerResponse)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-58"&gt;&lt;a href="#cb4-58" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id="cb4-59"&gt;&lt;a href="#cb4-59" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;}&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The worker maintains the Pyodide instance and handles two types of
messages: initialization and code execution. This keeps all the heavy
lifting off the main thread, ensuring the UI stays responsive.&lt;/p&gt;
&lt;p&gt;One thing to note is that web workers have their own &lt;a
href="https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope"
target="_blank"&gt;global scope&lt;/a&gt;, so the Pyodide instance and any
installed packages persist between executions. This is actually
beneficial as it means we only need to load Pyodide and install packages
once, rather than for each query generation.&lt;/p&gt;
&lt;h3 id="fin"&gt;Fin&lt;/h3&gt;
&lt;p&gt;Building this interface turned out to be surprisingly straightforward
thanks to Pyodide. The ability to run Python code directly in the
browser, without needing a backend server, makes for a great developer
experience. The combination of React for the UI, Pyodide for Python
execution, and web workers for performance created a smooth, interactive
interface for my Python package.&lt;/p&gt;
&lt;p&gt;While there are &lt;a
href="https://pyodide.org/en/stable/usage/wasm-constraints.html"
target="_blank"&gt;some limitations&lt;/a&gt; - Pyodide can only run pure Python
packages, and the initial load time can be significant - it’s a powerful
tool for the right use case. In my case, it allowed me to create a web
interface for my Python package with minimal overhead and deployment
complexity.&lt;/p&gt;
&lt;p&gt;The full code for the implementation can be &lt;a
href="https://github.com/DISLMcGill/pandas-query-generator/tree/master/www"
target="_blank"&gt;found on GitHub&lt;/a&gt;.&lt;/p&gt;</description>
<link>https://liam.rs/posts/Python-in-the-browser/</link>
<pubDate>Fri, 13 Dec 2024 05:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Python-in-the-browser/</guid>
</item>
<item>
<title>Incremental-select-with-treesitter</title>
<description>&lt;p&gt;&lt;a href="https://github.com/tree-sitter/tree-sitter"
target="_blank"&gt;treesitter&lt;/a&gt; is a tool that can build a concrete
syntax tree for a source file and incrementally update the tree as the
file is modified.&lt;/p&gt;
&lt;p&gt;Recently, I’ve been experimenting more and more with treesitter’s &lt;a
href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries"
target="_blank"&gt;query DSL&lt;/a&gt; and an abstraction layer in the form of a
&lt;a href="https://github.com/nvim-treesitter/nvim-treesitter"
target="_blank"&gt;neovim plugin&lt;/a&gt;, and found a configuration option to
be particularly useful when editing code: &lt;em&gt;incremental
selection&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When you write a treesitter parser, you must write a grammar that
treesitter can read, which it then uses to generate the parser. This
grammar specifies the named syntax nodes in the tree and how they relate
to other nodes.&lt;/p&gt;
&lt;p&gt;For instance, if we head over to the &lt;a
href="https://tree-sitter.github.io/tree-sitter/7-playground.html"
target="_blank"&gt;syntax tree playground&lt;/a&gt; and parse rust source code
that looks like this:&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;println!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Hello, world!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;we get the following syntax tree output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;source_file [0, 0] - [3, 0]
  function_item [0, 0] - [2, 1]
    name: identifier [0, 3] - [0, 7]
    parameters: parameters [0, 7] - [0, 9]
    body: block [0, 10] - [2, 1]
      macro_invocation [1, 2] - [1, 27]
        macro: identifier [1, 2] - [1, 9]
        token_tree [1, 10] - [1, 27]
          string_literal [1, 11] - [1, 26]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The neovim plugin written as an abstraction layer for treesitter
usage within neovim is able to parse your source file as you type. That
is, it’s able to compute a syntax tree that resembles the one shown
above, on the fly.&lt;/p&gt;
&lt;p&gt;As you hover over a certain part of a file, it is able to detect
which node you’re currently at in the tree.&lt;/p&gt;
&lt;p&gt;The plugin includes a configuration option which allows for the
setting of keybindings for initializing a node selection and
incrementing a selected node range – configured like so:&lt;/p&gt;
&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
class="sourceCode lua"&gt;&lt;code class="sourceCode lua"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;incremental_selection&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="va"&gt;enable&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="va"&gt;keymaps&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;init_selection&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;cr&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;node_incremental&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;grn&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;scope_incremental&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;grc&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;node_decremental&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;grm&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-9"&gt;&lt;a href="#cb3-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Incremental selection has improved the rapidity in which I can yank
or replace blocks of text in treesitter parsed source files, as
expanding a node selection with a keybinding is super fast and usually
results in the exact block of text I want to modify.&lt;/p&gt;
&lt;p&gt;Here’s a quick demo of it in action:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://asciinema.org/a/507405" target="_blank"&gt;&lt;img
src="https://asciinema.org/a/507405.svg" alt="asciicast" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A reference of my full neovim configuration can be found on github,
in my &lt;a href="https://github.com/terror/dotfiles"
target="_blank"&gt;dotfiles&lt;/a&gt; repo. Be sure to check it out!&lt;/p&gt;</description>
<link>https://liam.rs/posts/Incremental-select-with-treesitter/</link>
<pubDate>Sat, 09 Jul 2022 04:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Incremental-select-with-treesitter/</guid>
</item>
<item>
<title>Powerful-`just`-features</title>
<description>&lt;p&gt;&lt;a href="https://github.com/casey/just"
target="_blank"&gt;&lt;code&gt;just&lt;/code&gt;&lt;/a&gt; is a command runner written in
Rust. Commands, or &lt;em&gt;recipes&lt;/em&gt; in &lt;code&gt;just&lt;/code&gt; lingo, are
populated in a file called ‘justfile’, and are expressed in a make-like
syntax.&lt;/p&gt;
&lt;p&gt;I’ve been using &lt;code&gt;just&lt;/code&gt; as my command runner for all of my
projects, big or small, and find it extremely useful to have a file in
the projects root that contains every command needed to interact with
the project.&lt;/p&gt;
&lt;p&gt;There are quite a few features baked into this program that make it
unique from similar projects, which I find nice to have when crafting
software. This post simply documents the few I use most often.&lt;/p&gt;
&lt;h3 id="contents"&gt;Contents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#aliases"&gt;Aliases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#fuzzy-searching-recipes"&gt;Fuzzy searching recipes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#recipes-in-arbitrary-languages"&gt;Recipes in arbitrary
languages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#taking-advantage-of-the-default-recipe"&gt;Taking advantage
of the default recipe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#recipe-dependencies"&gt;Recipe dependencies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#format-your-justfile"&gt;Format your justfile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#documenting-recipes"&gt;Documenting recipes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aliases"&gt;Aliases&lt;/h3&gt;
&lt;p&gt;Recipes can have aliases, or alternative names which refer to the
original recipe that can be used with &lt;code&gt;just&lt;/code&gt; to invoke the
original recipe.&lt;/p&gt;
&lt;p&gt;For instance, if you have a recipe called &lt;code&gt;run&lt;/code&gt;, you can
alias it to &lt;code&gt;r&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alias r := run

run:
  cargo run&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and invoke it with &lt;code&gt;just r&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Somewhat related side note: consider aliasing the &lt;code&gt;just&lt;/code&gt;
command to &lt;code&gt;j&lt;/code&gt;, it’ll save you some typing if you frequently
execute commands with &lt;code&gt;just&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="fuzzy-searching-recipes"&gt;Fuzzy searching recipes&lt;/h3&gt;
&lt;p&gt;One feature I discovered recently is &lt;code&gt;just --choose&lt;/code&gt;,
which lets you fuzzy search through recipes defined in your justfile.
You can also specify a chooser by passing it into
&lt;code&gt;just --chooser&lt;/code&gt;, else it will default to using &lt;a
href="https://github.com/junegunn/fzf"
target="_blank"&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is work planned to support recipe previews and command line
arguments for recipes that take them when using the default chooser.&lt;/p&gt;
&lt;p&gt;However, with the help of &lt;code&gt;just --summary&lt;/code&gt;,
&lt;code&gt;just --show&lt;/code&gt; and a bit of &lt;a
href="https://en.wikipedia.org/wiki/Python_(programming_language)"
target="_blank"&gt;Python&lt;/a&gt;, here’s how you can get to look:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://asciinema.org/a/eNi5cZw4BZLcplHq4Ae1aN8nN"
target="_blank"&gt;&lt;img
src="https://asciinema.org/a/eNi5cZw4BZLcplHq4Ae1aN8nN.svg"
alt="asciicast" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="recipes-in-arbitrary-languages"&gt;Recipes in arbitrary
languages&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;just&lt;/code&gt; recipes can be expressed in another language by
adding a shebang at the top of the recipe, as they get executed as
scripts by the shell.&lt;/p&gt;
&lt;p&gt;For instance, we can write a small script in Python that lists the
contents of the current directory, and put it in a recipe:&lt;/p&gt;
&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ls:&lt;/span&gt;
&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="co"&gt;#!/usr/bin/env python3&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="im"&gt;import&lt;/span&gt; os&lt;/span&gt;
&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="op"&gt;*&lt;/span&gt;os.listdir())&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="taking-advantage-of-the-default-recipe"&gt;Taking advantage of the
default recipe&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;just&lt;/code&gt; allows you to specify a &lt;code&gt;default&lt;/code&gt; recipe
that gets executed when invoking &lt;code&gt;just&lt;/code&gt; without any arguments
in a directory that contains a justfile (or a sub-directory in which a
parent directory contains a justfile).&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default:
  just --list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I usually use this feature to list out all recipes that are available
in the justfile however this could be used for anything that merits
being quickly invoked with a single command.&lt;/p&gt;
&lt;h3 id="recipe-dependencies"&gt;Recipe dependencies&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;just&lt;/code&gt; recipes can contain ‘dependencies’, or other
recipes that should be ran &lt;em&gt;before&lt;/em&gt; a given recipe.&lt;/p&gt;
&lt;p&gt;For example, let’s say you have a ‘build’ recipe and want to run
tests – specified in a ‘test’ recipe – each time before executing the
contents of the recipe, you can do so by making ‘test’ a dependency of
‘build’, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default:
  just --list

build: test # this is a dependency
  cargo build

test:
  cargo test&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also comes in handy when you want to run multiple recipes in
sequence, &lt;code&gt;just&lt;/code&gt; allows for a very expressive syntax via
dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default:
  just --list

all: build test fmt

build:
  cargo build

test:
  cargo test

fmt:
  cargo +nightly fmt&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="format-your-justfile"&gt;Format your justfile&lt;/h3&gt;
&lt;p&gt;As of recently, &lt;code&gt;just&lt;/code&gt; supports justfile formatting via
the &lt;code&gt;--fmt&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;It currently requires the &lt;code&gt;--unstable&lt;/code&gt; flag, like so:&lt;/p&gt;
&lt;div class="sourceCode" id="cb6"&gt;&lt;pre
class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; just &lt;span class="at"&gt;--fmt&lt;/span&gt; &lt;span class="at"&gt;--unstable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Invoking the command above can turn a justfile that looks like
this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default:
    just --list

build:
        cargo build

test:
    cargo test

clippy:
            cargo clippy --all-targets --all-features&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;into this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default:
  just --list

build:
  cargo build

test:
  cargo test

clippy:
  cargo clippy --all-targets --all-features&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be useful if you have many people working on your project
and recipes get added or modified in your projects justfile on the
regular.&lt;/p&gt;
&lt;h3 id="documenting-recipes"&gt;Documenting recipes&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;just&lt;/code&gt; allows for comments above recipes that get appeared
when invoking &lt;code&gt;just --list&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, here is a sample justfile with a &lt;code&gt;run&lt;/code&gt; recipe
that contains a comment above it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Run the project
run:
  cargo run&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;invoking &lt;code&gt;just --list&lt;/code&gt; will yield the following
output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Available recipes:
    run # Run the project&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is extremely useful for documenting obscure commands, especially
when working in teams where people come and go on a project
frequently.&lt;/p&gt;
&lt;h3 id="fin"&gt;Fin&lt;/h3&gt;
&lt;p&gt;I personally think any project could benefit greatly by having a
single source of truth in regards to project specific commands, and
&lt;code&gt;just&lt;/code&gt; provides a simple way to set that up.&lt;/p&gt;
&lt;p&gt;Have a look over at the &lt;a href="https://github.com/casey/just"
target="_blank"&gt;official readme&lt;/a&gt; document on GitHub for more
information and further elaboration on the features mentioned here.&lt;/p&gt;</description>
<link>https://liam.rs/posts/Powerful-`just`-features/</link>
<pubDate>Tue, 12 Apr 2022 04:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Powerful-`just`-features/</guid>
</item>
<item>
<title>Scripting-in-markdown</title>
<description>&lt;p&gt;I recently wrote yet another command-line utility in Rust called &lt;a
href="https://github.com/terror/present"
target="_blank"&gt;&lt;code&gt;present&lt;/code&gt;&lt;/a&gt; that lets you interpolate the
standard output of arbitrary commands that get interpreted by the shell
into a markdown file, and I thought I’d share a bit about it here.&lt;/p&gt;
&lt;h3 id="problem"&gt;Problem&lt;/h3&gt;
&lt;p&gt;The main problem I kept running into that pushed me to write this
tool was having to &lt;em&gt;manually&lt;/em&gt; update the outputs of command line
utility help messages in my project readme documents.&lt;/p&gt;
&lt;p&gt;For instance, I wrote a command-line utility called &lt;a
href="https://github.com/terror/vim-profiler"
target="_blank"&gt;&lt;code&gt;vim-profiler&lt;/code&gt;&lt;/a&gt; that lets you profile the
startup-time for your installed vim plugins and receive a nicely
formatted output. In the readme document I have a usage section that
includes the output of calling &lt;code&gt;vp --help&lt;/code&gt;. Each time I make
a version change, update the description, or update the API – the result
of calling &lt;code&gt;vp --help&lt;/code&gt; changes, which prompts me to update
the readme.&lt;/p&gt;
&lt;h3 id="solution"&gt;Solution&lt;/h3&gt;
&lt;p&gt;Instead of invoking the binary with the &lt;code&gt;--help&lt;/code&gt; flag,
piping the result to &lt;code&gt;pbcopy&lt;/code&gt; and then manually pasting the
chunk into the appropriate section within the readme myself, I can now
have &lt;code&gt;present&lt;/code&gt; do all of that for me.&lt;/p&gt;
&lt;p&gt;Here’s how that looks like:&lt;/p&gt;
&lt;ol type="1"&gt;
&lt;li&gt;Include the command at the start of a fenced codeblock using the
&lt;code&gt;present&lt;/code&gt; prefix&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;## vim-profiler 🕒

...

### Usage

```present cargo run -- --help
```
...&lt;/code&gt;&lt;/pre&gt;
&lt;ol start="2" type="1"&gt;
&lt;li&gt;Run &lt;code&gt;present&lt;/code&gt; on the markdown file&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; present &lt;span class="at"&gt;--in-place&lt;/span&gt; &lt;span class="at"&gt;--path&lt;/span&gt; readme.md&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="3" type="1"&gt;
&lt;li&gt;View the modified document!&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;## vim-profiler 🕒

...

### Usage

```cargo run -- --help
vim-profiler 0.0.4
A vim profiling tool.

USAGE:
    vp [FLAGS] [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -r, --reverse    Display the plugin times in reverse order (fastest first)
    -s, --sys        Show system plugins in the output
    -V, --version    Prints version information
    -v, --verbose    Add informative messages during program execution

OPTIONS:
    -c, --command   &amp;lt;command&amp;gt;      The command to run, e.g vim or neovim [default: vim]
    -n, --count     &amp;lt;count&amp;gt;        The number of plugins to list in the output
    -e, --export    &amp;lt;path&amp;gt;         Export the results to a CSV file
    -f, --file      &amp;lt;file&amp;gt;         A file to open
    -i, --iter      &amp;lt;iter&amp;gt;         The number of iterations
    -p, --plot      &amp;lt;path&amp;gt;         Plot the data and save it to a SVG file
    -x, --precision &amp;lt;precision&amp;gt;    Precision in the output
```
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In practice, I’ll add the command in a justfile &lt;code&gt;all&lt;/code&gt;
recipe that I invoke before I commit any changes, such as shown in this
&lt;a href="https://github.com/terror/present/blob/master/justfile"
target="_blank"&gt;justfile&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="moving-forward"&gt;Moving forward&lt;/h3&gt;
&lt;p&gt;The project is still in its early stages of development, and there
most certainly exists a few non-trivial bugs to be found and fixed.&lt;/p&gt;
&lt;p&gt;Some things on the todo list, in no particular order, include:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Improve diff output in interactive mode&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The project uses the &lt;a href="https://github.com/mitsuhiko/similar"
target="_blank"&gt;&lt;code&gt;similar&lt;/code&gt;&lt;/a&gt; crate to help with diff output
in interactive mode, but it can be made nicer by taking advantage of
additional features the crate has to offer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Support same-line command interpolation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This isn’t that important, but it would be nice to support having
backticks remain on the same line and have the command result get
interpolated with the appropriate newlines. e.g&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-&amp;gt; ```echo foo```

-&amp;gt; ```echo foo
   foo
   ```&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Handle quotes as a single argument&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This would let you actually write inline bash scripts, e.g
&lt;code&gt;/bin/bash -c 'for i in *; do echo "$i"; done'&lt;/code&gt;. As of right
now, the program just splits the entire command string on whitespace,
which the shell doesn’t like in certain situations.&lt;/p&gt;
&lt;p&gt;This however, for now, can be hacked around by simply including the
script in a justfile or makefile and invoking
&lt;code&gt;just &amp;lt;name&amp;gt;&lt;/code&gt; or &lt;code&gt;make &amp;lt;name&amp;gt;&lt;/code&gt; within
the markdown file.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Get rid of &lt;code&gt;pulldown_cmark&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The project uses the &lt;a
href="https://github.com/raphlinus/pulldown-cmark"
target="_blank"&gt;&lt;code&gt;pulldown_cmark&lt;/code&gt;&lt;/a&gt; crate to get full
codeblock ranges within the source, and then hackily turns them into two
separate ranges (start, end) which represent the starting and ending
range of a single codeblock. This could probably be done better, perhaps
without depending on a library for that initial step.&lt;/p&gt;
&lt;p&gt;Overall, I get what I need out of the program as it is. Whether or
not the aforementioned todo’s provide useful to someone else will most
likely have a non-trivial amount of impact on my motivation for getting
them done.&lt;/p&gt;
&lt;p&gt;Feel free to check out the code over on github &lt;a
href="https://github.com/terror/present"
target="_blank"&gt;https://github.com/terror/present&lt;/a&gt;. It is licensed
under the highly permissive &lt;a
href="https://en.wikipedia.org/wiki/Creative_Commons_license"
target="_blank"&gt;CC0-1.0&lt;/a&gt; license.&lt;/p&gt;</description>
<link>https://liam.rs/posts/Scripting-in-markdown/</link>
<pubDate>Sun, 27 Feb 2022 05:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Scripting-in-markdown/</guid>
</item>
<item>
<title>From-bash-to-vim-and-back</title>
<description>&lt;p&gt;I recently ran the following command to get my top 5 most used &lt;a
href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)"
target="_blank"&gt;Bash&lt;/a&gt; commands:&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; history &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;awk&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;sort&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;uniq&lt;/span&gt; &lt;span class="at"&gt;-c&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;sort&lt;/span&gt; &lt;span class="at"&gt;-nr&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;head&lt;/span&gt; &lt;span class="at"&gt;-5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and here is what came up:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;20793 lt
10124 lv
9328 v
8686 j
7243 gst&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are, for the most part – ordinary, everyday commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lt&lt;/code&gt;: alias for &lt;code&gt;tree -L 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v&lt;/code&gt;: alias for &lt;code&gt;nvim&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;j&lt;/code&gt;: alias for &lt;code&gt;just&lt;/code&gt;, &lt;a
href="https://github.com/casey/just" target="_blank"&gt;the fabulous
command runner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gst&lt;/code&gt;: alias for &lt;code&gt;git status&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I assume isn’t so obvious is &lt;code&gt;lv&lt;/code&gt;, which stands for
‘last vim’. &lt;code&gt;lv&lt;/code&gt; is an alias for the command
&lt;code&gt;nvim -c "normal '0" -c bd1&lt;/code&gt;, which opens the last opened
file at the last cursor position in a new Neovim buffer.&lt;/p&gt;
&lt;p&gt;To break the command down a bit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nvim&lt;/code&gt;: the Neovim binary&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c &amp;lt;cmd&amp;gt;&lt;/code&gt;: Execute &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt; after
config and first file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;normal '0&lt;/code&gt;: The last set cursor position and file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bd1&lt;/code&gt;: Delete the first buffer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use &lt;a href="https://en.wikipedia.org/wiki/Vim_(text_editor)"
target="_blank"&gt;Neovim&lt;/a&gt; alot, and sometimes I quit the editor to run
some arbitrary Bash command. Without having to search for the previously
opened file, I invoke &lt;code&gt;lv&lt;/code&gt;, which gets me back to where I was
at.&lt;/p&gt;
&lt;p&gt;From bash to vim and back, in a flash.&lt;/p&gt;</description>
<link>https://liam.rs/posts/From-bash-to-vim-and-back/</link>
<pubDate>Fri, 25 Feb 2022 05:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/From-bash-to-vim-and-back/</guid>
</item>
<item>
<title>Ergonomic-error-handling-in-Rust</title>
<description>&lt;p&gt;There are many ways you can handle errors in Rust programs: panic at
every fallible situation, propagate foreign errors up the call stack,
craft your own error type.&lt;/p&gt;
&lt;p&gt;I’ve recently fallen into a comfortable pattern when dealing with
errors in Rust and believe it serves great for small or large
projects.&lt;/p&gt;
&lt;p&gt;This post will walk through a few different ways to handle errors and
then ultimately introduce the &lt;a
href="https://github.com/shepmaster/snafu"
target="_blank"&gt;&lt;code&gt;snafu&lt;/code&gt;&lt;/a&gt; library as a clean and ergonomic
solution to the elusive task of dealing with erroneous behaviour.&lt;/p&gt;
&lt;h3 id="contents"&gt;Contents&lt;/h3&gt;
&lt;!--ts--&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#panic-at-the-disco"&gt;Panic! at the disco&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#recoverable-errors-with-resultt-e"&gt;Recoverable errors with
Result&amp;lt;T, E&amp;gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#crafting-custom-error-types"&gt;Crafting custom error
types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#enter-snafu"&gt;Enter snafu&lt;/a&gt; &lt;!--te--&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="panic-at-the-disco"&gt;Panic! at the disco&lt;/h3&gt;
&lt;p&gt;Let’s say we have some arbitrary text file on disk that we want to
read from, and depending on the content of the file, we want to write
back some bytes to it. Simple enough?&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;std::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;fs::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; OpenOptions&lt;span class="op"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;io::prelude::&lt;/span&gt;&lt;span class="op"&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-5"&gt;&lt;a href="#cb1-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-6"&gt;&lt;a href="#cb1-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; PATH&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dt"&gt;str&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;file.txt&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-7"&gt;&lt;a href="#cb1-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; run() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-9"&gt;&lt;a href="#cb1-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; content &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;fs::&lt;/span&gt;read_to_string(PATH)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-10"&gt;&lt;a href="#cb1-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-11"&gt;&lt;a href="#cb1-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; file &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;OpenOptions::&lt;/span&gt;new()&lt;/span&gt;
&lt;span id="cb1-12"&gt;&lt;a href="#cb1-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;write(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb1-13"&gt;&lt;a href="#cb1-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;append(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb1-14"&gt;&lt;a href="#cb1-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;open(PATH)&lt;/span&gt;
&lt;span id="cb1-15"&gt;&lt;a href="#cb1-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-16"&gt;&lt;a href="#cb1-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-17"&gt;&lt;a href="#cb1-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;if&lt;/span&gt; content&lt;span class="op"&gt;.&lt;/span&gt;trim() &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-18"&gt;&lt;a href="#cb1-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    file&lt;span class="op"&gt;.&lt;/span&gt;write_all(&lt;span class="st"&gt;b&amp;quot;world!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-19"&gt;&lt;a href="#cb1-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-20"&gt;&lt;a href="#cb1-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-21"&gt;&lt;a href="#cb1-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cn"&gt;Ok&lt;/span&gt;(())&lt;/span&gt;
&lt;span id="cb1-22"&gt;&lt;a href="#cb1-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-23"&gt;&lt;a href="#cb1-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-24"&gt;&lt;a href="#cb1-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-25"&gt;&lt;a href="#cb1-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  run()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-26"&gt;&lt;a href="#cb1-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This program can fail in a few different ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The file doesn’t exist.&lt;/li&gt;
&lt;li&gt;The contents of the file aren’t valid UTF-8.&lt;/li&gt;
&lt;li&gt;The call to &lt;a
href="https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all"
target="_blank"&gt;&lt;code&gt;write_all&lt;/code&gt;&lt;/a&gt; gets interrupted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are handling each of these instances with our calls to &lt;a
href="https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap"
target="_blank"&gt;&lt;code&gt;unwrap&lt;/code&gt;&lt;/a&gt; on the fallible function calls.
However, instead of being able to recover from an error if it occurs,
the current thread &lt;a
href="https://doc.rust-lang.org/std/macro.panic.html"
target="_blank"&gt;&lt;code&gt;panics&lt;/code&gt;&lt;/a&gt;, which, if it is the main
thread, terminates all threads and ends the program with code
&lt;code&gt;101&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="recoverable-errors-with-resultt-e"&gt;Recoverable errors with
Result&amp;lt;T, E&amp;gt;&lt;/h3&gt;
&lt;p&gt;Instead of calls to &lt;code&gt;panic!&lt;/code&gt; each time the program can
fail, we should be writing more robust code by giving our caller a
chance to recover from this behaviour.&lt;/p&gt;
&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;std::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;fs::&lt;/span&gt;File&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;prelude::&lt;/span&gt;&lt;span class="op"&gt;*},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-5"&gt;&lt;a href="#cb2-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-6"&gt;&lt;a href="#cb2-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; PATH&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dt"&gt;str&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;file.txt&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-7"&gt;&lt;a href="#cb2-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; run() &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Result&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;()&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; content &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;fs::&lt;/span&gt;read_to_string(PATH)&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-10"&gt;&lt;a href="#cb2-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-11"&gt;&lt;a href="#cb2-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; file &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;OpenOptions::&lt;/span&gt;new()&lt;/span&gt;
&lt;span id="cb2-12"&gt;&lt;a href="#cb2-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;write(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb2-13"&gt;&lt;a href="#cb2-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;append(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb2-14"&gt;&lt;a href="#cb2-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;open(PATH)&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-15"&gt;&lt;a href="#cb2-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-16"&gt;&lt;a href="#cb2-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;if&lt;/span&gt; content&lt;span class="op"&gt;.&lt;/span&gt;trim() &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-17"&gt;&lt;a href="#cb2-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    file&lt;span class="op"&gt;.&lt;/span&gt;write_all(&lt;span class="st"&gt;b&amp;quot;world!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-18"&gt;&lt;a href="#cb2-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-19"&gt;&lt;a href="#cb2-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-20"&gt;&lt;a href="#cb2-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cn"&gt;Ok&lt;/span&gt;(())&lt;/span&gt;
&lt;span id="cb2-21"&gt;&lt;a href="#cb2-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-22"&gt;&lt;a href="#cb2-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-23"&gt;&lt;a href="#cb2-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-24"&gt;&lt;a href="#cb2-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;match&lt;/span&gt; run() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-25"&gt;&lt;a href="#cb2-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cn"&gt;Ok&lt;/span&gt;(()) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-26"&gt;&lt;a href="#cb2-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cn"&gt;Err&lt;/span&gt;(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;eprintln!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; e)&lt;/span&gt;
&lt;span id="cb2-27"&gt;&lt;a href="#cb2-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-28"&gt;&lt;a href="#cb2-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Result&lt;/code&gt; type is an &lt;code&gt;enum&lt;/code&gt; which has an
&lt;code&gt;Ok&lt;/code&gt; and an &lt;code&gt;Err&lt;/code&gt; variant. The &lt;code&gt;Ok&lt;/code&gt;
variant holds a generic value &lt;code&gt;T&lt;/code&gt; that gets returned in the
case that no errors have occurred. The &lt;code&gt;Err&lt;/code&gt; variant holds a
generic value &lt;code&gt;E&lt;/code&gt;, usually an error type, if an error has
occurred.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;?&lt;/code&gt; operator only works when the function we’re
applying it to returns a &lt;code&gt;Result&lt;/code&gt; in which whose
&lt;code&gt;Err&lt;/code&gt; variant contains the error type we wish to propagate.
It is essentially a shorthand for the following code:&lt;/p&gt;
&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;match&lt;/span&gt; result &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cn"&gt;Ok&lt;/span&gt;(v)  &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; v&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cn"&gt;Err&lt;/span&gt;(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cn"&gt;Err&lt;/span&gt;(e)&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This implementation allows for our caller to recover from any
erroneous behaviour. However, we can only return one type of error from
our function. This prompts anyone who wishes to possibly return more
than one error type to create their own type that contains multiple
variants.&lt;/p&gt;
&lt;h3 id="crafting-custom-error-types"&gt;Crafting custom error types&lt;/h3&gt;
&lt;p&gt;We can craft our own custom error type as a Rust &lt;a
href="https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html"
target="_blank"&gt;&lt;code&gt;enum&lt;/code&gt;&lt;/a&gt; and add multiple variants to it.
We can then define a &lt;code&gt;Result&lt;/code&gt; type which we can use
throughout our program which contains our custom error type as the error
to propagate.&lt;/p&gt;
&lt;p&gt;In order to demonstrate the need for multiple error types, we’ll
extend the functionality of this tiny application to include a call to
some API endpoint that is written in the text file, using the &lt;a
href="https://github.com/seanmonstar/reqwest"
target="_blank"&gt;&lt;code&gt;reqwest&lt;/code&gt;&lt;/a&gt; library.&lt;/p&gt;
&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;std::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;fmt::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="bu"&gt;Display&lt;/span&gt;&lt;span class="op"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;fs::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; OpenOptions&lt;span class="op"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;prelude::&lt;/span&gt;&lt;span class="op"&gt;*},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-6"&gt;&lt;a href="#cb4-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;reqwest::&lt;/span&gt;blocking&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-7"&gt;&lt;a href="#cb4-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-8"&gt;&lt;a href="#cb4-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; Result&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;,&lt;/span&gt; E &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;std::result::&lt;/span&gt;&lt;span class="dt"&gt;Result&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;,&lt;/span&gt; E&lt;span class="op"&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;derive&lt;span class="at"&gt;(&lt;/span&gt;&lt;span class="bu"&gt;Debug&lt;/span&gt;&lt;span class="at"&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-11"&gt;&lt;a href="#cb4-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;enum&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-12"&gt;&lt;a href="#cb4-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  IoError(&lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-13"&gt;&lt;a href="#cb4-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ApiError(&lt;span class="pp"&gt;reqwest::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-14"&gt;&lt;a href="#cb4-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-15"&gt;&lt;a href="#cb4-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-16"&gt;&lt;a href="#cb4-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;From&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="cf"&gt;for&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-17"&gt;&lt;a href="#cb4-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;fn&lt;/span&gt; from(err&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-18"&gt;&lt;a href="#cb4-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="pp"&gt;::&lt;/span&gt;IoError(err)&lt;/span&gt;
&lt;span id="cb4-19"&gt;&lt;a href="#cb4-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-20"&gt;&lt;a href="#cb4-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-21"&gt;&lt;a href="#cb4-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-22"&gt;&lt;a href="#cb4-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;From&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pp"&gt;reqwest::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="cf"&gt;for&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-23"&gt;&lt;a href="#cb4-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;fn&lt;/span&gt; from(err&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="pp"&gt;reqwest::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-24"&gt;&lt;a href="#cb4-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="pp"&gt;::&lt;/span&gt;ApiError(err)&lt;/span&gt;
&lt;span id="cb4-25"&gt;&lt;a href="#cb4-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-26"&gt;&lt;a href="#cb4-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-27"&gt;&lt;a href="#cb4-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-28"&gt;&lt;a href="#cb4-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Display&lt;/span&gt; &lt;span class="cf"&gt;for&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-29"&gt;&lt;a href="#cb4-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;fn&lt;/span&gt; fmt(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; f&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kw"&gt;mut&lt;/span&gt; &lt;span class="pp"&gt;fmt::&lt;/span&gt;Formatter&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="ot"&gt;&amp;#39;_&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;fmt::&lt;/span&gt;&lt;span class="dt"&gt;Result&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-30"&gt;&lt;a href="#cb4-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;match&lt;/span&gt; &lt;span class="kw"&gt;self&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-31"&gt;&lt;a href="#cb4-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="pp"&gt;::&lt;/span&gt;IoError(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;write!&lt;/span&gt;(f&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;IO Error: {}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; e)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-32"&gt;&lt;a href="#cb4-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="pp"&gt;::&lt;/span&gt;ApiError(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;write!&lt;/span&gt;(f&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Api Error: {}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; e)&lt;/span&gt;
&lt;span id="cb4-33"&gt;&lt;a href="#cb4-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-34"&gt;&lt;a href="#cb4-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-35"&gt;&lt;a href="#cb4-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-36"&gt;&lt;a href="#cb4-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-37"&gt;&lt;a href="#cb4-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; PATH&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dt"&gt;str&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;file.txt&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-38"&gt;&lt;a href="#cb4-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-39"&gt;&lt;a href="#cb4-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; run() &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Result&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;()&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-40"&gt;&lt;a href="#cb4-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; content &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;fs::&lt;/span&gt;read_to_string(PATH)&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-41"&gt;&lt;a href="#cb4-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-42"&gt;&lt;a href="#cb4-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; file &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;OpenOptions::&lt;/span&gt;new()&lt;/span&gt;
&lt;span id="cb4-43"&gt;&lt;a href="#cb4-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;write(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-44"&gt;&lt;a href="#cb4-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;append(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-45"&gt;&lt;a href="#cb4-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;open(PATH)&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-46"&gt;&lt;a href="#cb4-46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-47"&gt;&lt;a href="#cb4-47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; response &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;blocking::&lt;/span&gt;get(content&lt;span class="op"&gt;.&lt;/span&gt;trim())&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-48"&gt;&lt;a href="#cb4-48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-49"&gt;&lt;a href="#cb4-49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  file&lt;span class="op"&gt;.&lt;/span&gt;write_all(&lt;/span&gt;
&lt;span id="cb4-50"&gt;&lt;a href="#cb4-50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    response&lt;/span&gt;
&lt;span id="cb4-51"&gt;&lt;a href="#cb4-51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;.&lt;/span&gt;text()&lt;span class="op"&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-52"&gt;&lt;a href="#cb4-52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;.&lt;/span&gt;as_bytes()&lt;/span&gt;
&lt;span id="cb4-53"&gt;&lt;a href="#cb4-53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  )&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-54"&gt;&lt;a href="#cb4-54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-55"&gt;&lt;a href="#cb4-55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cn"&gt;Ok&lt;/span&gt;(())&lt;/span&gt;
&lt;span id="cb4-56"&gt;&lt;a href="#cb4-56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-57"&gt;&lt;a href="#cb4-57" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-58"&gt;&lt;a href="#cb4-58" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-59"&gt;&lt;a href="#cb4-59" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;match&lt;/span&gt; run() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-60"&gt;&lt;a href="#cb4-60" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cn"&gt;Ok&lt;/span&gt;(()) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-61"&gt;&lt;a href="#cb4-61" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cn"&gt;Err&lt;/span&gt;(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;eprintln!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; e)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-62"&gt;&lt;a href="#cb4-62" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-63"&gt;&lt;a href="#cb4-63" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In order to apply our nice shorthand &lt;code&gt;?&lt;/code&gt; operator, we have
the implement the &lt;a
href="https://doc.rust-lang.org/std/convert/trait.From.html"
target="_blank"&gt;&lt;code&gt;From&lt;/code&gt;&lt;/a&gt; trait for each error type we wish
to add to our custom &lt;code&gt;enum&lt;/code&gt;. In addition, in order for
&lt;code&gt;main&lt;/code&gt; to be able to print out the error message, we must
implement &lt;a href="https://doc.rust-lang.org/std/fmt/trait.Display.html"
target="_blank"&gt;&lt;code&gt;Display&lt;/code&gt;&lt;/a&gt; for our custom error type,
matching on each variant.&lt;/p&gt;
&lt;p&gt;This implementation solves the problem of dealing with multiple error
types in a given function. Having our own custom error type also allows
for other users of our application to deal with our various custom error
type variants using a similar approach. However, as we shall see, we can
avoid some of this tedium by bringing in a third party.&lt;/p&gt;
&lt;h3 id="enter-snafu"&gt;Enter snafu&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;snafu&lt;/code&gt; library allows for the easy assignment of
foreign errors into domain-specific errors while also adding contextual
information. Whenever a foreign error type is encountered, we can easily
pin it to our own custom typing by adding a &lt;code&gt;source&lt;/code&gt;
attribute.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;div class="sourceCode" id="cb5"&gt;&lt;pre
class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;std::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;fs::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; OpenOptions&lt;span class="op"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;prelude::&lt;/span&gt;&lt;span class="op"&gt;*},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;reqwest::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; blocking&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-6"&gt;&lt;a href="#cb5-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;snafu::&lt;/span&gt;Snafu&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-7"&gt;&lt;a href="#cb5-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-8"&gt;&lt;a href="#cb5-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; Result&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;,&lt;/span&gt; E &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;std::result::&lt;/span&gt;&lt;span class="dt"&gt;Result&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;,&lt;/span&gt; E&lt;span class="op"&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-9"&gt;&lt;a href="#cb5-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-10"&gt;&lt;a href="#cb5-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;derive&lt;span class="at"&gt;(&lt;/span&gt;&lt;span class="bu"&gt;Debug&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; Snafu&lt;span class="at"&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-11"&gt;&lt;a href="#cb5-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;enum&lt;/span&gt; &lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-12"&gt;&lt;a href="#cb5-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;#[&lt;/span&gt;snafu&lt;span class="at"&gt;(&lt;/span&gt;context&lt;span class="at"&gt;(&lt;/span&gt;&lt;span class="cn"&gt;false&lt;/span&gt;&lt;span class="at"&gt;)&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; display&lt;span class="at"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;IO Error: {}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; source&lt;span class="at"&gt;))]&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-13"&gt;&lt;a href="#cb5-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  Io &lt;span class="op"&gt;{&lt;/span&gt; source&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-14"&gt;&lt;a href="#cb5-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-15"&gt;&lt;a href="#cb5-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;#[&lt;/span&gt;snafu&lt;span class="at"&gt;(&lt;/span&gt;context&lt;span class="at"&gt;(&lt;/span&gt;&lt;span class="cn"&gt;false&lt;/span&gt;&lt;span class="at"&gt;)&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; display&lt;span class="at"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Api Error: {}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; source&lt;span class="at"&gt;))]&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-16"&gt;&lt;a href="#cb5-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  Api &lt;span class="op"&gt;{&lt;/span&gt; source&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="pp"&gt;reqwest::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt; &lt;span class="op"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-17"&gt;&lt;a href="#cb5-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-18"&gt;&lt;a href="#cb5-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-19"&gt;&lt;a href="#cb5-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; PATH&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dt"&gt;str&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;file.txt&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-20"&gt;&lt;a href="#cb5-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-21"&gt;&lt;a href="#cb5-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; run() &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Result&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;()&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-22"&gt;&lt;a href="#cb5-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; content &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;fs::&lt;/span&gt;read_to_string(PATH)&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-23"&gt;&lt;a href="#cb5-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-24"&gt;&lt;a href="#cb5-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; file &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;OpenOptions::&lt;/span&gt;new()&lt;/span&gt;
&lt;span id="cb5-25"&gt;&lt;a href="#cb5-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;write(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb5-26"&gt;&lt;a href="#cb5-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;append(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb5-27"&gt;&lt;a href="#cb5-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;.&lt;/span&gt;open(PATH)&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-28"&gt;&lt;a href="#cb5-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-29"&gt;&lt;a href="#cb5-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; response &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;blocking::&lt;/span&gt;get(content&lt;span class="op"&gt;.&lt;/span&gt;trim())&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-30"&gt;&lt;a href="#cb5-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-31"&gt;&lt;a href="#cb5-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  file&lt;span class="op"&gt;.&lt;/span&gt;write_all(&lt;/span&gt;
&lt;span id="cb5-32"&gt;&lt;a href="#cb5-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    response&lt;/span&gt;
&lt;span id="cb5-33"&gt;&lt;a href="#cb5-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;.&lt;/span&gt;text()&lt;span class="op"&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-34"&gt;&lt;a href="#cb5-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;.&lt;/span&gt;as_bytes()&lt;/span&gt;
&lt;span id="cb5-35"&gt;&lt;a href="#cb5-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  )&lt;span class="op"&gt;?;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-36"&gt;&lt;a href="#cb5-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-37"&gt;&lt;a href="#cb5-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cn"&gt;Ok&lt;/span&gt;(())&lt;/span&gt;
&lt;span id="cb5-38"&gt;&lt;a href="#cb5-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-39"&gt;&lt;a href="#cb5-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-40"&gt;&lt;a href="#cb5-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-41"&gt;&lt;a href="#cb5-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;match&lt;/span&gt; run() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-42"&gt;&lt;a href="#cb5-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cn"&gt;Ok&lt;/span&gt;(()) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-43"&gt;&lt;a href="#cb5-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cn"&gt;Err&lt;/span&gt;(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;eprintln!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; e)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-44"&gt;&lt;a href="#cb5-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-45"&gt;&lt;a href="#cb5-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a
href="https://docs.rs/snafu/0.6.10/snafu/guide/the_macro/index.html"
target="_blank"&gt;&lt;code&gt;Snafu&lt;/code&gt;&lt;/a&gt; macro implements all the
necessary traits in order to begin using our custom error type in
functions.&lt;/p&gt;
&lt;p&gt;Crafting our type this way not only let’s us avoid implementing
traits ourselves but also gives us the added benefit of easily adding in
custom fields to our error types as contextual information.&lt;/p&gt;
&lt;p&gt;This tiny example doesn’t show all of the functionality the
&lt;code&gt;snafu&lt;/code&gt; library has to offer, so I suggest you have a look at
the official &lt;a href="https://docs.rs/snafu/0.6.10/snafu/index.html"
target="_blank"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="fin"&gt;Fin&lt;/h3&gt;
&lt;p&gt;Quality Rust code should never panic when it doesn’t absolutely need
to, and knowing this you should make the best of the situation by
crafting your own error types that other people can use in their
applications. You can either make it tedious, by doing it by hand, or by
using the nifty &lt;code&gt;snafu&lt;/code&gt; library to do the job.&lt;/p&gt;</description>
<link>https://liam.rs/posts/Ergonomic-error-handling-in-Rust/</link>
<pubDate>Sun, 22 Aug 2021 04:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Ergonomic-error-handling-in-Rust/</guid>
</item>
<item>
<title>Higher-order-functions</title>
<description>&lt;p&gt;The higher-order function is one of the many powerful and important
concepts I have run into when dabbling in the world of functional
programming.&lt;/p&gt;
&lt;p&gt;Before diving into the details, it’s worth mentioning that in certain
languages like Python or Javascript, functions are treated as
first-class citizens. What does this mean? It means that functions can
be stored in variables, passed around to functions or returned from
functions, just as you would be able to do with a primitive or
non-primitive data type.&lt;/p&gt;
&lt;p&gt;Knowing this, a higher-order function is a function that either takes
in a function as input or returns a function as output.&lt;/p&gt;
&lt;p&gt;Examples of higher-order functions that you may deal with on a daily
basis but may be unaware of the underlying concept: &lt;code&gt;filter&lt;/code&gt;,
&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that definitions are taken care of, let’s take a look at some
examples:&lt;/p&gt;
&lt;h3 id="filter"&gt;Filter&lt;/h3&gt;
&lt;p&gt;Problem: &lt;em&gt;given an arbitrary iterable, filter out elements whose
value fail to meet a certain criteria.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;filter&lt;/code&gt; function takes in a single-argument predicate
function (a function that returns a boolean value) and an iterable, and
returns a new iterable that consists of each element in the passed in
iterable that when passed into to the predicate function evaluate to
true.&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; &lt;span class="bu"&gt;filter&lt;/span&gt;(func, iterable):&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; [el &lt;span class="cf"&gt;for&lt;/span&gt; el &lt;span class="kw"&gt;in&lt;/span&gt; iterable &lt;span class="cf"&gt;if&lt;/span&gt; func(el)]&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="bu"&gt;filter&lt;/span&gt;(&lt;span class="kw"&gt;lambda&lt;/span&gt; x: x &lt;span class="op"&gt;&amp;amp;&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;, [&lt;span class="dv"&gt;1&lt;/span&gt;, &lt;span class="dv"&gt;2&lt;/span&gt;, &lt;span class="dv"&gt;3&lt;/span&gt;, &lt;span class="dv"&gt;4&lt;/span&gt;, &lt;span class="dv"&gt;5&lt;/span&gt;])) &lt;span class="co"&gt;# [1, 3 ,5]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="map"&gt;Map&lt;/h3&gt;
&lt;p&gt;Problem: &lt;em&gt;given an arbitrary iterable, apply some transformation
to each element in that iterable.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;map&lt;/code&gt; function takes in a single-argument function and
an iterable applies that function to each item in the iterable,
returning the resulting iterable.&lt;/p&gt;
&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; &lt;span class="bu"&gt;map&lt;/span&gt;(func, iterable):&lt;/span&gt;
&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; [func(x) &lt;span class="cf"&gt;for&lt;/span&gt; x &lt;span class="kw"&gt;in&lt;/span&gt; iterable]&lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="bu"&gt;map&lt;/span&gt;(&lt;span class="kw"&gt;lambda&lt;/span&gt; x: x &lt;span class="op"&gt;//&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;, [&lt;span class="dv"&gt;2&lt;/span&gt;, &lt;span class="dv"&gt;4&lt;/span&gt;, &lt;span class="dv"&gt;6&lt;/span&gt;, &lt;span class="dv"&gt;8&lt;/span&gt;])) &lt;span class="co"&gt;# [1, 2, 3, 4]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="reduce"&gt;Reduce&lt;/h3&gt;
&lt;p&gt;Problem: &lt;em&gt;given an arbitrary iterable, accumulate some
transformation to each element in that iterable and return the resulting
value.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;reduce&lt;/code&gt; function takes in a two-argument function and
an iterable and applies that function to elements in the iterable,
accumulating the result along the way.&lt;/p&gt;
&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; &lt;span class="bu"&gt;reduce&lt;/span&gt;(func, iterable, init&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;None&lt;/span&gt;):&lt;/span&gt;
&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  it  &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="bu"&gt;iter&lt;/span&gt;(iterable)&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  val &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="bu"&gt;next&lt;/span&gt;(it) &lt;span class="cf"&gt;if&lt;/span&gt; init &lt;span class="kw"&gt;is&lt;/span&gt; &lt;span class="va"&gt;None&lt;/span&gt; &lt;span class="cf"&gt;else&lt;/span&gt; init&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;for&lt;/span&gt; el &lt;span class="kw"&gt;in&lt;/span&gt; it:&lt;/span&gt;
&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    val &lt;span class="op"&gt;=&lt;/span&gt; func(val, el)&lt;/span&gt;
&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; val&lt;/span&gt;
&lt;span id="cb3-9"&gt;&lt;a href="#cb3-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-10"&gt;&lt;a href="#cb3-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="bu"&gt;reduce&lt;/span&gt;(&lt;span class="kw"&gt;lambda&lt;/span&gt; x, y: x &lt;span class="op"&gt;*&lt;/span&gt; y, [&lt;span class="dv"&gt;1&lt;/span&gt;, &lt;span class="dv"&gt;2&lt;/span&gt;, &lt;span class="dv"&gt;3&lt;/span&gt;])) &lt;span class="co"&gt;# 6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As we can see above, we first deal with our initializer value, if
none is present we use the first element in the list.&lt;/p&gt;
&lt;p&gt;We then run through the list, applying the passed in
&lt;code&gt;func&lt;/code&gt; with our current value and each subsequent element in
the list.&lt;/p&gt;
&lt;h3 id="composition-of-programs"&gt;Composition of programs&lt;/h3&gt;
&lt;p&gt;Now that we’ve gone through some basic examples, let’s see how this
pattern might be useful in a practical scenario.&lt;/p&gt;
&lt;p&gt;Problem: &lt;em&gt;write a program that outputs the sum of naturals,
squares and cubes from numbers 1 to N where N is some arbitrary
input&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Seems easy enough? Without the use of higher order functions, we can
simple write the program like so:&lt;/p&gt;
&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; natural(N):&lt;/span&gt;
&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="bu"&gt;sum&lt;/span&gt;([x &lt;span class="cf"&gt;for&lt;/span&gt; x &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="bu"&gt;range&lt;/span&gt;(&lt;span class="dv"&gt;1&lt;/span&gt;, N &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)])&lt;/span&gt;
&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; square(N):&lt;/span&gt;
&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="bu"&gt;sum&lt;/span&gt;([x &lt;span class="op"&gt;**&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt; &lt;span class="cf"&gt;for&lt;/span&gt; x &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="bu"&gt;range&lt;/span&gt;(&lt;span class="dv"&gt;1&lt;/span&gt;, N &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)])&lt;/span&gt;
&lt;span id="cb4-6"&gt;&lt;a href="#cb4-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-7"&gt;&lt;a href="#cb4-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; cube(N):&lt;/span&gt;
&lt;span id="cb4-8"&gt;&lt;a href="#cb4-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="bu"&gt;sum&lt;/span&gt;([x &lt;span class="op"&gt;**&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="cf"&gt;for&lt;/span&gt; x &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="bu"&gt;range&lt;/span&gt;(&lt;span class="dv"&gt;1&lt;/span&gt;, N &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)])&lt;/span&gt;
&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; main(N):&lt;/span&gt;
&lt;span id="cb4-11"&gt;&lt;a href="#cb4-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;for&lt;/span&gt; func &lt;span class="kw"&gt;in&lt;/span&gt; [natural, square, cube]:&lt;/span&gt;
&lt;span id="cb4-12"&gt;&lt;a href="#cb4-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;print&lt;/span&gt;(func(N))&lt;/span&gt;
&lt;span id="cb4-13"&gt;&lt;a href="#cb4-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-14"&gt;&lt;a href="#cb4-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="va"&gt;__name__&lt;/span&gt; &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="cb4-15"&gt;&lt;a href="#cb4-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  main(&lt;span class="bu"&gt;int&lt;/span&gt;(&lt;span class="bu"&gt;input&lt;/span&gt;()))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that the three different functions are actually very similar,
the only difference is the &lt;em&gt;transformation of data&lt;/em&gt; we perform on
each number in the sequence.&lt;/p&gt;
&lt;p&gt;We can introduce a higher order function that &lt;em&gt;applies&lt;/em&gt; this
transformation to the data.&lt;/p&gt;
&lt;div class="sourceCode" id="cb5"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; summation(func, N):&lt;/span&gt;
&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="bu"&gt;sum&lt;/span&gt;(&lt;span class="bu"&gt;list&lt;/span&gt;(&lt;span class="bu"&gt;map&lt;/span&gt;(func, &lt;span class="bu"&gt;range&lt;/span&gt;(&lt;span class="dv"&gt;1&lt;/span&gt;, N &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))))&lt;/span&gt;
&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; main(N):&lt;/span&gt;
&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;for&lt;/span&gt; func &lt;span class="kw"&gt;in&lt;/span&gt; [&lt;span class="kw"&gt;lambda&lt;/span&gt; x: x, &lt;span class="kw"&gt;lambda&lt;/span&gt; x: x &lt;span class="op"&gt;**&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;, &lt;span class="kw"&gt;lambda&lt;/span&gt; x: x &lt;span class="op"&gt;**&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;]:&lt;/span&gt;
&lt;span id="cb5-6"&gt;&lt;a href="#cb5-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;print&lt;/span&gt;(summation(func, N))&lt;/span&gt;
&lt;span id="cb5-7"&gt;&lt;a href="#cb5-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-8"&gt;&lt;a href="#cb5-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="va"&gt;__name__&lt;/span&gt; &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="cb5-9"&gt;&lt;a href="#cb5-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  main(&lt;span class="bu"&gt;int&lt;/span&gt;(&lt;span class="bu"&gt;input&lt;/span&gt;()))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="decorators"&gt;Decorators&lt;/h3&gt;
&lt;p&gt;It’s worth covering another type of higher-order function, one that
&lt;em&gt;returns&lt;/em&gt; a function. In Python, the idea of a &lt;em&gt;decorator&lt;/em&gt;
is simply a function that takes in another function and returns a new
one with some modified behaviour.&lt;/p&gt;
&lt;p&gt;Here’s a simple example of a timer, a function that computes the time
of a function call.&lt;/p&gt;
&lt;div class="sourceCode" id="cb6"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; time&lt;/span&gt;
&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; timer(func):&lt;/span&gt;
&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;def&lt;/span&gt; wrap(&lt;span class="op"&gt;*&lt;/span&gt;args, &lt;span class="op"&gt;**&lt;/span&gt;kwargs):&lt;/span&gt;
&lt;span id="cb6-5"&gt;&lt;a href="#cb6-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    start &lt;span class="op"&gt;=&lt;/span&gt; time.perf_counter()&lt;/span&gt;
&lt;span id="cb6-6"&gt;&lt;a href="#cb6-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    func(&lt;span class="op"&gt;*&lt;/span&gt;args, &lt;span class="op"&gt;**&lt;/span&gt;kwargs)&lt;/span&gt;
&lt;span id="cb6-7"&gt;&lt;a href="#cb6-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    end   &lt;span class="op"&gt;=&lt;/span&gt; time.perf_counter()&lt;/span&gt;
&lt;span id="cb6-8"&gt;&lt;a href="#cb6-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="ss"&gt;f&amp;#39;Function &lt;/span&gt;&lt;span class="sc"&gt;{&lt;/span&gt;func&lt;span class="sc"&gt;.&lt;/span&gt;&lt;span class="va"&gt;__name__&lt;/span&gt;&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="ss"&gt; executed in &lt;/span&gt;&lt;span class="sc"&gt;{&lt;/span&gt;end &lt;span class="op"&gt;-&lt;/span&gt; start&lt;span class="sc"&gt;:.4f}&lt;/span&gt;&lt;span class="ss"&gt;s&amp;#39;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb6-9"&gt;&lt;a href="#cb6-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; wrap&lt;/span&gt;
&lt;span id="cb6-10"&gt;&lt;a href="#cb6-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-11"&gt;&lt;a href="#cb6-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;@timer&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-12"&gt;&lt;a href="#cb6-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; waste(n):&lt;/span&gt;
&lt;span id="cb6-13"&gt;&lt;a href="#cb6-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;for&lt;/span&gt; _ &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="bu"&gt;range&lt;/span&gt;(n):&lt;/span&gt;
&lt;span id="cb6-14"&gt;&lt;a href="#cb6-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;pass&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-15"&gt;&lt;a href="#cb6-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-16"&gt;&lt;a href="#cb6-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; main():&lt;/span&gt;
&lt;span id="cb6-17"&gt;&lt;a href="#cb6-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  waste(&lt;span class="dv"&gt;2000000&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb6-18"&gt;&lt;a href="#cb6-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-19"&gt;&lt;a href="#cb6-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="va"&gt;__name__&lt;/span&gt; &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="cb6-20"&gt;&lt;a href="#cb6-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  main() &lt;span class="co"&gt;# Function waste executed in 0.0396s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As we can see, the function &lt;code&gt;timer&lt;/code&gt; takes in a function as
input and returns a wrapper function that modifies the behaviour of the
passed in function by performing operations before and after the
function call. Now the new function will embody this new behaviour
whenever it is called.&lt;/p&gt;
&lt;h3 id="fin"&gt;Fin&lt;/h3&gt;
&lt;p&gt;Being able to treat functions as first-class citizens in your
programming language is a powerful idea to wrap your head around and a
worth while design choice when composing large scale and complex
applications.&lt;/p&gt;
&lt;p&gt;All of the functions written for this post can be found here -&amp;gt; &lt;a
href="https://gist.github.com/terror/4d86aaf49cc724d0bfe5af11d05da88e"
target="_blank"&gt;https://gist.github.com/terror/4d86aaf49cc724d0bfe5af11d05da88e&lt;/a&gt;&lt;/p&gt;</description>
<link>https://liam.rs/posts/Higher-order-functions/</link>
<pubDate>Tue, 08 Jun 2021 04:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Higher-order-functions/</guid>
</item>
<item>
<title>Binary-search-for-bugs</title>
<description>&lt;p&gt;I recently encountered a build failure in a dependency of a Rust
crate I was trying to install which led me to be introduced to a git
command called &lt;code&gt;bisect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From the official docs found over at &lt;a
href="https://git-scm.com/docs/git-bisect"
target="_blank"&gt;git-scm.com&lt;/a&gt;, the small description under the name
heading reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use binary search to find the commit that introduced a bug&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds super cool right? Using this feature I was able to track down
the commit that introduced the bug in less than 6 steps.&lt;/p&gt;
&lt;p&gt;Here’s a general overview of how this command works:&lt;/p&gt;
&lt;ol type="1"&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;git bisect start&lt;/code&gt; to start the bisect
session&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Specify a bad commit (usually HEAD) using
&lt;code&gt;git bisect bad &amp;lt;commit-id&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Specify a good commit using
&lt;code&gt;git bisect good &amp;lt;commit-id&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will kick off the binary search and pick a new commit in which
you can evaluate using &lt;code&gt;git bisect good&lt;/code&gt; or
&lt;code&gt;git bisect bad&lt;/code&gt;, in between the two endpoints.&lt;/p&gt;
&lt;p&gt;It is clear that using this method, over the linear scan approach,
can save a tremendous amount of time in the quest for finding where a
breaking change was introduced.&lt;/p&gt;</description>
<link>https://liam.rs/posts/Binary-search-for-bugs/</link>
<pubDate>Mon, 15 Feb 2021 05:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Binary-search-for-bugs/</guid>
</item>
<item>
<title>How-I-read-blogs</title>
<description>&lt;p&gt;I have recently gotten into the habit of reading more blogs, in
particular, ones featured on &lt;a href="https://news.ycombinator.com/news"
target="_blank"&gt;HackerNews&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Reading books, personally, has been a difficult habit to cultivate
over time, which I mainly attribute to the periodic feelings of being
“stuck” or bored on a certain set of books. Blogs, however, offer a
condensed read making them efficient and often amusing sources of
information.&lt;/p&gt;
&lt;p&gt;My typical sourcing routine would usually just consist of scrolling
through HackerNews, potentially seeing something that peaked my interest
and reading it, or realizing I didn’t have the time and putting the url
off in a &lt;code&gt;.txt&lt;/code&gt; file somewhere.&lt;/p&gt;
&lt;p&gt;Realizing the severe lack of efficiency present in this routine, I
thought about how to make it better. First, by asking the question: what
were the things I didn’t like?&lt;/p&gt;
&lt;ol type="1"&gt;
&lt;li&gt;Having to scroll through articles myself&lt;/li&gt;
&lt;li&gt;Reading on mobile or desktop&lt;/li&gt;
&lt;li&gt;Having no effortless &lt;code&gt;like&lt;/code&gt; or &lt;code&gt;archive&lt;/code&gt;
feature&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To address these problems I chose to try out &lt;a
href="https://www.instapaper.com/"
target="_blank"&gt;&lt;code&gt;Instapaper&lt;/code&gt;&lt;/a&gt; and build a simple tool
called &lt;a href="https://github.com/terror/hackerpaper"
target="_blank"&gt;&lt;code&gt;hackerpaper&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instapaper has a feature that let’s you send articles to your Kindle,
which makes reading blogs much more comfortable. Moreover, the built in
&lt;code&gt;like&lt;/code&gt; and &lt;code&gt;archive&lt;/code&gt; features carryover to the
Kindle as well, making it a seamless process of &lt;code&gt;read&lt;/code&gt; -&amp;gt;
&lt;code&gt;archive or like&lt;/code&gt; -&amp;gt; &lt;code&gt;repeat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To solve the issue of having to scroll through articles myself and
add them to Instapaper, as mentioned above, I built
&lt;code&gt;hackerpaper&lt;/code&gt;. This tool sends HackerNews articles to
Instapaper with certain filters such as type, subdomains or a specific
article id.&lt;/p&gt;
&lt;p&gt;I run a &lt;code&gt;cron job&lt;/code&gt; that sends the articles to Instapaper
at 5:00AM and have Instapaper send those articles to my Kindle at
7:00AM.&lt;/p&gt;
&lt;p&gt;The script is as simple as:&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; ~/path/to/python3 ~/path/to/hackerpaper &lt;span class="at"&gt;-a&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;email&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;password&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; -t topstories&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To recap the routine:&lt;/p&gt;
&lt;ol type="1"&gt;
&lt;li&gt;Have &lt;code&gt;hackerpaper&lt;/code&gt; send articles to Instapaper&lt;/li&gt;
&lt;li&gt;Have &lt;code&gt;Instapaper&lt;/code&gt; send those articles to Kindle&lt;/li&gt;
&lt;li&gt;Read and archive those articles&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ol&gt;</description>
<link>https://liam.rs/posts/How-I-read-blogs/</link>
<pubDate>Sun, 15 Nov 2020 05:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/How-I-read-blogs/</guid>
</item>
<item>
<title>Useful-git-aliases</title>
<description>&lt;p&gt;I really enjoy using &lt;code&gt;aliases&lt;/code&gt; for git commands because a)
I’m lazy and b) it makes me feel more productive.&lt;/p&gt;
&lt;p&gt;Some basic ones I use&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alias ga=&amp;quot;git add&amp;quot;
alias gc=&amp;quot;git commit&amp;quot;
alias gd=&amp;quot;git diff&amp;quot;
alias gch=&amp;quot;git checkout&amp;quot;
alias gst=&amp;quot;git status&amp;quot;
alias gp=&amp;quot;git push -u origin master&amp;quot;
alias gpo=&amp;quot;git push origin&amp;quot;
alias gb=&amp;quot;git branch&amp;quot;
alias gcb=&amp;quot;git checkout -b&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These ones are set up in my &lt;code&gt;.bashrc&lt;/code&gt; file so that I can
just execute them as is, i.e &lt;code&gt;gc&lt;/code&gt; -&amp;gt;
&lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Some more complex ones (except for fetch) in my
&lt;code&gt;.gitconfig&lt;/code&gt; I enjoy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;f = fetch
fu = fetch upstream master
track = branch --set-upstream-to=upstream/master master
parent = &amp;quot;!git show-branch | grep &amp;#39;*&amp;#39; | grep -v \&amp;quot;$(git rev-parse --abbrev-ref HEAD)\&amp;quot; | head -n1 | sed &amp;#39;s/.*\\[\\(.*\\)\\].*/\\1/&amp;#39; | sed &amp;#39;s/[\\^~].*//&amp;#39; #&amp;quot;
lg = log --oneline
last = log -1 HEAD&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fu&lt;/code&gt; and &lt;code&gt;track&lt;/code&gt; are useful for doing things
when I’m working on a forked repository&lt;/p&gt;
&lt;p&gt;&lt;code&gt;parent&lt;/code&gt; shows the parent branch of the current working
branch&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lg&lt;/code&gt; shows commit history one line at a time&lt;/p&gt;
&lt;p&gt;&lt;code&gt;last&lt;/code&gt; shows information for the last commit&lt;/p&gt;
&lt;p&gt;Whether they make me more productive or not, I just enjoy using them
and see no reason not to.&lt;/p&gt;</description>
<link>https://liam.rs/posts/Useful-git-aliases/</link>
<pubDate>Wed, 02 Sep 2020 04:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Useful-git-aliases/</guid>
</item>
<item>
<title>Chaining-comparison-operators</title>
<description>&lt;p&gt;I recently came across this lesser known feature in Python and
started to play around with it.&lt;/p&gt;
&lt;p&gt;Being able to chain comparison operators is a rarity among most
modern programming languages, which is a shame considering how elegant
and intuitive it turns out to be.&lt;/p&gt;
&lt;p&gt;Here are some examples:&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;a, b, c &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;, &lt;span class="dv"&gt;10&lt;/span&gt;, &lt;span class="dv"&gt;15&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;print&lt;/span&gt;(a &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; b &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; c)&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# True&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code above is equivalent to:&lt;/p&gt;
&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;a, b, c &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;, &lt;span class="dv"&gt;10&lt;/span&gt;, &lt;span class="dv"&gt;15&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;print&lt;/span&gt;(a &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; b &lt;span class="kw"&gt;and&lt;/span&gt; b &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; c) &lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# True&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And something a bit more complex:&lt;/p&gt;
&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;a, b, c, d, e, f, g &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;, &lt;span class="dv"&gt;10&lt;/span&gt;, &lt;span class="dv"&gt;30&lt;/span&gt;, &lt;span class="dv"&gt;20&lt;/span&gt;, &lt;span class="dv"&gt;15&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;flag &lt;span class="op"&gt;=&lt;/span&gt; a &lt;span class="op"&gt;&amp;lt;=&lt;/span&gt; b &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; f &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; c &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; d &lt;span class="kw"&gt;is&lt;/span&gt; &lt;span class="kw"&gt;not&lt;/span&gt; f &lt;span class="kw"&gt;is&lt;/span&gt; g&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;print&lt;/span&gt;(flag)&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# True&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That is all equivalent to:&lt;/p&gt;
&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;a, b, c, d, e, f, g &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;, &lt;span class="dv"&gt;10&lt;/span&gt;, &lt;span class="dv"&gt;30&lt;/span&gt;, &lt;span class="dv"&gt;20&lt;/span&gt;, &lt;span class="dv"&gt;15&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;flag &lt;span class="op"&gt;=&lt;/span&gt; a &lt;span class="op"&gt;&amp;lt;=&lt;/span&gt; b &lt;span class="kw"&gt;and&lt;/span&gt; b &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; f &lt;span class="kw"&gt;and&lt;/span&gt; f &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; c &lt;span class="kw"&gt;and&lt;/span&gt; c &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; d &lt;span class="kw"&gt;and&lt;/span&gt; d &lt;span class="kw"&gt;is&lt;/span&gt; &lt;span class="kw"&gt;not&lt;/span&gt; f &lt;span class="kw"&gt;and&lt;/span&gt; f &lt;span class="kw"&gt;is&lt;/span&gt; g&lt;/span&gt;
&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;print&lt;/span&gt;(flag)&lt;/span&gt;
&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# True&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can see how tedious things might get. Python continues to amaze
me with how beautiful and concise it can be.&lt;/p&gt;</description>
<link>https://liam.rs/posts/Chaining-comparison-operators/</link>
<pubDate>Tue, 25 Aug 2020 04:00:00 +0000</pubDate>
<guid>https://liam.rs/posts/Chaining-comparison-operators/</guid>
</item>

  </channel>
</rss>
