<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title></title>
    <link href="https://blog.dend.ro/atom.xml" rel="self" type="application/atom+xml" />
    <link href="https://blog.dend.ro/" />
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-11-14T00:00:00+00:00</updated>
    <id>https://blog.dend.ro/atom.xml</id>
    <entry xml:lang="en">
        <title>Talks</title>
        <published>2025-11-14T00:00:00+00:00</published>
        <updated>2025-11-14T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/content/talks/" type="text/html" />
        <id>https://blog.dend.ro/content/talks/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.dend.ro&#x2F;content&#x2F;talks&#x2F;omniopencon2025&#x2F;index.html&quot;&gt;A Rusty Geospatial Adventure (OmniOpenCon 2025)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Recovering information from a PDF map</title>
        <published>2023-02-23T00:00:00+00:00</published>
        <updated>2023-02-23T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/recovering-information-pdf-map/" type="text/html" />
        <id>https://blog.dend.ro/recovering-information-pdf-map/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;This post is going to be about a question that recently came up in the &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;#gdal:osgeo.org&quot;&gt;GDAL Matrix room&lt;&#x2F;a&gt;.
A user had a discrete heat map of noise levels in their town as a PDF, and wanted to extract some usable information out of it.
Let&#x27;s see if we can help them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;looking-at-the-data&quot;&gt;Looking at the data&lt;&#x2F;h2&gt;
&lt;p&gt;If you want to play along, you can download the file from &lt;a href=&quot;https:&#x2F;&#x2F;hartiacustice.pmb.ro&#x2F;page&#x2F;hstrat&quot;&gt;here&lt;&#x2F;a&gt;.
Pick the &lt;a href=&quot;https:&#x2F;&#x2F;hartiacustice.pmb.ro&#x2F;docs&#x2F;harti&#x2F;3.1_harti_strategice_de_zgomot_drumuri&#x2F;drumuri_Lzsn.pdf&quot;&gt;first one&lt;&#x2F;a&gt;, with &lt;code&gt;Lzsn&lt;&#x2F;code&gt; in its name.
It&#x27;s a 42 MB PDF, looking like this (click on the image for a better version):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-sample.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-sample-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If that seems unreadable, it&#x27;s partly because &lt;a href=&quot;https:&#x2F;&#x2F;wiki.gnome.org&#x2F;Apps&#x2F;Evince&quot;&gt;my PDF viewer&lt;&#x2F;a&gt; can&#x27;t zoom into large documents.
A better choice is probably &lt;a href=&quot;https:&#x2F;&#x2F;qgis.org&#x2F;&quot;&gt;QGIS&lt;&#x2F;a&gt;, so you can install it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-better-sample.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-better-sample-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This would probably make a real cartographer unhappy, but fortunately I&#x27;m not one.
And yes, some labels are doubled, don&#x27;t ask me why.
It happens in Evince, Okular and QGIS, but I don&#x27;t have a &quot;real&quot; PDF reader to test with.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re following along, you might have noticed that QGIS took about 20 minutes to open the file and probably just as long to close it.
That&#x27;s not great and puts our software in a bad light, so let&#x27;s convert it to a better format.&lt;&#x2F;p&gt;
&lt;p&gt;Using &lt;a href=&quot;https:&#x2F;&#x2F;gdal.org&#x2F;&quot;&gt;GDAL&lt;&#x2F;a&gt;, you can convert it to a GeoTIFF like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; gdal_translate drumuri_Lzsn.pdf drumuri_Lzsn_temp.tif
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; gdal_translate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; COG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -co&lt;&#x2F;span&gt;&lt;span&gt; NUM_THREADS=ALL_CPUS drumuri_Lzsn_temp.tif drumuri_Lzsn.tif
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.cogeo.org&#x2F;&quot;&gt;COG&lt;&#x2F;a&gt; is just a GeoTIFF laid out so it can load faster while zooming in.
If you&#x27;re wondering why I&#x27;m doing the conversion in two steps, it just happens to be very slow otherwise, while the commands above should only take a couple of seconds.
COGs are tiled (stored in blocks), and going from a striped (stored by lines) to a tiled layout can be slow, but I don&#x27;t think that&#x27;s the case for our PDF.
Anyway, once you have a TIFF, QGIS should be quite snappy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;extracting-the-image&quot;&gt;Extracting the image&lt;&#x2F;h2&gt;
&lt;p&gt;The user would like to have a nice vector dataset, and overlay it on top of &lt;a href=&quot;https:&#x2F;&#x2F;www.openstreetmap.org&#x2F;&quot;&gt;OpenStreetMap&lt;&#x2F;a&gt;.
This means that we&#x27;re not really interested in the roads, road labels and building footprints, which are already available there.&lt;&#x2F;p&gt;
&lt;p&gt;I initially missed this, but the user pointed out that the roads in the PDF seem to be stored in a vector format.
Maybe there&#x27;s a chance we can get rid of them?&lt;&#x2F;p&gt;
&lt;p&gt;After some searching, I found the &lt;code&gt;pdfimages&lt;&#x2F;code&gt; tool, part of Poppler.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; pdfimages&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -list&lt;&#x2F;span&gt;&lt;span&gt; drumuri_Lzsn.pdf
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;page&lt;&#x2F;span&gt;&lt;span&gt;   num  type   width height color comp bpc  enc interp  object ID x-ppi y-ppi size ratio
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;--------------------------------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;     0 image   16377 12649  rgb     3   8  jpeg   no         7  0   200   200 39.7M 6.7%
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This sounds promising, as we have a large image which we can extract.
It&#x27;s a JPEG, which might cause us some problems later, but we&#x27;ll cross that bridge when we get there.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; pdfimages&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -j&lt;&#x2F;span&gt;&lt;span&gt; drumuri_Lzsn.pdf drumuri_Lzsn
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; ls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -lh&lt;&#x2F;span&gt;&lt;span&gt; drumuri_Lzsn*.jpg
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span&gt; 1 user group 40M Feb 21 19:04 drumuri-Lzsn.jpg
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; gdal_translate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; COG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -co&lt;&#x2F;span&gt;&lt;span&gt; NUM_THREADS=ALL_CPUS drumuri-Lzsn.jpg drumuri_Lzsn-data.tif
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Yes, GDAL can read JPEG, that&#x27;s pretty nifty.
Let&#x27;s see what we got:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-data-overview.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-data-overview-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yup, we still have the legend and other stuff on the right, and we can reasonably suspect that our map was scanned.
But is it at least cleaner?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-data-detail.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-data-detail-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Success — it looks like we&#x27;re on the right track!
We still have the building footprints, but the labels are gone.
We won&#x27;t miss them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;georeferencing&quot;&gt;Georeferencing&lt;&#x2F;h2&gt;
&lt;p&gt;Unfortunately, if we open both images in QGIS, they won&#x27;t show up in the same place.
This is because the one we extracted is missing the georeferencing and projection information.
To put it differently, QGIS doesn&#x27;t know where the image is located, its orientation and how large a pixel is on the ground.&lt;&#x2F;p&gt;
&lt;p&gt;The original PDF had this information, and it was propagated to the TIFF we made from it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; gdalinfo drumuri_Lzsn.tif
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Driver:&lt;&#x2F;span&gt;&lt;span&gt; GTiff&#x2F;GeoTIFF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Files:&lt;&#x2F;span&gt;&lt;span&gt; drumuri_Lzsn.tif
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Size&lt;&#x2F;span&gt;&lt;span&gt; is 12992, 9448
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Coordinate&lt;&#x2F;span&gt;&lt;span&gt; System is:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PROJCRS[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;WGS 84 &#x2F; Pseudo-Mercator&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;BASEGEOGCRS[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;WGS 84&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ENSEMBLE[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 ensemble&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MEMBER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 (Transit)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MEMBER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 (G730)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MEMBER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 (G873)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MEMBER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 (G1150)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MEMBER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 (G1674)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MEMBER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 (G1762)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MEMBER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World Geodetic System 1984 (G2139)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ELLIPSOID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;WGS 84&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,6378137,298.257223563,
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LENGTHUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;metre&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,1]],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ENSEMBLEACCURACY[2.0]],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PRIMEM[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Greenwich&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ANGLEUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;degree&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0.0174532925199433]],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EPSG&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,4326]],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CONVERSION[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Popular Visualisation Pseudo-Mercator&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;METHOD[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Popular Visualisation Pseudo Mercator&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EPSG&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,1024]],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PARAMETER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Latitude of natural origin&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ANGLEUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;degree&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0.0174532925199433],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EPSG&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,8801]],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PARAMETER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Longitude of natural origin&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ANGLEUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;degree&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0.0174532925199433],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EPSG&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,8802]],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PARAMETER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;False easting&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LENGTHUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;metre&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,1],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EPSG&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,8806]],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PARAMETER[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;False northing&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LENGTHUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;metre&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,1],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EPSG&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,8807]]],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CS[Cartesian,2],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AXIS[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;easting (X)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,east,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ORDER[1],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LENGTHUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;metre&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,1]],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AXIS[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;northing (Y)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,north,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ORDER[2],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LENGTHUNIT[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;metre&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,1]],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;USAGE[
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SCOPE[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Web mapping and visualisation.&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AREA[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;World between 85.06°S and 85.06°N.&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;BBOX[-85.06,-180,85.06,180]],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ID[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EPSG&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,3857]]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span&gt; axis to CRS axis mapping: 1,2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Origin&lt;&#x2F;span&gt;&lt;span&gt; = (2886267.104982524644583,5550384.975221752189100)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Pixel&lt;&#x2F;span&gt;&lt;span&gt; Size = (3.554565159517144,-3.554573706431164)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Metadata:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AREA_OR_POINT&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Area
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CREATION_DATE&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;D:20180606221414
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CREATOR&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;þÿ
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;NEATLINE&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;POLYGON &lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2886267&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10498252 5550384&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;38278758&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2886267&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10498252 5516801&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;36284339&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2932447&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42309224 5516801&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;36284339&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2932447&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42309224 5550384&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;38278758&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2886267&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10498252 5550384&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;38278758&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PRODUCER&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Qt &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;4.8.5&lt;&#x2F;span&gt;&lt;span&gt; (C) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2011&lt;&#x2F;span&gt;&lt;span&gt; Nokia Corporation and&#x2F;or its subsidiary(-ies)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;TITLE&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;þÿ
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Image&lt;&#x2F;span&gt;&lt;span&gt; Structure Metadata:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;COMPRESSION&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;LZW
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;INTERLEAVE&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PIXEL
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LAYOUT&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COG
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Corner&lt;&#x2F;span&gt;&lt;span&gt; Coordinates:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Upper&lt;&#x2F;span&gt;&lt;span&gt; Left  ( 2886267.105, 5550384.975) ( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;25d55&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;40.00&amp;quot;E, 44d32&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;46.88&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Lower Left  ( 2886267.105, 5516801.363) ( 25d55&amp;#39;40.00&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;E,&lt;&#x2F;span&gt;&lt;span&gt; 44d19&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;51.43&amp;quot;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Upper Right ( 2932448.016, 5550384.975) ( 26d20&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;33.46&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;E, 44d32&amp;#39;46.88&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Lower&lt;&#x2F;span&gt;&lt;span&gt; Right ( 2932448.016, 5516801.363) ( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;26d20&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;33.46&amp;quot;E, 44d19&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;51.43&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Center      ( 2909357.560, 5533593.169) ( 26d 8&amp;#39; 6.73&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;E,&lt;&#x2F;span&gt;&lt;span&gt; 44d26&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;19.51&amp;quot;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Band 1 Block=512x512 Type=Byte, ColorInterp=Red
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Min=0.000 Max=255.000 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Minimum=0.000, Maximum=255.000, Mean=222.565, StdDev=77.753
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Overviews: 6496x4724, 3248x2362, 1624x1181, 812x590, 406x295
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_APPROXIMATE=YES
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MAXIMUM=255
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MEAN=222.56487158937
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MINIMUM=0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_STDDEV=77.753237328653
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_VALID_PERCENT=100
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Band 2 Block=512x512 Type=Byte, ColorInterp=Green
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Min=0.000 Max=255.000 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Minimum=0.000, Maximum=255.000, Mean=214.219, StdDev=83.659
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Overviews: 6496x4724, 3248x2362, 1624x1181, 812x590, 406x295
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_APPROXIMATE=YES
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MAXIMUM=255
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MEAN=214.21891418763
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MINIMUM=0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_STDDEV=83.65912385424
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_VALID_PERCENT=100
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Band 3 Block=512x512 Type=Byte, ColorInterp=Blue
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Min=0.000 Max=255.000 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Minimum=0.000, Maximum=255.000, Mean=211.690, StdDev=87.032
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Overviews: 6496x4724, 3248x2362, 1624x1181, 812x590, 406x295
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_APPROXIMATE=YES
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MAXIMUM=255
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MEAN=211.69040207532
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_MINIMUM=0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_STDDEV=87.03195681233
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    STATISTICS_VALID_PERCENT=100
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see it&#x27;s using EPSG:3857 &quot;Web Mercator&quot; as the coordinate reference system.
This tells QGIS and other software how to convert the coordinates in the image to latitude and longitude on the globe.
Just below we also have the corner coordinates and pixel spacing (size), which is about 3.55 meters or 3.89 yards.&lt;&#x2F;p&gt;
&lt;p&gt;But the image we extracted using &lt;code&gt;pdfimages&lt;&#x2F;code&gt; doesn&#x27;t have this information:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; gdalinfo drumuri_Lzsn-data.tif 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Driver:&lt;&#x2F;span&gt;&lt;span&gt; GTiff&#x2F;GeoTIFF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Files:&lt;&#x2F;span&gt;&lt;span&gt; drumuri_Lzsn-data.tif
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Size&lt;&#x2F;span&gt;&lt;span&gt; is 16377, 12649
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Image&lt;&#x2F;span&gt;&lt;span&gt; Structure Metadata:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;COMPRESSION&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;LZW
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;INTERLEAVE&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PIXEL
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LAYOUT&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COG
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Corner&lt;&#x2F;span&gt;&lt;span&gt; Coordinates:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Upper&lt;&#x2F;span&gt;&lt;span&gt; Left  (    0.0,    0.0)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Lower&lt;&#x2F;span&gt;&lt;span&gt; Left  (    0.0,12649.0)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Upper&lt;&#x2F;span&gt;&lt;span&gt; Right (16377.0,    0.0)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Lower&lt;&#x2F;span&gt;&lt;span&gt; Right (16377.0,12649.0)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Center&lt;&#x2F;span&gt;&lt;span&gt;      ( 8188.5, 6324.5)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Band&lt;&#x2F;span&gt;&lt;span&gt; 1 Block=512x512 Type=Byte, ColorInterp=Red
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Overviews:&lt;&#x2F;span&gt;&lt;span&gt; 8189x6325, 4095x3163, 2048x1582
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Band&lt;&#x2F;span&gt;&lt;span&gt; 2 Block=512x512 Type=Byte, ColorInterp=Green
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Overviews:&lt;&#x2F;span&gt;&lt;span&gt; 8189x6325, 4095x3163, 2048x1582
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Band&lt;&#x2F;span&gt;&lt;span&gt; 3 Block=512x512 Type=Byte, ColorInterp=Blue
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Overviews:&lt;&#x2F;span&gt;&lt;span&gt; 8189x6325, 4095x3163, 2048x1582
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So what do we do?
Can we copy it from the original one?
Sure, and it&#x27;s quite easy!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; python
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Python&lt;&#x2F;span&gt;&lt;span&gt; 3.10.9 (main, Dec 24 2022, 19:48:26) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[GCC&lt;&#x2F;span&gt;&lt;span&gt; 12.2.0] on linux
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Type &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;help&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;copyright&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;credits&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; or &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;license&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; for more information.
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; from &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;osgeo&lt;&#x2F;span&gt;&lt;span&gt; import gdal
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; image = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;gdal.Open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;drumuri_Lzsn-data.tif&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; reference = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;gdal.Open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;drumuri_Lzsn.tif&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; reference.GetProjection() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# just to check
&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PROJCS[&amp;quot;WGS 84 &#x2F; Pseudo-Mercator&amp;quot;,GEOGCS[&amp;quot;WGS 84&amp;quot;,DATUM[&amp;quot;WGS_1984&amp;quot;,SPHEROID[&amp;quot;WGS 84&amp;quot;,6378137,298.257223563,AUTHORITY[&amp;quot;EPSG&amp;quot;,&amp;quot;7030&amp;quot;]],AUTHORITY[&amp;quot;EPSG&amp;quot;,&amp;quot;6326&amp;quot;]],PRIMEM[&amp;quot;Greenwich&amp;quot;,0,AUTHORITY[&amp;quot;EPSG&amp;quot;,&amp;quot;8901&amp;quot;]],UNIT[&amp;quot;degree&amp;quot;,0.0174532925199433,AUTHORITY[&amp;quot;EPSG&amp;quot;,&amp;quot;9122&amp;quot;]],AUTHORITY[&amp;quot;EPSG&amp;quot;,&amp;quot;4326&amp;quot;]],PROJECTION[&amp;quot;Mercator_1SP&amp;quot;],PARAMETER[&amp;quot;central_meridian&amp;quot;,0],PARAMETER[&amp;quot;scale_factor&amp;quot;,1],PARAMETER[&amp;quot;false_easting&amp;quot;,0],PARAMETER[&amp;quot;false_northing&amp;quot;,0],UNIT[&amp;quot;metre&amp;quot;,1,AUTHORITY[&amp;quot;EPSG&amp;quot;,&amp;quot;9001&amp;quot;]],AXIS[&amp;quot;Easting&amp;quot;,EAST],AXIS[&amp;quot;Northing&amp;quot;,NORTH],EXTENSION[&amp;quot;PROJ4&amp;quot;,&amp;quot;+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs&amp;quot;],AUTHORITY[&amp;quot;EPSG&amp;quot;,&amp;quot;3857&amp;quot;]]&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; reference.GetGeoTransform() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# just to check
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2886267.1049825246,&lt;&#x2F;span&gt;&lt;span&gt; 3.5545651595171437, 0.0, 5550384.975221752, 0.0,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -3&lt;&#x2F;span&gt;&lt;span&gt;.5545737064311638)
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; image.SetProjection(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;reference.GetProjection&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; image.SetGeoTransform(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;reference.GetGeoTransform&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; image.FlushCache() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# write our changes to disk
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ gdalinfo drumuri_Lzsn-data.tif
&lt;&#x2F;span&gt;&lt;span&gt;Driver: GTiff&#x2F;GeoTIFF
&lt;&#x2F;span&gt;&lt;span&gt;Files: drumuri_Lzsn-data.tif
&lt;&#x2F;span&gt;&lt;span&gt;       drumuri_Lzsn-data.tif.aux.xml
&lt;&#x2F;span&gt;&lt;span&gt;Size is 16377, 12649
&lt;&#x2F;span&gt;&lt;span&gt;Coordinate System is:
&lt;&#x2F;span&gt;&lt;span&gt;PROJCRS[&amp;quot;WGS 84 &#x2F; Pseudo-Mercator&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    BASEGEOGCRS[&amp;quot;WGS 84&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;        DATUM[&amp;quot;World Geodetic System 1984&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;            ELLIPSOID[&amp;quot;WGS 84&amp;quot;,6378137,298.257223563,
&lt;&#x2F;span&gt;&lt;span&gt;                LENGTHUNIT[&amp;quot;metre&amp;quot;,1]]],
&lt;&#x2F;span&gt;&lt;span&gt;        PRIMEM[&amp;quot;Greenwich&amp;quot;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            ANGLEUNIT[&amp;quot;degree&amp;quot;,0.0174532925199433]],
&lt;&#x2F;span&gt;&lt;span&gt;        ID[&amp;quot;EPSG&amp;quot;,4326]],
&lt;&#x2F;span&gt;&lt;span&gt;    CONVERSION[&amp;quot;unnamed&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;        METHOD[&amp;quot;Popular Visualisation Pseudo Mercator&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,1024]],
&lt;&#x2F;span&gt;&lt;span&gt;        PARAMETER[&amp;quot;Latitude of natural origin&amp;quot;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            ANGLEUNIT[&amp;quot;degree&amp;quot;,0.0174532925199433],
&lt;&#x2F;span&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8801]],
&lt;&#x2F;span&gt;&lt;span&gt;        PARAMETER[&amp;quot;Longitude of natural origin&amp;quot;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            ANGLEUNIT[&amp;quot;degree&amp;quot;,0.0174532925199433],
&lt;&#x2F;span&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8802]],
&lt;&#x2F;span&gt;&lt;span&gt;        PARAMETER[&amp;quot;False easting&amp;quot;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1],
&lt;&#x2F;span&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8806]],
&lt;&#x2F;span&gt;&lt;span&gt;        PARAMETER[&amp;quot;False northing&amp;quot;,0,
&lt;&#x2F;span&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1],
&lt;&#x2F;span&gt;&lt;span&gt;            ID[&amp;quot;EPSG&amp;quot;,8807]]],
&lt;&#x2F;span&gt;&lt;span&gt;    CS[Cartesian,2],
&lt;&#x2F;span&gt;&lt;span&gt;        AXIS[&amp;quot;easting&amp;quot;,east,
&lt;&#x2F;span&gt;&lt;span&gt;            ORDER[1],
&lt;&#x2F;span&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1]],
&lt;&#x2F;span&gt;&lt;span&gt;        AXIS[&amp;quot;northing&amp;quot;,north,
&lt;&#x2F;span&gt;&lt;span&gt;            ORDER[2],
&lt;&#x2F;span&gt;&lt;span&gt;            LENGTHUNIT[&amp;quot;metre&amp;quot;,1]],
&lt;&#x2F;span&gt;&lt;span&gt;    ID[&amp;quot;EPSG&amp;quot;,3857]]
&lt;&#x2F;span&gt;&lt;span&gt;Data axis to CRS axis mapping: 1,2
&lt;&#x2F;span&gt;&lt;span&gt;Origin = (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2886267.104982524644583,5550384.975221752189100&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Pixel&lt;&#x2F;span&gt;&lt;span&gt; Size = (3.554565159517144,-3.554573706431164)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Image&lt;&#x2F;span&gt;&lt;span&gt; Structure Metadata:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;COMPRESSION&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;LZW
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;INTERLEAVE&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PIXEL
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;LAYOUT&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COG
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Corner&lt;&#x2F;span&gt;&lt;span&gt; Coordinates:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Upper&lt;&#x2F;span&gt;&lt;span&gt; Left  ( 2886267.105, 5550384.975) ( 25d55&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;40.00&amp;quot;E, 44d32&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;46.88&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Lower Left  ( 2886267.105, 5505423.172) ( 25d55&amp;#39;40.00&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;E, 44d15&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;28.05&amp;quot;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Upper Right ( 2944480.219, 5550384.975) ( 26d27&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; 2.58&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;E, 44d32&amp;#39;46.88&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Lower&lt;&#x2F;span&gt;&lt;span&gt; Right ( 2944480.219, 5505423.172) ( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;26d27&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; 2.58&amp;quot;E, 44d15&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;28.05&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Center      ( 2915373.662, 5527904.074) ( 26d11&amp;#39;21.29&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;E,&lt;&#x2F;span&gt;&lt;span&gt; 44d24&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; 8.11&amp;quot;N)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Band 1 Block=512x512 Type=Byte, ColorInterp=Red
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Overviews: 8189x6325, 4095x3163, 2048x1582
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Band 2 Block=512x512 Type=Byte, ColorInterp=Green
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Overviews: 8189x6325, 4095x3163, 2048x1582
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Band 3 Block=512x512 Type=Byte, ColorInterp=Blue
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  Overviews: 8189x6325, 4095x3163, 2048x1582
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you&#x27;re wondering, the &lt;a href=&quot;https:&#x2F;&#x2F;gdal.org&#x2F;tutorials&#x2F;geotransforms_tut.html&quot;&gt;&quot;Geotransform&quot;&lt;&#x2F;a&gt; is a set of parameters for an &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Affine_transformation&quot;&gt;affine transformation&lt;&#x2F;a&gt;.
It can describe a combination of translation (where the image is located), scaling (how large a pixel is), rotation (the orientation of the image) and shear, which I suspect nobody uses.
These are sufficient for any &quot;well-behaved&quot; image like those you&#x27;ll find on my blog, but that&#x27;s not always the case.&lt;&#x2F;p&gt;
&lt;p&gt;We can load them both in QGIS, but something seems a little off.
In the screenshot below, I reduced the transparency of &lt;code&gt;drumuri_Lzsn-data.tif&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-misalignment.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-misalignment-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s pretty awful, and it seems that our approach was not quite right.
In retrospect, this makes sense.
The PDF had a correct georeference, but it doesn&#x27;t necessarily transfer to the one we extracted, because we didn&#x27;t take into account the position and scale of the image on the page.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;georeferencing-again&quot;&gt;Georeferencing, again&lt;&#x2F;h2&gt;
&lt;p&gt;Fortunately, not all is lost, as this must be a problem a lot of QGIS users must running into.
Digitizing a map doesn&#x27;t seem like such a rare use case, and I knew that QGIS has a feature that helps with this.
What we&#x27;d like to do is pick some points on our image, find their pair in the original one, and let QGIS figure it out.
In GIS-speak, these are called GCPs, for Ground Control Points.&lt;&#x2F;p&gt;
&lt;p&gt;We can do this using the Georeferencer tool.
If you&#x27;re looking it up, a lot of documentation online is outdated, and it&#x27;s now found Layer menu.
The documentation makes this seem pretty complex, but it&#x27;s not that bad.&lt;&#x2F;p&gt;
&lt;p&gt;Note: if you&#x27;re following along, the file you load must not have a geotransform, otherwise QGIS will get &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qgis&#x2F;QGIS&#x2F;issues&#x2F;51814&quot;&gt;very confused&lt;&#x2F;a&gt;.
So we have to undo the work from the previous section.
The easiest way is probably to rebuild the file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; gdal_translate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; COG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -co&lt;&#x2F;span&gt;&lt;span&gt; NUM_THREADS=ALL_CPUS drumuri-Lzsn.jpg drumuri_Lzsn-data.tif
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I opened the tool, loaded the raster (&lt;code&gt;drumuri_Lzsn-data.tif&lt;&#x2F;code&gt;), then zoomed in a lot and clicked on a pixel that seemed easy to spot.
A new window showed up asking for some coordinates, I clicked &quot;From Map Canvas&quot; and selected the corresponding pixel from the original (&lt;code&gt;drumuri_Lzsn-data.tif&lt;&#x2F;code&gt;):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-georeferencer.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-georeferencer.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The points you click on don&#x27;t get snapped to pixel centers, so I tried to be somewhat precise when clicking.&lt;&#x2F;p&gt;
&lt;p&gt;After hitting &quot;OK&quot;, the GCP showed up at the bottom of the window.&lt;&#x2F;p&gt;
&lt;p&gt;You need at least two pairs of points, but I picked three because it was pretty fun.
It&#x27;s probably a good idea to choose points that are far apart from each other.&lt;&#x2F;p&gt;
&lt;p&gt;Then I went to &quot;Transformation Settings&quot;, checked &quot;Set target resolution&quot;, but left the horizontal and vertical values set to 0 (you get a weird error if you don&#x27;t do this).
Linear and Nearest Neighbor should be fine.
Once you hit start, you should see a &lt;code&gt;drumuri_Lzsn-data_modified.tif&lt;&#x2F;code&gt; layer in QGIS.&lt;&#x2F;p&gt;
&lt;p&gt;Here I opened the layer settings and added &lt;code&gt;255&lt;&#x2F;code&gt; as an additional no data value in the Transparency tab, then added the OpenStreetMap XYZ tileset:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-georeferenced.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-georeferenced-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;lzsn-georeferenced-detail.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;lzsn-georeferenced-detail-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, I couldn&#x27;t get a pixel-perfect match over the original, but it should be good enough for practical purposes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;&#x2F;h2&gt;
&lt;p&gt;Our result looks encouraging, but we still need to do something about the compression artefacts (remember, the image we extracted is a JPEG) and, ideally, fill in the building footprints.
If you&#x27;d like to read more, stay tuned for the next part!&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>About a fun little NFS bug</title>
        <published>2022-06-29T00:00:00+00:00</published>
        <updated>2022-06-29T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/a-fun-nfs-bug/" type="text/html" />
        <id>https://blog.dend.ro/a-fun-nfs-bug/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;One &lt;a href=&quot;https:&#x2F;&#x2F;blog.dend.ro&#x2F;a-mysterous-python-crash&#x2F;&quot;&gt;cloud provider&lt;&#x2F;a&gt; I sometimes work with has a large repository of images, accessible using the S3 protocol or over an NFS gateway. Today I spent a bit of time debugging an issue related to the NFS gateway, so read on for more — and for a twist at the end.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;something-is-broken&quot;&gt;Something is broken&lt;&#x2F;h2&gt;
&lt;p&gt;I have a workload which involves relatively many of those images at once, accessed through the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;s3fs-fuse&#x2F;s3fs-fuse&quot;&gt;&lt;code&gt;s3fs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; FUSE helper (a way to make an S3 bucket look like a file system).
For some reason, sometimes requests start failing after a while, and using NFS is a way to work around that.&lt;&#x2F;p&gt;
&lt;p&gt;But something strange was happening today when I was trying to use the NFS share.
One version of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OSGeo&#x2F;gdal&#x2F;&quot;&gt;GDAL&lt;&#x2F;a&gt; was able to read the files, while another, older one, complained they were invalid and wasn&#x27;t able to open them.
Using &lt;code&gt;s3fs&lt;&#x2F;code&gt;, both GDAL versions worked fine.&lt;&#x2F;p&gt;
&lt;p&gt;This made me think that NFS is returning corrupted files (maybe with some junk at the end), and the newer GDAL was able to ignore that.
But on a closer look, both &lt;code&gt;s3fs&lt;&#x2F;code&gt; and NFS returned identical (up to a checksum, at least) files.
This was the cause of some head scratching, since reading a the same file from different places should yield the same results —&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-favourite-tool&quot;&gt;My favourite tool&lt;&#x2F;h2&gt;
&lt;p&gt;— unless maybe it shouldn&#x27;t?
This story seemed fishy and I broke out what&#x27;s probably my favourite debugging tool, &lt;code&gt;strace&lt;&#x2F;code&gt;.
&lt;code&gt;strace&lt;&#x2F;code&gt; sets breakpoints on every interaction of a program with the operating system (&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;System_call&quot;&gt;system call&lt;&#x2F;a&gt;) and displays the request involved, including the arguments.
So, for example, if Linux a program tries to open a file, it will show up in &lt;code&gt;strace&lt;&#x2F;code&gt; as an &lt;code&gt;open&lt;&#x2F;code&gt; or &lt;code&gt;openat&lt;&#x2F;code&gt; call.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: if that sounds interesting and you want to know more, check out &lt;a href=&quot;https:&#x2F;&#x2F;jvns.ca&#x2F;blog&#x2F;2015&#x2F;04&#x2F;14&#x2F;strace-zine&#x2F;&quot;&gt;this zine&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;jvns.ca&#x2F;blog&#x2F;2021&#x2F;04&#x2F;03&#x2F;what-problems-do-people-solve-with-strace&#x2F;&quot;&gt;this article&lt;&#x2F;a&gt;.
And if you&#x27;re not using Linux, you can try &lt;a href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;sysinternals&#x2F;downloads&#x2F;procmon&quot;&gt;Process Monitor&lt;&#x2F;a&gt; or &lt;a href=&quot;http:&#x2F;&#x2F;dtrace.org&#x2F;blogs&#x2F;about&#x2F;&quot;&gt;DTrace&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So I gave &lt;code&gt;strace&lt;&#x2F;code&gt; a try (edited for brevity):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; strace gdalinfo &#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# old GDAL
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;stat&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, {st_mode=S_IFREG|0666, st_size=115495922, ...}) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, O_RDONLY) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fstat&lt;&#x2F;span&gt;&lt;span&gt;(3, {st_mode=S_IFREG|0666, st_size=115495922, ...}) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;(3, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;[snip]&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;..., 8192) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;8192
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lseek&lt;&#x2F;span&gt;&lt;span&gt;(3, 0, SEEK_SET) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, O_RDONLY) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-1&lt;&#x2F;span&gt;&lt;span&gt; EPERM (Operation not permitted)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, O_RDONLY) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-1&lt;&#x2F;span&gt;&lt;span&gt; EPERM (Operation not permitted)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Most of the output above isn&#x27;t too important, but the last &lt;code&gt;open&lt;&#x2F;code&gt; calls fail with &lt;code&gt;EPERM&lt;&#x2F;code&gt;, which sounds like a good reason to not work.
If you have trouble reading the log, the full sequence is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gdalinfo&lt;&#x2F;code&gt; checks the file length and attributes&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gdalinfo&lt;&#x2F;code&gt; opens the file&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gdalinfo&lt;&#x2F;code&gt; checks the length and attributes of the open file&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gdalinfo&lt;&#x2F;code&gt; reads 8 KB from the file, which works, then rewinds to the beginning&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gdalinfo&lt;&#x2F;code&gt; tries to open the file again and gets a permissions-related error&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gdalinfo&lt;&#x2F;code&gt; tries to open the file again and gets a permissions-related error&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sure, this is a bit redundant, but it doesn&#x27;t matter that much when you&#x27;re reading 115 MB.
Note how the first &lt;code&gt;open&lt;&#x2F;code&gt; call works, then but the next ones fail.&lt;&#x2F;p&gt;
&lt;p&gt;In contrast, the newer GDAL works because it only tries to open the file once.
So what&#x27;s wrong, can we only read files once?&lt;&#x2F;p&gt;
&lt;p&gt;Of course not, otherwise a second &lt;code&gt;gdalinfo&lt;&#x2F;code&gt; wouldn&#x27;t work.
So a better theory is that we can&#x27;t open the same file twice.
And now that we have a theory, we can try to confirm it using &lt;del&gt;Rust&lt;&#x2F;del&gt; just kidding, let&#x27;s use Python this time:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# open the file once, works
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; f1 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# open it again, fails with EPERM
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; f2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Traceback &lt;&#x2F;span&gt;&lt;span&gt;(most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;lt;stdin&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, line &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, in &amp;lt;module&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;IOError: [Errno &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] Operation not permitted: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# close the first handle
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; f1.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;close&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# opening it works
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; f2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# opening it a second time fails again
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; f3 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Traceback &lt;&#x2F;span&gt;&lt;span&gt;(most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;lt;stdin&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, line &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, in &amp;lt;module&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;IOError: [Errno &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] Operation not permitted: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# and so on
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; f2.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;close&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; f3 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;mount_nfs&#x2F;path&#x2F;to&#x2F;file.jp2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So yeah, our theory was correct.
I don&#x27;t know what kind of server we&#x27;re dealing with, but it doesn&#x27;t let us open any file multiple times.
It even fails — maybe not surprisingly — if we&#x27;re opening it from different processes.&lt;&#x2F;p&gt;
&lt;p&gt;I wasn&#x27;t able to find any reports of a similar problem, so one of my reasons for writing this is to make it available to search engines.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;&#x2F;h2&gt;
&lt;p&gt;I also happened to stumble upon a pretty simple workaround: add &lt;code&gt;nfsvers=3&lt;&#x2F;code&gt; to the mount options (&lt;code&gt;&#x2F;etc&#x2F;fstab&lt;&#x2F;code&gt;).
It appears that the problem only occurs when using NFSv4, and not NFSv3.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-final-twist&quot;&gt;A final twist&lt;&#x2F;h2&gt;
&lt;p&gt;All this sounded somewhat familiar, so I searched through my inbox and found I had already reported this to the cloud provider in March 2020.
I even took a &lt;code&gt;tcpdump&lt;&#x2F;code&gt; capture and found out that the server was returning &lt;code&gt;NFS4ERR_PERM&lt;&#x2F;code&gt; on the failing call:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This indicates that the requester is not the owner.  The operation was not allowed because the caller is neither a privileged user (root) nor the owner of the target of the operation.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;But don&#x27;t confuse this with &lt;code&gt;NFS4ERR_ACCESS&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This indicates permission denied.  The caller does not have the correct permission to perform the requested operation.  Contrast this with NFS4ERR_PERM (Section 13.1.6.2), which restricts itself to owner or privileged user permission failures.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Hear this, Google?
If you&#x27;ve got a weird NFS server that doesn&#x27;t allow you to open files a second time and yields &lt;code&gt;NFS4ERR_PERM&lt;&#x2F;code&gt;, try downgrading to NFSv3.&lt;&#x2F;p&gt;
&lt;p&gt;And no, the provider never answered back.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;By the way, if your files sometime go away or can&#x27;t be reopened, please consider &lt;a href=&quot;https:&#x2F;&#x2F;www.buymeacoffee.com&#x2F;lnicolaq&quot;&gt;buying me a coffee&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Decoding Firefox session store data</title>
        <published>2022-06-12T00:00:00+00:00</published>
        <updated>2022-06-12T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/decoding-firefox-session-store-data/" type="text/html" />
        <id>https://blog.dend.ro/decoding-firefox-session-store-data/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;If you&#x27;re using Firefox (and you should), you might have wanted to read its session restore files, perhaps to recover some lost tabs, re-import an old session after a refresh, or even track your tab hoarding habit.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, last time I checked, there wasn&#x27;t much information available about the session restore format.
I&#x27;ve previously used &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;andikleen&#x2F;lz4json&quot;&gt;&lt;code&gt;lz4json&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to decode them, but it&#x27;s a good prompt for a post, and I&#x27;d rather not keep an extra AUR package anyway.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finding-the-files&quot;&gt;Finding the files&lt;&#x2F;h2&gt;
&lt;p&gt;Under &lt;code&gt;~&#x2F;.mozilla&#x2F;firefox&lt;&#x2F;code&gt; on Linux, or &lt;code&gt;%APPDATA%\Mozilla\Firefox&lt;&#x2F;code&gt; on Windows, you should have a &lt;code&gt;profiles.ini&lt;&#x2F;code&gt;, an &lt;code&gt;installs.ini&lt;&#x2F;code&gt; and one or more randomly-named subdirectories.
The default profile is marked as such in the two INI files.
Of course, the better way is to open &lt;code&gt;about:support&lt;&#x2F;code&gt; and copy the path from there.&lt;&#x2F;p&gt;
&lt;p&gt;In there, there should be a directory called &lt;code&gt;sessionstore-backups&lt;&#x2F;code&gt;, with a couple of files:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; ls sessionstore-backups
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;previous.jsonlz4
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;recovery.baklz4
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;recovery.jsonlz4
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;upgrade.jsonlz4-20220518214245
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;upgrade.jsonlz4-20220530093943
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;upgrade.jsonlz4-20220606212503
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I don&#x27;t know the specifics, but these are backup versions, more or less recent, some of them saved during browser upgrades.
Looking at the last modified dates, it appears that the most recent one is called &lt;code&gt;recovery.jsonlz4&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-lz4json-format&quot;&gt;The &lt;code&gt;lz4json&lt;&#x2F;code&gt; format&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;jsonlz4&lt;&#x2F;code&gt; extension is a good hint, but a good first step is to run the &lt;code&gt;file&lt;&#x2F;code&gt; utility, which tries to guess the type of a file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; file recovery.jsonlz4
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;recovery.jsonlz4:&lt;&#x2F;span&gt;&lt;span&gt; Mozilla lz4 compressed data, originally 145030214 bytes
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;file&lt;&#x2F;code&gt; recognizes thousands of file formats, but it&#x27;s relatively shallow.
This means that the uncompressed length is likely to be easily accessible.
Let&#x27;s look at the file contents:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ hexyl recovery.jsonlz4 | head -n7
&lt;&#x2F;span&gt;&lt;span&gt;┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
&lt;&#x2F;span&gt;&lt;span&gt;│00000000│ 6d 6f 7a 4c 7a 34 30 00 ┊ 46 fc a4 08 f2 21 7b 22 │mozLz400┊F××•×!{&amp;quot;│
&lt;&#x2F;span&gt;&lt;span&gt;│00000010│ 76 65 72 73 69 6f 6e 22 ┊ 3a 5b 22 73 65 73 73 69 │version&amp;quot;┊:[&amp;quot;sessi│
&lt;&#x2F;span&gt;&lt;span&gt;│00000020│ 6f 6e 72 65 73 74 6f 72 ┊ 65 22 2c 31 5d 2c 22 77 │onrestor┊e&amp;quot;,1],&amp;quot;w│
&lt;&#x2F;span&gt;&lt;span&gt;│00000030│ 69 6e 64 6f 77 73 22 3a ┊ 5b 7b 22 74 61 62 09 00 │indows&amp;quot;:┊[{&amp;quot;tab_0│
&lt;&#x2F;span&gt;&lt;span&gt;│00000040│ 62 65 6e 74 72 69 65 0c ┊ 00 f3 29 75 72 6c 22 3a │bentrie_┊0×)url&amp;quot;:│
&lt;&#x2F;span&gt;&lt;span&gt;│00000050│ 22 68 74 74 70 73 3a 2f ┊ 2f 6d 61 74 72 69 78 2e │&amp;quot;https:&#x2F;┊&#x2F;matrix.│
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can actually see some &lt;a href=&quot;https:&#x2F;&#x2F;blog.dend.ro&#x2F;decoding-firefox-session-store-data&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;JSON&quot;&gt;JSON&lt;&#x2F;a&gt; in there.
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;LZ4_(compression_algorithm)&quot;&gt;LZ4&lt;&#x2F;a&gt; is designed to be as fast as possible, so it doesn&#x27;t do anything fancy like &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Huffman_coding&quot;&gt;Huffman coding&lt;&#x2F;a&gt;, yielding partially-readable text as output.&lt;&#x2F;p&gt;
&lt;p&gt;Before the JSON, though, there is a line that looks a bit strange.
The file starts with the &lt;code&gt;&quot;mozLz40\0&quot;&lt;&#x2F;code&gt; &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;File_format#Magic_number&quot;&gt;magic number&lt;&#x2F;a&gt;, followed by what appear to be six non-ASCII bytes, then the start of the JSON.
We can expect the six bytes to contain the file length, or maybe a checksum.
These are usually found either at the beginning or at the end of a file.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily, &lt;code&gt;file&lt;&#x2F;code&gt; was nice to tell us the uncompressed data size.
&lt;code&gt;145030214&lt;&#x2F;code&gt;, converted to &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hexadecimal&quot;&gt;hex&lt;&#x2F;a&gt; is &lt;code&gt;0x08A4FC46&lt;&#x2F;code&gt;, which is actually visible as &lt;code&gt;46 fc a4 08&lt;&#x2F;code&gt; in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sharkdp&#x2F;hexyl&quot;&gt;&lt;code&gt;hexyl&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; output above.&lt;&#x2F;p&gt;
&lt;p&gt;We can also &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;file&#x2F;file&#x2F;blob&#x2F;46976e05f97e4b2bc77476a16f7107ff0be12df1&#x2F;magic&#x2F;Magdir&#x2F;mozilla#L22-L25&quot;&gt;peek&lt;&#x2F;a&gt; at the implementation of &lt;code&gt;file&lt;&#x2F;code&gt;.
It appears to confirm that the uncompressed size is a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Endianness&quot;&gt;little-endian&lt;&#x2F;a&gt; 32-bit number, followed directly by the compressed data.
I assume that the &lt;code&gt;&amp;gt;8&lt;&#x2F;code&gt; annotation means &quot;starting from offset 8&quot; or something similar to that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;writing-some-code&quot;&gt;Writing some code&lt;&#x2F;h2&gt;
&lt;p&gt;This is a &lt;a href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;&quot;&gt;Rust&lt;&#x2F;a&gt;-related blog, so of course I&#x27;ll be using that.
Fortunately, we already have libraries for everything we&#x27;re going to need, so it&#x27;s going to be easy.
We can use &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;lz4_flex&quot;&gt;&lt;code&gt;lz4_flex&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for LZ4 decoding, &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;serde&quot;&gt;&lt;code&gt;serde&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;serde_json&quot;&gt;&lt;code&gt;serde_json&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for JSON decoding, and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;anyhow&quot;&gt;&lt;code&gt;anyhow&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to handle errors in a nicer way.
We&#x27;ll also pull in &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;memmap2&quot;&gt;&lt;code&gt;memmap2&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to map the file in memory (which is optional, but saves a bit of RAM) and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;serde_json&quot;&gt;&lt;code&gt;url&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for URL parsing.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Cargo.toml
&lt;&#x2F;span&gt;&lt;span&gt;[package]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tabs&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;edition &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2021&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[dependencies]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;anyhow &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lz4_flex &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.9&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;memmap2 &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.5&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;serde &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;features &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;serde_json &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2.2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;lz4_flex&lt;&#x2F;code&gt; has a nifty &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;lz4_flex&#x2F;0.9.3&#x2F;lz4_flex&#x2F;fn.decompress_size_prepended.html&quot;&gt;helper function&lt;&#x2F;a&gt; to decode a size-prepended block, exactly what our file uses.
So if we&#x27;re lucky, it should be enough to open the file, read it, then call the decompression function.
With some imports and command line handling omitted, it simply comes to:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; file = File::open(&amp;amp;path)?;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; mmap = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{ MmapOptions::new().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;file)? };
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; buf = lz4_flex::decompress_size_prepended(&amp;amp;mmap[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;..])?;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; buf = String::from_utf8(buf)?;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; check if it worked
&lt;&#x2F;span&gt;&lt;span&gt;println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;buf[..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; cargo run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --release&lt;&#x2F;span&gt;&lt;span&gt; -- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.mozilla&#x2F;firefox&#x2F;ou63gnwj.default
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# snip
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;:[&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sessionrestore&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;,1],&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;windows&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;:[{&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tabs&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;:[{&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;entries&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;:[
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I won&#x27;t show it here, but the way the JSON is structured, the session has a list of windows, each window has a list of tabs, and each tab has a list of history entries.
We only care for the last entry, which is the one currently displayed.&lt;&#x2F;p&gt;
&lt;p&gt;This is pretty easy to parse with &lt;code&gt;serde&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Entry {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Tab {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;entries&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Entry&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Window {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tabs&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Tab&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;SessionStore {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;windows&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Window&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; session = serde_json::from_slice::&amp;lt;SessionStore&amp;gt;(&amp;amp;buf)?;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; domains = HashMap::&amp;lt;_, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;::new();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; window in session.windows {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; tab in window.tabs {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if let &lt;&#x2F;span&gt;&lt;span&gt;Some(entry) = tab.entries.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;last&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; url = Url::parse(&amp;amp;entry.url)?;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; skip about:blank, about:reader etc.
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if let &lt;&#x2F;span&gt;&lt;span&gt;Some(host) = url.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;host_str&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;                *domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;entry&lt;&#x2F;span&gt;&lt;span&gt;(host.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;or_default&lt;&#x2F;span&gt;&lt;span&gt;() += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For this example, I&#x27;m grabbing every tab in every window, making sure it&#x27;s not empty, taking the last entry, then sticking the domain of each URL in a &lt;code&gt;HashMap&lt;&#x2F;code&gt;, in order to count them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: If you know Rust, that snippet looks a bit nicer written in a functional&#x2F;iterator-based style.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;iter&#x2F;trait.Iterator.html#method.collect&quot;&gt;&lt;code&gt;collect&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; the entries into a &lt;code&gt;Vec&lt;&#x2F;code&gt;, sort them, and display the most common domains:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; domains = domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;().collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;sort_unstable_by_key&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| Reverse(p.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(domain, count) in domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;take&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{} {}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, domain, count);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# sample output, truncated
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; cargo run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --release&lt;&#x2F;span&gt;&lt;span&gt; -- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.mozilla&#x2F;firefox&#x2F;ou63gnwj.default
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;github.com&lt;&#x2F;span&gt;&lt;span&gt; 1150
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;www.youtube.com&lt;&#x2F;span&gt;&lt;span&gt; 213
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;twitter.com&lt;&#x2F;span&gt;&lt;span&gt; 206
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;news.ycombinator.com&lt;&#x2F;span&gt;&lt;span&gt; 109
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;I may or may not have a tab hoarding problem.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Full code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::cmp::Reverse;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::collections::HashMap;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::fs::File;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::path::PathBuf;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::{env, process};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;memmap2::MmapOptions;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;serde::Deserialize;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;url::Url;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Entry {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Tab {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;entries&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Entry&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Window {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tabs&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Tab&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;SessionStore {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;windows&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Window&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; args = env::args_os().collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; args.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        eprintln!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Usage: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; &amp;lt;profile&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, args[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string_lossy&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;        process::exit(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; path = PathBuf::from(args.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;remove&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;    path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sessionstore-backups&#x2F;recovery.jsonlz4&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; file = File::open(&amp;amp;path)?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; mmap = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{ MmapOptions::new().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;file)? };
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; buf = lz4_flex::decompress_size_prepended(&amp;amp;mmap[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;..])?;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; session = serde_json::from_slice::&amp;lt;SessionStore&amp;gt;(&amp;amp;buf)?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; domains = HashMap::&amp;lt;_, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;::new();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; window in session.windows {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; tab in window.tabs {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if let &lt;&#x2F;span&gt;&lt;span&gt;Some(entry) = tab.entries.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;last&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; url = Url::parse(&amp;amp;entry.url)?;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; println!(&amp;quot;{url}&amp;quot;); &#x2F;&#x2F; uncomment this to show all URLs
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if let &lt;&#x2F;span&gt;&lt;span&gt;Some(host) = url.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;host_str&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;                    *domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;entry&lt;&#x2F;span&gt;&lt;span&gt;(host.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;or_default&lt;&#x2F;span&gt;&lt;span&gt;() += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                }
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; domains = domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;().collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;sort_unstable_by_key&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| Reverse(p.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(domain, count) in domains.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;take&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{} {}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, domain, count);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    Ok(())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve uncompressed a Firefox session backup and printed the most common domains in the open tabs.&lt;&#x2F;p&gt;
&lt;p&gt;I actually think this is quite a poor choice of format for sessions like mine.
Perhaps you&#x27;ve noticed that my session was 142 MB uncompressed, which is not insignificant.
Worse, it&#x27;s on-disk size is 42 MB, and Firefox tends to write it every couple of seconds (but only as long as it changes, I hope).
That&#x27;s pretty bad, not only for performance (since the file must be rewritten every time you scroll, navigate to another page, or type something in a form), but can also reduce the lifespan of an SSD drive.&lt;&#x2F;p&gt;
&lt;p&gt;Because of this, people ended up with &lt;a href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;title&#x2F;profile-sync-daemon&quot;&gt;workarounds&lt;&#x2F;a&gt; to keep the session on a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;RAM_drive&quot;&gt;RAM drive&lt;&#x2F;a&gt;, at the cost of durability in case of a power failure or a crash.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t know the reasoning behind this design, but I suspect the vast majority of users have less than four tabs.
Maybe the Firefox engineers wanted to avoid calling into SQLite while restoring the session.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;By the way, if you&#x27;ve ever felt anxious about your ever-growing tab list, please consider &lt;a href=&quot;https:&#x2F;&#x2F;www.buymeacoffee.com&#x2F;lnicolaq&quot;&gt;buying me a coffee&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Debugging a mysterious Python crash</title>
        <published>2022-05-28T00:00:00+00:00</published>
        <updated>2022-05-28T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/a-mysterous-python-crash/" type="text/html" />
        <id>https://blog.dend.ro/a-mysterous-python-crash/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;I recently wanted to prepare a Jupyter notebook with some example code and ran into an interesting problem: trying to display a Matplotlib chart made the IPython kernel crash.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gathering-more-info&quot;&gt;Gathering more info&lt;&#x2F;h2&gt;
&lt;p&gt;Luckily, the crash was easy to reproduce outside of Jupyter:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; python3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -c &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;import matplotlib.pyplot as plt; plt.axes()&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Illegal&lt;&#x2F;span&gt;&lt;span&gt; instruction
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This usually means one of two things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;some compilers &#x2F; standard libraries produce an &lt;code&gt;ud2&lt;&#x2F;code&gt; instruction in order to abort the program execution, e.g. &lt;code&gt;core::intrinsics::abort()&lt;&#x2F;code&gt; in Rust.&lt;&#x2F;li&gt;
&lt;li&gt;the program tried to execute an instruction that is not available on the CPU it was running on.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I&#x27;ve encountered the former one much more often than the latter, but many popular Python libraries code call into optimized C.
To be honest, I was pretty sure this was caused by my mess of old, distro-supplied packages (from CentOS 7), in combination with some installed using &lt;code&gt;pip&lt;&#x2F;code&gt;.
Of course, it&#x27;s better to check than to guess:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; gdb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --args&lt;&#x2F;span&gt;&lt;span&gt; python3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -c &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;import matplotlib.pyplot as plt; plt.axes()&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;) r
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Starting&lt;&#x2F;span&gt;&lt;span&gt; program: &#x2F;usr&#x2F;bin&#x2F;python3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -c&lt;&#x2F;span&gt;&lt;span&gt; import&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\ &lt;&#x2F;span&gt;&lt;span&gt;matplotlib.pyplot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\ &lt;&#x2F;span&gt;&lt;span&gt;as&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\ &lt;&#x2F;span&gt;&lt;span&gt;plt&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\;\ &lt;&#x2F;span&gt;&lt;span&gt;plt.axes&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\(\)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[Thread&lt;&#x2F;span&gt;&lt;span&gt; debugging using libthread_db enabled]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Using&lt;&#x2F;span&gt;&lt;span&gt; host libthread_db library &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;usr&#x2F;lib&#x2F;libthread_db.so.1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Thread&lt;&#x2F;span&gt;&lt;span&gt; 1 &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;python3&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; received signal SIGILL, Illegal instruction.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0x00007ffff556545c&lt;&#x2F;span&gt;&lt;span&gt; in dgemm_kernel_PILEDRIVER () &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;usr&#x2F;local&#x2F;lib64&#x2F;python3.6&#x2F;site-packages&#x2F;numpy&#x2F;core&#x2F;..&#x2F;..&#x2F;numpy.libs&#x2F;libopenblasp-r0-8a0c371f.3.13.so
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Heads-up: for reasons I&#x27;ll show below, I&#x27;m reproducing the issue on my own computer. I&#x27;m trying to doctor the outputs, but there might be some inconsistencies.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It appears to be crashing in a &lt;code&gt;dgemm&lt;&#x2F;code&gt; kernel in OpenBLAS, docs courtesy of LAPACK:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;DGEMM  performs one of the matrix-matrix operations
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;C := alpha*op( A )*op( B ) + beta*C,
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;where  op( X ) is one of
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;op( X ) = X   or   op( X ) = X**T,
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;alpha and beta are scalars, and A, B and C are matrices, with op( A )
&lt;&#x2F;span&gt;&lt;span&gt;an m by k matrix,  op( B )  a  k by n matrix and  C an m by n matrix.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s basically a fancy matrix multiplication.
More importantly, notice the Piledriver reference in the function name.
Piledriver is an AMD microarchitecture from around 2012–2014, which is hopefully not what I&#x27;m running on.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, function names aren&#x27;t always accurate, especially in highly-optimized code.
We can ask GDB to disassemble the current function in order to check the place where the code crashed and it will output a 4890-line monstruosity:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(gdb) disassemble
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;Dump of assembler code for function dgemm_kernel_PILEDRIVER:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff555fe00 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;sub    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x60&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff555fe04 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rbx&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff555fe08 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rbp&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;snip&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff5565450 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;22096&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;vmovddup &lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x20&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsi&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rbp&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff5565456 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;22102&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;vmovups &lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x80&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff556545c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;22108&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;vfmaddpd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm4
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff5565462 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;22114&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;vmovddup &lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x18&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsi&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rbp&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x00007ffff5565468 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;22120&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;:    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;vfmaddpd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xmm5
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The crashing opcode was &lt;code&gt;vfmaddpd&lt;&#x2F;code&gt;.
I&#x27;ve never encountered it before — not exactly surprising — but notice how it has four operands, which is pretty rare in &lt;code&gt;x86&lt;&#x2F;code&gt; instructions.
That said, it&#x27;s pretty easy to guess what it does if you can unpack its mnemonic:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v&lt;&#x2F;code&gt;: vector (SIMD) instruction, meaning it operates not on scalars, but on vector registers with multiple values&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;fma&lt;&#x2F;code&gt;: fused multiply-add, that is, a multiplication and addition in one step, for better performance, precision, or both&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;p&lt;&#x2F;code&gt;: packed, meaning it uses all the values in the registers (as opposed to the scalar ones, which only touch a single value in a vector register)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;d&lt;&#x2F;code&gt;: double-precision, i.e. 64-bit floating-point numbers&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Peeking at &lt;a href=&quot;https:&#x2F;&#x2F;www.amd.com&#x2F;system&#x2F;files&#x2F;TechDocs&#x2F;43479.pdf&quot;&gt;the docs&lt;&#x2F;a&gt;, the instruction name is &lt;code&gt;Multiply and Add Packed Double-Precision Floating-Point&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;VFMADDPD &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;dest&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;src1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;src2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;src3 # dest = (src1 &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;src2) &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;src3
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It doesn&#x27;t matter for us, but &lt;code&gt;xmm&lt;&#x2F;code&gt; are 128-bit registers, so it&#x27;s working on pairs &lt;code&gt;double&lt;&#x2F;code&gt;s.&lt;&#x2F;p&gt;
&lt;p&gt;This is an &lt;code&gt;FMA4&lt;&#x2F;code&gt; (four-operand FMA) instruction, which has a bit of a weird history.
It was introduced by AMD, but Intel never implemented it.
Instead, Intel added their own &lt;code&gt;FMA3&lt;&#x2F;code&gt; (three-operand) instructions, which look like &lt;code&gt;vfmadd213pd xmm0, xmm1, xmm2&lt;&#x2F;code&gt; and don&#x27;t have a separate destination.
If you&#x27;re wondering, &lt;code&gt;213&lt;&#x2F;code&gt; specifies the operand order, the one here doing &lt;code&gt;xmm0 = xmm1 * xmm0 + xmm2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, AMD dropped FMA4 in 2017 with the Zen microarchitecture, which probably caused some confusion because the instructions still work, but give the wrong results sometimes.&lt;&#x2F;p&gt;
&lt;p&gt;By this point, we have a theory: our CPU does not support FMA4, but OpenBLAS (used by &lt;code&gt;numpy&lt;&#x2F;code&gt;, used by &lt;code&gt;matplotlib&lt;&#x2F;code&gt;) thinks it does, picks up that code path and happily crashes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;opteron&quot;&gt;Opteron&lt;&#x2F;h2&gt;
&lt;p&gt;I don&#x27;t have the &lt;code&gt;&#x2F;proc&#x2F;cpuinfo&lt;&#x2F;code&gt; output any more (see below), but the model name was &lt;code&gt;AMD Opteron 63xx class&lt;&#x2F;code&gt;, or something similar.
This is a virtual machine, so I&#x27;m assuming the hypervisor was reporting an older CPU model.&lt;&#x2F;p&gt;
&lt;p&gt;Software can detect CPU features in a fine-grained way (using the &lt;code&gt;cpuid&lt;&#x2F;code&gt; instruction), but OpenBLAS only checks for the CPU model &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;xianyi&#x2F;OpenBLAS&#x2F;blob&#x2F;d33fc32cf30cf1262030c93fa44c72ca8ab27681&#x2F;cpuid_x86.c#L1288-L1327&quot;&gt;here&lt;&#x2F;a&gt; and then again &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;xianyi&#x2F;OpenBLAS&#x2F;blob&#x2F;d33fc32cf30cf1262030c93fa44c72ca8ab27681&#x2F;driver&#x2F;others&#x2F;dynamic.c#L353-L385&quot;&gt;here&lt;&#x2F;a&gt;.
There actually was an &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;List_of_AMD_Opteron_processors#3300-,_4300-_&amp;amp;_6300-series_Opterons&quot;&gt;Opteron 6300&lt;&#x2F;a&gt; series, which matches the reported model name and did support &lt;code&gt;FMA4&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I also tried &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;rindeal&#x2F;81198b1cf8f55c356743#file-cpuid-dump2-c&quot;&gt;some code&lt;&#x2F;a&gt; that checks specifically for &lt;code&gt;FMA4&lt;&#x2F;code&gt;.
I can&#x27;t run it again, but indeed, it reported no &lt;code&gt;FMA4&lt;&#x2F;code&gt; support.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-fix-and-a-twist&quot;&gt;The fix and a twist&lt;&#x2F;h2&gt;
&lt;p&gt;Knowing the problem, the fix was pretty simple.
Fortunately, OpenBLAS supports overriding the CPU-specific code paths through an environment variable, and setting &lt;code&gt;OPENBLAS_CORETYPE=ZEN&lt;&#x2F;code&gt; made it work.
I still filed &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;xianyi&#x2F;OpenBLAS&#x2F;issues&#x2F;3638&quot;&gt;an issue&lt;&#x2F;a&gt; against the OpenBLAS repo,
in case anyone else runs into this.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, one day later, I can&#x27;t run my notebook because the &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; partition is mounted read-only, the file system might be corrupted, and pretty much everything is broken. But for once, it&#x27;s not my fault 😅.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;FileNotFoundError: [Errno 2] No usable temporary directory found in [&amp;#39;&#x2F;tmp&amp;#39;, &amp;#39;&#x2F;var&#x2F;tmp&amp;#39;, &amp;#39;&#x2F;usr&#x2F;tmp&amp;#39;, &amp;#39;&#x2F;home&#x2F;user&amp;#39;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Yes, I could mount &lt;code&gt;tmpfs&lt;&#x2F;code&gt; into &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt;, but it doesn&#x27;t matter.&lt;&#x2F;p&gt;
&lt;p&gt;And the Opteron magically turned into an EPYC:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;processor       : 0
&lt;&#x2F;span&gt;&lt;span&gt;vendor_id       : AuthenticAMD
&lt;&#x2F;span&gt;&lt;span&gt;cpu family      : 23
&lt;&#x2F;span&gt;&lt;span&gt;model           : 49
&lt;&#x2F;span&gt;&lt;span&gt;model name      : AMD EPYC 7502P 32-Core Processor
&lt;&#x2F;span&gt;&lt;span&gt;stepping        : 0
&lt;&#x2F;span&gt;&lt;span&gt;microcode       : 0x1000065
&lt;&#x2F;span&gt;&lt;span&gt;cpu MHz         : 2500.001
&lt;&#x2F;span&gt;&lt;span&gt;cache size      : 512 KB
&lt;&#x2F;span&gt;&lt;span&gt;physical id     : 0
&lt;&#x2F;span&gt;&lt;span&gt;siblings        : 1
&lt;&#x2F;span&gt;&lt;span&gt;core id         : 0
&lt;&#x2F;span&gt;&lt;span&gt;cpu cores       : 1
&lt;&#x2F;span&gt;&lt;span&gt;apicid          : 0
&lt;&#x2F;span&gt;&lt;span&gt;initial apicid  : 0
&lt;&#x2F;span&gt;&lt;span&gt;fpu             : yes
&lt;&#x2F;span&gt;&lt;span&gt;fpu_exception   : yes
&lt;&#x2F;span&gt;&lt;span&gt;cpuid level     : 16
&lt;&#x2F;span&gt;&lt;span&gt;wp              : yes
&lt;&#x2F;span&gt;&lt;span&gt;flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm art rep_good nopl extd_apicid eagerfpu pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core retpoline_amd ssbd ibrs ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 virt_ssbd arat npt nrip_save umip spec_ctrl
&lt;&#x2F;span&gt;&lt;span&gt;bogomips        : 5000.00
&lt;&#x2F;span&gt;&lt;span&gt;TLB size        : 1024 4K pages
&lt;&#x2F;span&gt;&lt;span&gt;clflush size    : 64
&lt;&#x2F;span&gt;&lt;span&gt;cache_alignment : 64
&lt;&#x2F;span&gt;&lt;span&gt;address sizes   : 40 bits physical, 48 bits virtual
&lt;&#x2F;span&gt;&lt;span&gt;power management:
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Just a couple of things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;feature detection is better than version checking not only when writing JavaScript, but even when targeting low-level code&lt;&#x2F;li&gt;
&lt;li&gt;it&#x27;s a good idea to provide escape hatches from optimized code paths&lt;&#x2F;li&gt;
&lt;li&gt;the CPU is a lie&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;And by the way, if you enjoyed this short post, please consider &lt;a href=&quot;https:&#x2F;&#x2F;www.buymeacoffee.com&#x2F;lnicolaq&quot;&gt;buying me a coffee&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Blogroll</title>
        <published>2022-05-24T00:00:00+00:00</published>
        <updated>2022-05-24T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/content/blogroll/" type="text/html" />
        <id>https://blog.dend.ro/content/blogroll/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;muscar.eu&#x2F;&quot;&gt;Alex&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Building Rust code for my OpenWrt Wi-Fi router</title>
        <published>2022-05-08T00:00:00+00:00</published>
        <updated>2022-05-08T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/building-rust-for-routers/" type="text/html" />
        <id>https://blog.dend.ro/building-rust-for-routers/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;I recently got interested in running Rust code on my router (stay tuned for a future blog post?).
This is supposed to be easy, but I never tried it, so let&#x27;s see how it goes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-test-project&quot;&gt;A test project&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;Hello, world&lt;&#x2F;em&gt;s are somewhat boring, so I&#x27;d like to build something more realistic — a DNS client.
We&#x27;re not going to implement DNS here, but rather piggy-back on the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;trust-dns-resolver&quot;&gt;&lt;code&gt;trust-dns-resolver&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crate, which looks pretty good.&lt;&#x2F;p&gt;
&lt;p&gt;After skimming the &lt;code&gt;trust-dns&lt;&#x2F;code&gt; and &lt;code&gt;tokio&lt;&#x2F;code&gt; docs, and a &lt;code&gt;cargo new delve&lt;&#x2F;code&gt; (shouts to &lt;code&gt;dig&lt;&#x2F;code&gt; and &lt;code&gt;drill&lt;&#x2F;code&gt;), we have this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span&gt;[package]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;delve&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;edition &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2021&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[dependencies]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;anyhow &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tokio &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.18&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;features &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;net&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;rt-multi-thread&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;trust-dns-resolver &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.21&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;features &lt;&#x2F;span&gt;&lt;span&gt;= [
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;dns-over-rustls&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tokio&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;] }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::env;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;tokio::runtime;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;trust_dns_resolver::{
&lt;&#x2F;span&gt;&lt;span&gt;    config::{ResolverConfig, ResolverOpts},
&lt;&#x2F;span&gt;&lt;span&gt;    proto::{rr::RecordType, xfer::DnsRequestOptions},
&lt;&#x2F;span&gt;&lt;span&gt;    TokioAsyncResolver,
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Result&amp;lt;(), anyhow::Error&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; resolver =
&lt;&#x2F;span&gt;&lt;span&gt;        TokioAsyncResolver::tokio(ResolverConfig::cloudflare_tls(), ResolverOpts::default())?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; query = env::args().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;nth&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; response = resolver
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;lookup&lt;&#x2F;span&gt;&lt;span&gt;(query, RecordType::A, DnsRequestOptions::default())
&lt;&#x2F;span&gt;&lt;span&gt;        .await?;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; address in response.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;        println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, address);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    Ok(())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Result&amp;lt;(), anyhow::Error&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; runtime = runtime::Builder::new_multi_thread().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;enable_all&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;()?;
&lt;&#x2F;span&gt;&lt;span&gt;    runtime.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;block_on&lt;&#x2F;span&gt;&lt;span&gt;(async { tokio::spawn(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;()).await })?
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code is pretty simple.
It creates a &lt;code&gt;tokio&lt;&#x2F;code&gt; multi-threaded &lt;code&gt;Runtime&lt;&#x2F;code&gt;, sets up a &lt;code&gt;trust-dns&lt;&#x2F;code&gt; &lt;code&gt;TokioAsyncResolver&lt;&#x2F;code&gt;, then queries the Cloudflare DNS server for the hostname given in the command line.
&lt;code&gt;RecordType::A&lt;&#x2F;code&gt; means asking for an IPv4 address record.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re wondering about the &lt;code&gt;block_on&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;spawn&lt;&#x2F;code&gt; dance, apparently &lt;code&gt;tokio&lt;&#x2F;code&gt; prefers that you don&#x27;t do a lot of work in &lt;code&gt;block_on&lt;&#x2F;code&gt;, but rather spawn a root future and do your stuff from there.
It doesn&#x27;t really matter in this case, and &lt;code&gt;trust-dns-resolver&lt;&#x2F;code&gt; helpfully provides a synchronous resolver, but it will matter in the project I have in mind.&lt;&#x2F;p&gt;
&lt;p&gt;And it does appear to work fine:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; cargo run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --release&lt;&#x2F;span&gt;&lt;span&gt; -- google.com
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Finished&lt;&#x2F;span&gt;&lt;span&gt; release &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;optimized&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; target(s) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; 9.66s
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Running &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target&#x2F;release&#x2F;delve&lt;&#x2F;span&gt;&lt;span&gt; google.com`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;142.250.179.174
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;inside-my-router&quot;&gt;Inside my router&lt;&#x2F;h2&gt;
&lt;p&gt;My router is an AVM FRITZ!Box 4040 running OpenWrt.
As far as embedded systems go, OpenWrt is pretty close to a Linux PC.
I&#x27;ve already enabled SSH and added my key, but I don&#x27;t know what architecture it&#x27;s running.
Fortunately, &lt;code&gt;uname -a&lt;&#x2F;code&gt; works just as expected:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;root@OpenWrt:~#&lt;&#x2F;span&gt;&lt;span&gt; uname&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -a
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Linux&lt;&#x2F;span&gt;&lt;span&gt; OpenWrt 4.14.171 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#0 SMP Thu Feb 27 21:05:12 2020 armv7l GNU&#x2F;Linux
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;root@OpenWrt:~#&lt;&#x2F;span&gt;&lt;span&gt; cat &#x2F;proc&#x2F;cpuinfo
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;processor&lt;&#x2F;span&gt;&lt;span&gt;	: 0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;model&lt;&#x2F;span&gt;&lt;span&gt; name	: ARMv7 Processor rev 5 (v7l)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;BogoMIPS&lt;&#x2F;span&gt;&lt;span&gt;	: 67.03
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Features&lt;&#x2F;span&gt;&lt;span&gt;	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; implementer	: 0x41
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; architecture: 7
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; variant	: 0x0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; part	: 0xc07
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; revision	: 5
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;processor&lt;&#x2F;span&gt;&lt;span&gt;	: 1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;model&lt;&#x2F;span&gt;&lt;span&gt; name	: ARMv7 Processor rev 5 (v7l)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;BogoMIPS&lt;&#x2F;span&gt;&lt;span&gt;	: 67.03
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Features&lt;&#x2F;span&gt;&lt;span&gt;	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; implementer	: 0x41
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; architecture: 7
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; variant	: 0x0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; part	: 0xc07
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; revision	: 5
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;processor&lt;&#x2F;span&gt;&lt;span&gt;	: 2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;model&lt;&#x2F;span&gt;&lt;span&gt; name	: ARMv7 Processor rev 5 (v7l)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;BogoMIPS&lt;&#x2F;span&gt;&lt;span&gt;	: 67.03
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Features&lt;&#x2F;span&gt;&lt;span&gt;	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; implementer	: 0x41
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; architecture: 7
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; variant	: 0x0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; part	: 0xc07
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; revision	: 5
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;processor&lt;&#x2F;span&gt;&lt;span&gt;	: 3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;model&lt;&#x2F;span&gt;&lt;span&gt; name	: ARMv7 Processor rev 5 (v7l)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;BogoMIPS&lt;&#x2F;span&gt;&lt;span&gt;	: 67.03
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Features&lt;&#x2F;span&gt;&lt;span&gt;	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; implementer	: 0x41
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; architecture: 7
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; variant	: 0x0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; part	: 0xc07
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CPU&lt;&#x2F;span&gt;&lt;span&gt; revision	: 5
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Hardware&lt;&#x2F;span&gt;&lt;span&gt;	: Generic DT based system
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Revision&lt;&#x2F;span&gt;&lt;span&gt;	: 0000
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Serial&lt;&#x2F;span&gt;&lt;span&gt;		: 0000000000000000
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;root@OpenWrt:~#&lt;&#x2F;span&gt;&lt;span&gt; ldd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --version
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;musl&lt;&#x2F;span&gt;&lt;span&gt; libc (armhf)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Version&lt;&#x2F;span&gt;&lt;span&gt; 1.1.24
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Dynamic&lt;&#x2F;span&gt;&lt;span&gt; Program Loader
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Usage:&lt;&#x2F;span&gt;&lt;span&gt; ldd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;options&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;] [&lt;&#x2F;span&gt;&lt;span&gt;--&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; pathname
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So it appears a 4-core ARMv7 CPU with hardware floating-point support, running a MUSL-based distro.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cross-compiling&quot;&gt;Cross-compiling&lt;&#x2F;h2&gt;
&lt;p&gt;Rust supports dozens of targets, but ARMv7 is pretty common, so it&#x27;s hopefully well-supported.
I&#x27;m not sure how the target is called, so &lt;code&gt;rustup target list&lt;&#x2F;code&gt; is handy:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; rustup target list | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rg&lt;&#x2F;span&gt;&lt;span&gt; armv7
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7-linux-androideabi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7-unknown-linux-gnueabi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7-unknown-linux-gnueabihf
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7-unknown-linux-musleabi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7-unknown-linux-musleabihf &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# sounds like a winner
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7a-none-eabi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7r-none-eabi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;armv7r-none-eabihf
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; rustup target add armv7-unknown-linux-musleabihf
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;info:&lt;&#x2F;span&gt;&lt;span&gt; downloading component &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;rust-std&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; for &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;armv7-unknown-linux-musleabihf&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;info:&lt;&#x2F;span&gt;&lt;span&gt; installing component &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;rust-std&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; for &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;armv7-unknown-linux-musleabihf&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Great, let&#x27;s try it!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; cargo build&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --release --target&lt;&#x2F;span&gt;&lt;span&gt; armv7-unknown-linux-musleabihf
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error:&lt;&#x2F;span&gt;&lt;span&gt; linking with `&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cc&lt;&#x2F;span&gt;&lt;span&gt;` failed: exit status: 1
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip&lt;&#x2F;span&gt;&lt;span&gt; half a screenful of errors]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oh, we also need a linker.
This would normally be a version of the BFD linker (&lt;code&gt;ld&lt;&#x2F;code&gt;).
Unlike &lt;code&gt;clang&lt;&#x2F;code&gt; and &lt;code&gt;rustc&lt;&#x2F;code&gt;, &lt;code&gt;gcc&lt;&#x2F;code&gt; and &lt;code&gt;ld&lt;&#x2F;code&gt; only support one target at a time, so I&#x27;d have to track down or compile a compatible version.
My Linux distro actually has one, available in AUR as &lt;code&gt;muslcc-arm-linux-musleabihf-cross-bin&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But since we&#x27;re compiling pure-Rust code — did you notice the fancy &lt;code&gt;rustls&lt;&#x2F;code&gt; feature of &lt;code&gt;trust-dns-resolver&lt;&#x2F;code&gt;? — the LLVM linker, &lt;code&gt;lld&lt;&#x2F;code&gt;, will do the trick with less work.&lt;&#x2F;p&gt;
&lt;p&gt;The correct incantation is then:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER=rust-lld cargo build&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --release --target&lt;&#x2F;span&gt;&lt;span&gt; armv7-unknown-linux-musleabihf
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Finished&lt;&#x2F;span&gt;&lt;span&gt; release &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;optimized&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; target(s) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; 9.50s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Is that all?
That was surpisingly easy!&lt;&#x2F;p&gt;
&lt;p&gt;And by the way, you can also set the linker in &lt;code&gt;.config&#x2F;cargo.toml&lt;&#x2F;code&gt;, like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span&gt;[target.armv7-unknown-linux-musleabihf]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;linker &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;rust-lld&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h2&gt;
&lt;p&gt;We could test using QEMU, but that seems too much of a hassle, as the real hardware is already available.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; scp target&#x2F;armv7-unknown-linux-musleabihf&#x2F;release&#x2F;delve root@192.168.2.1:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scp:&lt;&#x2F;span&gt;&lt;span&gt; Connection closed
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The router is running OpenSSH 8.0p1, but &lt;code&gt;scp&lt;&#x2F;code&gt; is deprecated, and the version on my PC uses SFTP by default.
The &lt;code&gt;-O&lt;&#x2F;code&gt; flag reverts to the deprecated protocol:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; scp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -O&lt;&#x2F;span&gt;&lt;span&gt; target&#x2F;armv7-unknown-linux-musleabihf&#x2F;release&#x2F;delve root@192.168.2.1:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;delve&lt;&#x2F;span&gt;&lt;span&gt;                                        100% 8598KB 176.1KB&#x2F;s   00:48
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s a larger binary than I&#x27;d like, but 176 KB&#x2F;s seems pretty slow.
I know my network is faster that this, but it could be the file system:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;root@OpenWrt:~#&lt;&#x2F;span&gt;&lt;span&gt; mount
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;root&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;rom type squashfs (ro,relatime)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;proc&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;proc type proc (rw,nosuid,nodev,noexec,noatime)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sysfs&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;sys type sysfs (rw,nosuid,nodev,noexec,noatime)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tmpfs&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;tmp type tmpfs (rw,nosuid,nodev,noatime)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;mtdblock14&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;overlay type jffs2 (rw,noatime)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;overlayfs:&#x2F;overlay&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F; type overlay (rw,noatime,lowerdir=&#x2F;,upperdir=&#x2F;overlay&#x2F;upper,workdir=&#x2F;overlay&#x2F;work)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tmpfs&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;dev type tmpfs (rw,nosuid,relatime,size=512k,mode=755)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;devpts&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;dev&#x2F;pts type devpts (rw,nosuid,noexec,relatime,mode=600,ptmxmode=000)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;debugfs&lt;&#x2F;span&gt;&lt;span&gt; on &#x2F;sys&#x2F;kernel&#x2F;debug type debugfs (rw,noatime)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oh, okay, let&#x27;s copy it to &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt; instead:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; scp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -O&lt;&#x2F;span&gt;&lt;span&gt; target&#x2F;armv7-unknown-linux-musleabihf&#x2F;release&#x2F;delve root@192.168.2.1:&#x2F;tmp
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;delve&lt;&#x2F;span&gt;&lt;span&gt;                                        100% 8598KB  11.6MB&#x2F;s   00:00
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;More importantly, does it work?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;root@OpenWrt:~#&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;tmp&#x2F;delve news.ycombinator.com
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;209.216.230.240
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Honestly, I was more suprised to see it working than you are.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-about-the-binary-size&quot;&gt;What about the binary size?&lt;&#x2F;h2&gt;
&lt;p&gt;Our executable packs in quite a bit: Tokio, an async DNS client, and a TLS implementation for DNS-over-TLS.
But at 8.5 MB, it&#x27;s pretty large for a Wi-Fi router with 128 MB of flash.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see if we can get it to weigh less, testing with the PC version.
I know that a large part of the binary must be the symbols.
I&#x27;d normally use &lt;code&gt;strip -s&lt;&#x2F;code&gt;, but &lt;code&gt;cargo&lt;&#x2F;code&gt; can do this by itself.
This is also a good excuse to try the custom profiles feature.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s start by adding a new profile to &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span&gt;[profile.minsize]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;inherits &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;release&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;, then build it with &lt;code&gt;cargo build --profile minsize&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s a lot of resources out there with tips for reducing the binary sizes (it&#x27;s a common complaint), so I&#x27;ll just list each thing I&#x27;ve tried, incrementally:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;baseline: 8.5 MB&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;strip = true&lt;&#x2F;code&gt;: 3.2 MB&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lto = &quot;thin&quot;&lt;&#x2F;code&gt;: 3.1 MB&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lto = &quot;fat&quot;&lt;&#x2F;code&gt;: 2.6 MB (didn&#x27;t expect this!)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;opt-level = &quot;s&quot;&lt;&#x2F;code&gt;: 2.3 MB (didn&#x27;t expect this either)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;panic = &quot;abort&quot;&lt;&#x2F;code&gt;: 2.1 MB&lt;&#x2F;li&gt;
&lt;li&gt;switch to the single-thread &lt;code&gt;tokio&lt;&#x2F;code&gt; runtime: 2.0 MB&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cargo build -Z build-std=panic_abort,std --profile minsize --target x86_64-unknown-linux-gnu&lt;&#x2F;code&gt; (you&#x27;ll need nightly or &lt;code&gt;RUSTC_BOOTSTRAP=1&lt;&#x2F;code&gt; for this): 1.9 MB&lt;&#x2F;li&gt;
&lt;li&gt;disable the &lt;code&gt;system-config&lt;&#x2F;code&gt; feature of &lt;code&gt;trust-dns-resolver&lt;&#x2F;code&gt;: 1.9 MB&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Rebuilding it for the router, we get a 1.4 MB binary, which is still a bit large, but workable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bonus-packaging-for-openwrt&quot;&gt;Bonus: packaging for OpenWrt&lt;&#x2F;h2&gt;
&lt;p&gt;I was curious about making a binary package for OpenWrt, which appears to use a format inspired by Debian (&lt;code&gt;ipkg&lt;&#x2F;code&gt;).
Reading the docs isn&#x27;t fun, but we can find where the package manager (&lt;code&gt;okpg&lt;&#x2F;code&gt;) downloads stuff from (&lt;code&gt;&#x2F;etc&#x2F;opkg&#x2F;distfeeds.conf&lt;&#x2F;code&gt;), then get a random package from there.&lt;&#x2F;p&gt;
&lt;p&gt;I picked &lt;code&gt;attr_20170915-1_arm_cortex-a7_neon-vfpv4.ipk&lt;&#x2F;code&gt;, which appears to be a &lt;code&gt;.tar.gz&lt;&#x2F;code&gt; archive, containing three files:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;control.tar.gz&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;data.tar.gz&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;debian-binary&lt;&#x2F;code&gt;, a text file saying &lt;code&gt;2.0&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;control.tar.gz&lt;&#x2F;code&gt; has one metadata file, &lt;code&gt;control&lt;&#x2F;code&gt;, and some pre- and post-install scripts we can copy over or ignore:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Package: attr
&lt;&#x2F;span&gt;&lt;span&gt;Version: 20170915-1
&lt;&#x2F;span&gt;&lt;span&gt;Depends: libc, libattr
&lt;&#x2F;span&gt;&lt;span&gt;Source: feeds&#x2F;packages&#x2F;utils&#x2F;attr
&lt;&#x2F;span&gt;&lt;span&gt;License: LGPL-2.1 GPL-2.0
&lt;&#x2F;span&gt;&lt;span&gt;LicenseFiles: doc&#x2F;COPYING doc&#x2F;COPYING.LGPL
&lt;&#x2F;span&gt;&lt;span&gt;Section: utils
&lt;&#x2F;span&gt;&lt;span&gt;Maintainer: Maxim Storchak &amp;lt;m.storchak@gmail.com&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;Architecture: arm_cortex-a7_neon-vfpv4
&lt;&#x2F;span&gt;&lt;span&gt;Installed-Size: 11080
&lt;&#x2F;span&gt;&lt;span&gt;Description:  Extended attributes support
&lt;&#x2F;span&gt;&lt;span&gt; This package provides xattr manipulation utilities
&lt;&#x2F;span&gt;&lt;span&gt; - attr
&lt;&#x2F;span&gt;&lt;span&gt; - getfattr
&lt;&#x2F;span&gt;&lt;span&gt; - setfattr
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Interestingly, my router uses &lt;code&gt;vfpv4&lt;&#x2F;code&gt; packages, even though only &lt;code&gt;vfpv3&lt;&#x2F;code&gt; appears in &lt;code&gt;&#x2F;proc&#x2F;cpuinfo&lt;&#x2F;code&gt;.
Well, whatever makes it happy.
The &lt;code&gt;Installed-Size&lt;&#x2F;code&gt; field is also strange, as it doesn&#x27;t seem to match the size of the files.
It&#x27;s optional optional, so it doesn&#x27;t matter too much.&lt;&#x2F;p&gt;
&lt;p&gt;We can make a similar file:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Package: delve
&lt;&#x2F;span&gt;&lt;span&gt;Version: 0.0.1
&lt;&#x2F;span&gt;&lt;span&gt;Depends: libc
&lt;&#x2F;span&gt;&lt;span&gt;License: MIT
&lt;&#x2F;span&gt;&lt;span&gt;Section: utils
&lt;&#x2F;span&gt;&lt;span&gt;Architecture: arm_cortex-a7_neon-vfpv4
&lt;&#x2F;span&gt;&lt;span&gt;Installed-Size: 1414464
&lt;&#x2F;span&gt;&lt;span&gt;Description: DNS testing tool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, &lt;code&gt;data.tar.gz&lt;&#x2F;code&gt; contains the installed tree.
Putting things together, we have:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;├── control
&lt;&#x2F;span&gt;&lt;span&gt;├── control.tar.gz
&lt;&#x2F;span&gt;&lt;span&gt;├── data.tar.gz
&lt;&#x2F;span&gt;&lt;span&gt;├── debian-binary
&lt;&#x2F;span&gt;&lt;span&gt;├── delve_0.0.1_arm_cortex-a7_neon-vfpv4.ipk
&lt;&#x2F;span&gt;&lt;span&gt;└── usr
&lt;&#x2F;span&gt;&lt;span&gt;    └── bin
&lt;&#x2F;span&gt;&lt;span&gt;        └── delve
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;2 directories, 6 files
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And on the router:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;root@OpenWrt:&#x2F;tmp#&lt;&#x2F;span&gt;&lt;span&gt; opkg install delve_0.0.1_arm_cortex-a7_neon-vfpv4.ipk
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Installing&lt;&#x2F;span&gt;&lt;span&gt; delve (0.0.1) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to&lt;&#x2F;span&gt;&lt;span&gt; root...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Configuring&lt;&#x2F;span&gt;&lt;span&gt; delve.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;root@OpenWrt:&#x2F;tmp#&lt;&#x2F;span&gt;&lt;span&gt; delve sci-hub.se
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;186.2.163.219
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you ever try this, make sure to actually compress the archives using &lt;code&gt;gzip&lt;&#x2F;code&gt; (or &lt;code&gt;tar czf&lt;&#x2F;code&gt;).
I forgot that &lt;code&gt;tar&lt;&#x2F;code&gt; only guesses the format when extracting, and &lt;code&gt;opkg install&lt;&#x2F;code&gt; greeted me with a fun &lt;code&gt;Segmentation fault&lt;&#x2F;code&gt; message.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;naming-apologies&quot;&gt;Naming apologies&lt;&#x2F;h2&gt;
&lt;p&gt;I just realized that the &lt;code&gt;delve&lt;&#x2F;code&gt; name is already taken by a Go debugger.
Not that it matters, as nobody will be using this, but it&#x27;s a common source of complaints.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;&#x2F;h2&gt;
&lt;p&gt;To sum up, we wrote a simple DNS client, tweaked things a little to reduce the binary size, cross-compiled it for an ARM Wi-Fi router, packaged and tested it there.
Surprisingly, it actually worked.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for staying with me, and if you found this interesting please &lt;a href=&quot;https:&#x2F;&#x2F;www.buymeacoffee.com&#x2F;lnicolaq&quot;&gt;consider buying me a coffee&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Some eye candy</title>
        <published>2022-03-30T00:00:00+00:00</published>
        <updated>2022-03-30T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/some-eye-candy/" type="text/html" />
        <id>https://blog.dend.ro/some-eye-candy/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;saloum.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;saloum-med.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;False color composite of Sentinel-1 stack from the end of May 2021 around the Saloum River in Senegal.
VH (cross-polarization) backscatter, VV (co-polarization) backscatter and VV coherence, contrast-stretched and mapped to RGB.
Data courtesy of the European Space Agency.&lt;&#x2F;p&gt;
&lt;p&gt;Click the image for a larger (23 MB) version.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>On self-modifying executables in Rust</title>
        <published>2022-01-23T00:00:00+00:00</published>
        <updated>2022-01-23T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/self-modifying-rust/" type="text/html" />
        <id>https://blog.dend.ro/self-modifying-rust/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;This is a short post prompted by a question on &lt;a href=&quot;https:&#x2F;&#x2F;reddit.com&#x2F;r&#x2F;rust&#x2F;&quot;&gt;&#x2F;r&#x2F;rust&lt;&#x2F;a&gt; from May 2019, asking about a way for a Rust program to modify itself.&lt;&#x2F;p&gt;
&lt;p&gt;Think of how much fun it would be to store a high score list directly inside the a executable.
When you make a copy (on floppy disk, to make things more realistic) and pass it to your friends, your high scores are persisted.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errata&quot;&gt;Errata&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;the variable should probably be marked as &lt;code&gt;#[repr(C)]&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;as &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;saxzs8&#x2F;on_selfmodifying_executables_in_rust&#x2F;htwxint&#x2F;&quot;&gt;pointed out&lt;&#x2F;a&gt; by a reader, &lt;code&gt;unsafe { ptr::read_volatile(&amp;amp;RUN_COUNT) }&lt;&#x2F;code&gt; is a better alternative to &lt;code&gt;static mut&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;you probably shouldn&#x27;t do this except as a party trick.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;diving-right-in&quot;&gt;Diving right in&lt;&#x2F;h2&gt;
&lt;p&gt;As a proof of concept, we&#x27;ll write a program that counts how many times it has been run.
This is hardly the only approach, but probably the simplest way is to store the counter in a separate section of the executable.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;link_section &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;used&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;static mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;RUN_COUNT&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;#[link_section]&lt;&#x2F;code&gt; tells the linker to put the variable in a section called &lt;code&gt;count&lt;&#x2F;code&gt;.
&lt;a href=&quot;https:&#x2F;&#x2F;rust-lang.github.io&#x2F;rfcs&#x2F;2386-used.html&quot;&gt;&lt;code&gt;#[used]&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; means that the variable must be kept by the linker, even if could be optimized away.
Similarly, &lt;code&gt;mut&lt;&#x2F;code&gt; is required because otherwise the compiler will propagate the variable value to the code that reads it.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not sure if the combination above the best way to accomplish this, or if it&#x27;s guaranteed to work.
It was the only working method I found back then, and it still seems to be the case today.&lt;&#x2F;p&gt;
&lt;p&gt;Since the code is so short, I&#x27;ll just paste the rest of it here:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;memmap2::MmapOptions;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;object::{File, Object, ObjectSection};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::env;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::error::Error;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::fs::{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, OpenOptions};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_section&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;file&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;File, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Option&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; section in file.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;sections&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; section.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;            Ok(n) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; n == name =&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; section.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;file_range&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;            _ =&amp;gt; {}
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    None
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn Error&amp;gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; run_count = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;RUN_COUNT &lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Previous run count: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, run_count);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; exe = env::current_exe()?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tmp = exe.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;with_extension&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tmp&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;    fs::copy(&amp;amp;exe, &amp;amp;tmp)?;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; file = OpenOptions::new().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;write&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;tmp)?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; buf = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{ MmapOptions::new().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map_mut&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;file) }?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; file = File::parse(&amp;amp;*buf)?;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if let &lt;&#x2F;span&gt;&lt;span&gt;Some(range) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_section&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;file, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) {
&lt;&#x2F;span&gt;&lt;span&gt;        assert_eq!(range.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; base = range.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        buf[base..(base + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;)].&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;copy_from_slice&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;(run_count + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_ne_bytes&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; perms = fs::metadata(&amp;amp;exe)?.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        fs::set_permissions(&amp;amp;tmp, perms)?;
&lt;&#x2F;span&gt;&lt;span&gt;        fs::rename(&amp;amp;tmp, &amp;amp;exe)?;
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        fs::remove_file(&amp;amp;tmp)?;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    Ok(())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We look up the current executable, and map it into memory using &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;memmap2&#x2F;&quot;&gt;&lt;code&gt;memmap2&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
Then we get a list of sections using the &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;object&#x2F;&quot;&gt;&lt;code&gt;object&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crate, search for one called &lt;code&gt;count&lt;&#x2F;code&gt; — beware of libraries using the same name! — then replace the variable value in the memory-mapped view of the file.&lt;&#x2F;p&gt;
&lt;p&gt;All this happens on a copy of our program.
Self-modifying programs were fine under MS-DOS, but modern operating systems won&#x27;t let it fly.
Renaming or overwriting is fine, since the original file is still unchanged.&lt;&#x2F;p&gt;
&lt;p&gt;You can see a nice diagram showing the ELF (the executable format on my platform) structure &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;corkami&#x2F;pics&#x2F;blob&#x2F;28cb0226093ed57b348723bc473cea0162dad366&#x2F;binary&#x2F;elf101&#x2F;elf101-64.svg&quot;&gt;here&lt;&#x2F;a&gt;.
But we&#x27;re not here to learn about executable formats.
We&#x27;re here to clear out a tiny bit of backlog and see a working example, so does it work?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; cargo run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --release
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Compiling&lt;&#x2F;span&gt;&lt;span&gt; self-modify v0.1.0 (&#x2F;home&#x2F;grayshade&#x2F;Projects&#x2F;self-modify)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Finished&lt;&#x2F;span&gt;&lt;span&gt; release &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;optimized&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; target(s) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; 0.30s
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Running &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target&#x2F;release&#x2F;self-modify&lt;&#x2F;span&gt;&lt;span&gt;`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Previous&lt;&#x2F;span&gt;&lt;span&gt; run count: 0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; target&#x2F;release&#x2F;self-modify
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Previous&lt;&#x2F;span&gt;&lt;span&gt; run count: 1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; target&#x2F;release&#x2F;self-modify
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Previous&lt;&#x2F;span&gt;&lt;span&gt; run count: 2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; target&#x2F;release&#x2F;self-modify
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Previous&lt;&#x2F;span&gt;&lt;span&gt; run count: 3
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It does!&lt;&#x2F;p&gt;
&lt;p&gt;Note that I&#x27;m on Linux.
The &lt;code&gt;object&lt;&#x2F;code&gt; crate should work with MacOS and Windows executables too, but on Windows the &lt;code&gt;fs::rename&lt;&#x2F;code&gt; call will probably fail.
There you can rename the current executable to some temporary name, but I don&#x27;t want to deal with that stuff &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-analyzer&#x2F;rust-analyzer&#x2F;issues&#x2F;6602&quot;&gt;again&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bonus-section&quot;&gt;Bonus &lt;em&gt;section&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I mentioned above that declaring our variable as &lt;code&gt;mut&lt;&#x2F;code&gt; is necessary because the compiler will optimize it otherwise.
How did I figure that out?&lt;&#x2F;p&gt;
&lt;p&gt;First, let&#x27;s simplify the code and give the variable a more noticeable value:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;link_section &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;used&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;static mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;RUN_COUNT&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x55aa55aa&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; run_count = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;RUN_COUNT &lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Previous run count: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, run_count);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; cargo build&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --release
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; objdump&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span&gt; target&#x2F;release&#x2F;self-modify
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0000000000011160 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;_ZN11self_modify4main17hd56d204cd8f62812E&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11160&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 83 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ec &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;sub    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x48&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11164&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       8b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;05 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ee 7e &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;03 00       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x37eee&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;eax        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;49058 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;__TMC_END__&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1116a:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;89 44 24 04             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;eax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1116e:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 04          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11173&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 08          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11178&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;05 49 51 03 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x35149&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# 462c8 &amp;lt;_etext&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x423&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1117f:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 10          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11184&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;05 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;e5 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;57 03 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x357e5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;46970 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;_DYNAMIC&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x280&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1118b:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 18          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x18&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11190&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 20 02 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x20&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11197&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00 00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11199&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 28 00 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x28&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111a0:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00 00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111a2:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 08          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111a7:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 38          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x38&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111ac:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 40 01 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x40&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111b3:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00 00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111b5:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d 7c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;24 18          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x18&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111ba:       ff &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;15 48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;4f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;03 00       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;call   &lt;&#x2F;span&gt;&lt;span&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x34f48&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)        # &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;46108 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;_etext&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x263&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111c0:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 83 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;add    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x48&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111c4:       c3                      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ret
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;        ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ookay, assembly is hard to read.
What happens without the &lt;code&gt;mut&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0000000000011160 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;_ZN11self_modify4main17hd56d204cd8f62812E&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11160&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 83 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ec &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;sub    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x48&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11164&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 04 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;aa &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;55 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;aa    movl   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x55aa55aa&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1116b:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;55
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1116c:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 04          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11171&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 08          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11176&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;05 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;4b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;51 03 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x3514b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# 462c8 &amp;lt;_etext&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x423&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1117d:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 10          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11182&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;05 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;e7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;57 03 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x357e7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;46970 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;_DYNAMIC&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x280&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11189&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 18          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x18&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1118e:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 20 02 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x20&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11195&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00 00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11197&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 28 00 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x28&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   1119e:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00 00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111a0:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 08          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111a5:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 44 24 38          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x38&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111aa:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 24 40 01 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x40&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111b1:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00 00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111b3:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8d 7c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;24 18          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lea    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x18&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111b8:       ff &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;15 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;4a 4f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;03 00       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;call   &lt;&#x2F;span&gt;&lt;span&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x34f4a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)        # &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;46108 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;lt;_etext&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x263&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111be:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 83 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;add    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x48&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsp
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   111c2:       c3                      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ret
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;        ...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Did you spot the &lt;code&gt;movl   $0x55aa55aa,0x4(%rsp)&lt;&#x2F;code&gt; on the second line?
That&#x27;s our value, inlined in the compiled code.&lt;&#x2F;p&gt;
&lt;p&gt;To be honest, we&#x27;re getting a lot of extra code in there.
Instead, it&#x27;s better to get rid of the &lt;code&gt;println!&lt;&#x2F;code&gt;, simplify the code as much as possible and paste it on godbolt.org.
Click &lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;z&#x2F;d5rbj7fMG&quot;&gt;here&lt;&#x2F;a&gt; to see how that looks.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Mapping my walks with OSRM and Rust</title>
        <published>2022-01-15T00:00:00+00:00</published>
        <updated>2022-01-15T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/mapping-my-walks-osrm-rust/" type="text/html" />
        <id>https://blog.dend.ro/mapping-my-walks-osrm-rust/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;&lt;a href=&quot;&#x2F;map-matching-osrm&#x2F;&quot;&gt;Last week&lt;&#x2F;a&gt;, we looked at the data from my smartwatch app and how to snap it to the OpenStreetMap roads.
If you haven&#x27;t already, consider reading that post before moving on.
This time, we&#x27;ll be writing some code in the &lt;a href=&quot;https:&#x2F;&#x2F;rust-lang.org&#x2F;&quot;&gt;Rust&lt;&#x2F;a&gt; programming language.
Keep in mind that this isn&#x27;t exactly production-grade code, but rather something you would normally write in Python in one afternoon.
I&#x27;ll link to the crates I&#x27;m using for the benefit of readers less familiar with the Rust ecosystem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;importing-the-data&quot;&gt;Importing the data&lt;&#x2F;h2&gt;
&lt;p&gt;If you recall from last time, our data points include a timestamp, the latitude and longitude, and an accuracy radius.
We can define our point type as follows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;Point {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;time&lt;&#x2F;span&gt;&lt;span&gt;: OffsetDateTime,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;geom&lt;&#x2F;span&gt;&lt;span&gt;: geo_types::Point&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;radius&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;OffsetDateTime&lt;&#x2F;code&gt; and &lt;code&gt;Point&amp;lt;T&amp;gt;&lt;&#x2F;code&gt; types are from the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;time&quot;&gt;&lt;code&gt;time&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;geo-types&quot;&gt;&lt;code&gt;geo-types&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crates, respectively.
We&#x27;ll also need &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;zip&quot;&gt;&lt;code&gt;zip&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;csv&quot;&gt;&lt;code&gt;csv&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; in order to parse the exported file.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see what reading the file looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;read_archive&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;Path) -&amp;gt; Result&amp;lt;Vec&amp;lt;Point&amp;gt;, Error&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; file = File::open(path)?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; archive = ZipArchive::new(file)?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; latitudes = Vec::new();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; record = StringRecord::new();
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; reader = archive.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;by_name&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;raw_location_latitude.csv&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)?;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; reader = Reader::from_reader(reader);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt; reader.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;read_record&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; record)? {
&lt;&#x2F;span&gt;&lt;span&gt;            latitudes.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_array_first_value&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;record[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;])?);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; n = latitudes.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; times = Vec::with_capacity(n);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; longitudes = Vec::with_capacity(n);
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; reader = archive.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;by_name&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;raw_location_longitude.csv&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)?;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; reader = Reader::from_reader(reader);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt; reader.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;read_record&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; record)? {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; time = OffsetDateTime::parse(&amp;amp;record[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;], &amp;amp;well_known::Rfc3339)?;
&lt;&#x2F;span&gt;&lt;span&gt;            times.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(time);
&lt;&#x2F;span&gt;&lt;span&gt;            longitudes.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_array_first_value&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;record[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;])?);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    assert_eq!(longitudes.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;(), n);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; radiuses = Vec::with_capacity(n);
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; reader = archive.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;by_name&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;raw_location_horizontal-radius.csv&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)?;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; reader = Reader::from_reader(reader);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt; reader.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;read_record&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; record)? {
&lt;&#x2F;span&gt;&lt;span&gt;            radiuses.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_array_first_value&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;record[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;])?);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    assert_eq!(radiuses.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;(), n);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; points = izip!(times, latitudes, longitudes, radiuses)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;time&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lat&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lon&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;radius&lt;&#x2F;span&gt;&lt;span&gt;)| {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; geom = geo_types::Point::new(lon, lat);
&lt;&#x2F;span&gt;&lt;span&gt;            Point { time, geom, radius }
&lt;&#x2F;span&gt;&lt;span&gt;        })
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    Ok(points)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_array_first_value&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Result&amp;lt;T, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;T::&lt;&#x2F;span&gt;&lt;span&gt;Err&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;where
&lt;&#x2F;span&gt;&lt;span&gt;    T: FromStr,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;T::&lt;&#x2F;span&gt;&lt;span&gt;Err: std::fmt::Debug,
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; p = s.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;find&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;| c == &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; || c == &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;expected array&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;    s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;..p].&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;parse&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code is somewhat unwieldly because it needs to read three different CSVs from the archive.
The ZIP reader needs to seek into the archive, so we can&#x27;t read all of them at once.
If you&#x27;re familiar with Rust, that constraint is expressed in the type system by &lt;code&gt;Reader&lt;&#x2F;code&gt; having a mutable reference to &lt;code&gt;ZipArchive&lt;&#x2F;code&gt;.
Instead, we open the files one at a time and scan through each.&lt;&#x2F;p&gt;
&lt;p&gt;We need to remember to read the timestamps and there is one extra complication.
The values are written as JSON-like arrays (e.g. &lt;code&gt;[44.XXX,657.XXX]&lt;&#x2F;code&gt;), but only the first one makes sense.
Instead of reaching for a full-blown JSON parser, we simply look for a bracket or comma and parse the number we find there.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;izip&lt;&#x2F;code&gt; macro comes from &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;itertools&quot;&gt;&lt;code&gt;itertools&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and lets us iterate over the multiple collections at once.&lt;&#x2F;p&gt;
&lt;p&gt;Note that the implementation keeps all the points in memory (twice, even).
Normally I would dump the points to disk and read them back, but it would make the code harder to follow in a blog post.
In any case, this doesn&#x27;t dominate our memory usage.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;calling-into-osrm&quot;&gt;Calling into OSRM&lt;&#x2F;h2&gt;
&lt;p&gt;As mentioned last time, OSRM has an HTTP server, so we&#x27;ll use &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;reqwest&quot;&gt;&lt;code&gt;reqwest&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to call into it and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;serde&quot;&gt;&lt;code&gt;serde&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to deserialize the JSON responses.&lt;&#x2F;p&gt;
&lt;p&gt;First of all, we define some structs that roughly match the OSRM response:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize, Debug)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MatchResponse {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;matchings&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Matching&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Deserialize, Debug)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;Matching {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;geometry&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then our client:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;OsrmClient {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client&lt;&#x2F;span&gt;&lt;span&gt;: Client,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base_url&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;OsrmClient {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base_url&lt;&#x2F;span&gt;&lt;span&gt;: String) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; client = Client::new();
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{ client, base_url }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;match_map&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;profile&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;points&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;[Point],
&lt;&#x2F;span&gt;&lt;span&gt;    ) -&amp;gt; Result&amp;lt;MultiLineString&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;, Error&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; q = format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;match&#x2F;v1&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{profile}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;polyline6(&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.base_url);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; timestamps = String::new();
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; radiuses = String::from(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;amp;radiuses=&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; coordinates = LineString::from_iter(points.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| p.geom));
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; point in points {
&lt;&#x2F;span&gt;&lt;span&gt;            write!(timestamps, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, point.time.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unix_timestamp&lt;&#x2F;span&gt;&lt;span&gt;())?;
&lt;&#x2F;span&gt;&lt;span&gt;            write!(radiuses, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, point.radius)?;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        timestamps.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;pop&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        radiuses.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;pop&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; coordinates =
&lt;&#x2F;span&gt;&lt;span&gt;            polyline::encode_coordinates(coordinates, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map_err&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;| anyhow!(e))?;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; pe = percent_encoding::percent_encode(
&lt;&#x2F;span&gt;&lt;span&gt;            coordinates.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;as_bytes&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;            percent_encoding::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;NON_ALPHANUMERIC&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        );
&lt;&#x2F;span&gt;&lt;span&gt;        write!(
&lt;&#x2F;span&gt;&lt;span&gt;            q,
&lt;&#x2F;span&gt;&lt;span&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;)?geometries=polyline6&amp;amp;tidy=true&amp;amp;steps=false&amp;amp;timestamps=&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;            pe
&lt;&#x2F;span&gt;&lt;span&gt;        )?;
&lt;&#x2F;span&gt;&lt;span&gt;        q.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push_str&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;timestamps);
&lt;&#x2F;span&gt;&lt;span&gt;        q.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push_str&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;radiuses);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; res = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.client.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;q).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;()?.json::&amp;lt;MatchResponse&amp;gt;()?;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; mls = MultiLineString(
&lt;&#x2F;span&gt;&lt;span&gt;            res.matchings
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;| polyline::decode_polyline(&amp;amp;m.geometry, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;                .collect::&amp;lt;Result&amp;lt;Vec&amp;lt;_&amp;gt;, _&amp;gt;&amp;gt;()
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map_err&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;| anyhow!(e))?,
&lt;&#x2F;span&gt;&lt;span&gt;        );
&lt;&#x2F;span&gt;&lt;span&gt;        Ok(mls)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Again, this is quick and dirty code.
We use the &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;maps&#x2F;documentation&#x2F;utilities&#x2F;polylinealgorithm&quot;&gt;&lt;code&gt;polyline&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; encoding of the coordinates and the corresponding &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;polyline&quot;&gt;crate&lt;&#x2F;a&gt; for it.
Because &lt;code&gt;polyline&lt;&#x2F;code&gt; uses an encoding that contains non-alphanumeric characters, we need to encode them using &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;polyline&quot;&gt;&lt;code&gt;percent-encoding&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
This crate doesn&#x27;t have a standard error type (it uses &lt;code&gt;String&lt;&#x2F;code&gt;s), so we adapt them using &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;anyhow&quot;&gt;&lt;code&gt;anyhow&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which is also appears in the rest of the code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;saving-a-flatgeobuf&quot;&gt;Saving a FlatGeobuf&lt;&#x2F;h2&gt;
&lt;p&gt;This isn&#x27;t really required for our purposes, but I want to keep a copy of the points in a format better suited for using later.
I&#x27;d normally use &lt;a href=&quot;https:&#x2F;&#x2F;geopackage.org&#x2F;&quot;&gt;GeoPackage&lt;&#x2F;a&gt;, but I want to give &lt;a href=&quot;https:&#x2F;&#x2F;flatgeobuf.org&#x2F;&quot;&gt;FlatGeobuf&lt;&#x2F;a&gt; a try.
This is a newer format, with a simpler structure and which should be simpler to write, since a &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;flatgeobuf&quot;&gt;pure-Rust&lt;&#x2F;a&gt; implementation is available.
Fortunately, &lt;a href=&quot;https:&#x2F;&#x2F;gdal.org&#x2F;&quot;&gt;GDAL&lt;&#x2F;a&gt; also has a reader, so it should be compatible with every application I care about at the moment.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;flatgeobuf&lt;&#x2F;code&gt; has a slightly strange API, but it&#x27;s not too bad and I&#x27;ve seen worse.
It integrates closely with &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;geozero&quot;&gt;&lt;code&gt;geozero&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which is a visitor-based API for zero-copy processing of geospatial data.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;export_fgb&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;file&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;Path, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;points&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;[Point]) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; fgb = FgbWriter::create(name, GeometryType::Point, |_, _| {})?;
&lt;&#x2F;span&gt;&lt;span&gt;    fgb.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;set_crs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4326&lt;&#x2F;span&gt;&lt;span&gt;, |&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_fbb&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_crs&lt;&#x2F;span&gt;&lt;span&gt;| {});
&lt;&#x2F;span&gt;&lt;span&gt;    fgb.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;add_column&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;time&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ColumnType::DateTime, |_, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;col&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;        col.nullable = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    });
&lt;&#x2F;span&gt;&lt;span&gt;    fgb.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;add_column&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;radius&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ColumnType::Float, |_, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;col&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;        col.nullable = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    });
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; point in points {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; time = point.time.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;format&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;well_known::Rfc3339)?;
&lt;&#x2F;span&gt;&lt;span&gt;        fgb.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;add_feature_geom&lt;&#x2F;span&gt;&lt;span&gt;(Geometry::Point(point.geom), |&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;feat&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;            feat.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;property&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;time&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;ColumnValue::DateTime(&amp;amp;time))
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;            feat.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;property&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;radius&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;ColumnValue::Float(point.radius))
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        })?;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; out_file = File::create(file)?;
&lt;&#x2F;span&gt;&lt;span&gt;    fgb.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;write&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;BufWriter::new(out_file))?;
&lt;&#x2F;span&gt;&lt;span&gt;    Ok(())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We create a writer, configure the &lt;a href=&quot;https:&#x2F;&#x2F;www.earthdatascience.org&#x2F;courses&#x2F;earth-analytics&#x2F;spatial-data-r&#x2F;intro-to-coordinate-reference-systems&#x2F;&quot;&gt;CRS&lt;&#x2F;a&gt; and define the two columns.
Afterwards, we can iterate over our points, create features from them, and set the column values.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reprojecting-the-data&quot;&gt;Reprojecting the data&lt;&#x2F;h2&gt;
&lt;p&gt;I want to display the resulting tracks on a map, but the (latitude, longitude) coordinates aren&#x27;t ideal, since they introduce quite a bit of distorsion:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-4326.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-4326.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Instead, we will reproject our points to the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Web_Mercator_projection&quot;&gt;Web Mercator&lt;&#x2F;a&gt; (or, more formally, EPSG:3857) projection.
While it&#x27;s not really accurate, it&#x27;s good enough at this latitude for my purposes.
Web Mercator has been popularized by Google Maps, and the look of it should be familiar to anyone who&#x27;s ever seen an interactive map on the Web.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-3857.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-3857.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For this, I&#x27;d normally use &lt;code&gt;GDAL&lt;&#x2F;code&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;proj.org&#x2F;&quot;&gt;&lt;code&gt;PROJ&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, but GDAL&#x27;s approach to threading isn&#x27;t the most fortunate.
We could probably use the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;proj&quot;&gt;&lt;code&gt;proj&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; bindings, but even those bring quite a bit of complexity.&lt;&#x2F;p&gt;
&lt;p&gt;The conversion to Web Mercator should be pretty easy.
You can see a pair of formulas in the link above, but they use different bounds, and it&#x27;s not obvious how to do it correctly.
Stack Overflow produces a fair bit of &lt;a href=&quot;https:&#x2F;&#x2F;gis.stackexchange.com&#x2F;questions&#x2F;208966&#x2F;converting-lat-long-to-epsg3857-coordinates&quot;&gt;confusion&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;gis.stackexchange.com&#x2F;questions&#x2F;142866&#x2F;converting-latitude-longitude-epsg4326-into-epsg3857&#x2F;142871#142871&quot;&gt;two&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;37523872&#x2F;converting-coordinates-from-epsg-3857-to-4326&#x2F;40403522#comment81831709_40403522&quot;&gt;answers&lt;&#x2F;a&gt;, but neither of them agrees with &lt;code&gt;PROJ&lt;&#x2F;code&gt;.
After a bit of hit-and miss, I realized that the three implementations are using different values for the Earth radius.
I believe the correct value to use in this case is &lt;code&gt;6_378_137 m&lt;&#x2F;code&gt;.
My final implementation gives the same result (up to the precision limit) as &lt;code&gt;PROJ&lt;&#x2F;code&gt; for a couple of points I&#x27;ve tried, so I hope it&#x27;s correct.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;epsg_4326_to_3857&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;WGS84_EQUATORIAL_RADIUS&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64 &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6_378_137.0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;MAX_LATITUDE&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64 &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;85.06&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; x = x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_radians&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; y = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; y &amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;MAX_LATITUDE &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        std::f64::consts::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;PI
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else if&lt;&#x2F;span&gt;&lt;span&gt; y &amp;lt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;MAX_LATITUDE &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        -std::f64::consts::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;PI
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; y = y.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_radians&lt;&#x2F;span&gt;&lt;span&gt;() &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2.0 &lt;&#x2F;span&gt;&lt;span&gt;+ std::f64::consts::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;FRAC_PI_4&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        y.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;tan&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;ln&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;    (x * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;WGS84_EQUATORIAL_RADIUS&lt;&#x2F;span&gt;&lt;span&gt;, y * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;WGS84_EQUATORIAL_RADIUS&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is also a helper that reprojects an entire track:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;reproject_route&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mls&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;MultiLineString&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    mls.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;iter_mut&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;for_each&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;        ls.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;iter_mut&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;for_each&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(x, y) = geo::epsg_4326_to_3857(p.x, p.y);
&lt;&#x2F;span&gt;&lt;span&gt;            p.x = x;
&lt;&#x2F;span&gt;&lt;span&gt;            p.y = y;
&lt;&#x2F;span&gt;&lt;span&gt;        });
&lt;&#x2F;span&gt;&lt;span&gt;    });
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;rasterization&quot;&gt;Rasterization&lt;&#x2F;h2&gt;
&lt;p&gt;Next, I want to display the tracks returned by OSRM as images.
Converting from vector data to an image is called rasterization.
I had a couple of options here (it&#x27;s less flexible, but GDAL can do it), but I decided to a recently-published crate called &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;rasterize&quot;&gt;&lt;code&gt;rasterize&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;First of all, &lt;code&gt;rasterize&lt;&#x2F;code&gt; represents paths as a list of segments, not points, so we need a conversion function for that:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;mls_to_path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mls&lt;&#x2F;span&gt;&lt;span&gt;: MultiLineString&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) -&amp;gt; rasterize::Path {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; subpaths = mls
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;filter_map&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;            SubPath::new(
&lt;&#x2F;span&gt;&lt;span&gt;                ls.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;                    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| p.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;x_y&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;                    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;tuple_windows&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;                    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p2&lt;&#x2F;span&gt;&lt;span&gt;)| Segment::Line(Line::new(p1, p2)))
&lt;&#x2F;span&gt;&lt;span&gt;                    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            )
&lt;&#x2F;span&gt;&lt;span&gt;        })
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    rasterize::Path::new(subpaths)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also need to pick a couple of things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the view bounding box in map coordinates&lt;&#x2F;li&gt;
&lt;li&gt;the stroke style and color&lt;&#x2F;li&gt;
&lt;li&gt;a scale factor to apply, so that our output image size doesn&#x27;t depend on the EPSG:3857 coordinates&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;RasterizeOptions {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rasterizer&lt;&#x2F;span&gt;&lt;span&gt;: ActiveEdgeRasterizer,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bbox&lt;&#x2F;span&gt;&lt;span&gt;: BBox,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;transform&lt;&#x2F;span&gt;&lt;span&gt;: Transform,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;stroke_color&lt;&#x2F;span&gt;&lt;span&gt;: Arc&amp;lt;LinColor&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;stroke_style&lt;&#x2F;span&gt;&lt;span&gt;: StrokeStyle,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we can write a bit of code to rasterize a track and save the result to a file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rasterize_route&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;options&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;RasterizeOptions,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt;: File,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mls&lt;&#x2F;span&gt;&lt;span&gt;: MultiLineString&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;reproject_mls&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; mls);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; scene = Scene::stroke(
&lt;&#x2F;span&gt;&lt;span&gt;        Arc::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;mls_to_path&lt;&#x2F;span&gt;&lt;span&gt;(mls)),
&lt;&#x2F;span&gt;&lt;span&gt;        Arc::clone(&amp;amp;options.stroke_color) as Arc&amp;lt;dyn Paint&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        options.stroke_style,
&lt;&#x2F;span&gt;&lt;span&gt;    );
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; layer = scene.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;render&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;amp;options.rasterizer,
&lt;&#x2F;span&gt;&lt;span&gt;        options.transform,
&lt;&#x2F;span&gt;&lt;span&gt;        Some(options.bbox),
&lt;&#x2F;span&gt;&lt;span&gt;        None,
&lt;&#x2F;span&gt;&lt;span&gt;    );
&lt;&#x2F;span&gt;&lt;span&gt;    layer.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;write_png&lt;&#x2F;span&gt;&lt;span&gt;(output)?;
&lt;&#x2F;span&gt;&lt;span&gt;    Ok(())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The result looks like this (if it looks weird for you, it&#x27;s because it has a transparent background):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-track-rasterized.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-track-rasterized.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;accumulating-the-images&quot;&gt;Accumulating the images&lt;&#x2F;h2&gt;
&lt;p&gt;At the end, I want to overlay all the tracks in the same image.
We load the files from the previous step using &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;png&quot;&gt;&lt;code&gt;png&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, then accumulate them into a white layer:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;accumulate_images&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bbox&lt;&#x2F;span&gt;&lt;span&gt;: BBox, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;images&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;[String]) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; layer = Layer::new(bbox, Some(LinColor::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;)));
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; buf = vec![&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; layer.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;width&lt;&#x2F;span&gt;&lt;span&gt;() * layer.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;height&lt;&#x2F;span&gt;&lt;span&gt;() * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; img in images {
&lt;&#x2F;span&gt;&lt;span&gt;        {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; decoder = Decoder::new(File::open(&amp;amp;img)?);
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; reader = decoder.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;read_info&lt;&#x2F;span&gt;&lt;span&gt;()?;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; info = reader.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;next_frame&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; buf)?;
&lt;&#x2F;span&gt;&lt;span&gt;            layer
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;iter_mut&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;zip&lt;&#x2F;span&gt;&lt;span&gt;((&amp;amp;buf[..info.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;buffer_size&lt;&#x2F;span&gt;&lt;span&gt;()]).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;chunks&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;for_each&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pa&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;)| {
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; p = &amp;amp;p[..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;                    *pa = pa.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;blend_over&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;ColorU8::new(p[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;], p[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;], p[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;], p[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;                });
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; file = File::create(img)?;
&lt;&#x2F;span&gt;&lt;span&gt;        layer.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;write_png&lt;&#x2F;span&gt;&lt;span&gt;(file)?;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    Ok(())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The bleding operator (&lt;code&gt;blend_over&lt;&#x2F;code&gt;, from &lt;code&gt;rasterize&lt;&#x2F;code&gt;) keeps the existing pixels and only overwrites the transparent ones.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;putting-it-together&quot;&gt;Putting it together&lt;&#x2F;h2&gt;
&lt;p&gt;Skipping over argument parsing and other initializations, we can finally read the archive and save the FlatGeobuf file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; points = import::read_archive(archive)?;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;export_fgb&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;location&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;archive.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;with_extension&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;fgb&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;), &amp;amp;points)?;
&lt;&#x2F;span&gt;&lt;span&gt;points.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;sort_unstable_by_key&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| p.time);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We then filter out the bad points and group them by date:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; points = points
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;filter&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| p.radius &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;50.0&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;group_by&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;| p.time.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;)| (d, p.collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;()))
&lt;&#x2F;span&gt;&lt;span&gt;    .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Run them through OSRM:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; osrm_client = osrm::OsrmClient::new(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;http:&#x2F;&#x2F;127.0.0.1:5000&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; routes = points
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_par_iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;filter_map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;points&lt;&#x2F;span&gt;&lt;span&gt;)| {
&lt;&#x2F;span&gt;&lt;span&gt;        osrm_client
&lt;&#x2F;span&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;match_map&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;foot&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;points)
&lt;&#x2F;span&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;| (date, m))
&lt;&#x2F;span&gt;&lt;span&gt;    })
&lt;&#x2F;span&gt;&lt;span&gt;    .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;m using &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;rayon&quot;&gt;&lt;code&gt;rayon&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; here in order to do multiple requests to OSRM at once.
It would be very inconsiderate to do this against another server, but I&#x27;m running my own instance in Docker.&lt;&#x2F;p&gt;
&lt;p&gt;Rasterize the routes for every date into a corresponding image:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; images = routes
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_par_iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mls&lt;&#x2F;span&gt;&lt;span&gt;)| {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; raster_name = format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{date}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; file = File::create(&amp;amp;raster_name)?;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;rasterize_route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;rasterize_options, file, mls)?;
&lt;&#x2F;span&gt;&lt;span&gt;        Ok(raster_name)
&lt;&#x2F;span&gt;&lt;span&gt;    })
&lt;&#x2F;span&gt;&lt;span&gt;    .collect::&amp;lt;Result&amp;lt;Vec&amp;lt;_&amp;gt;, Error&amp;gt;&amp;gt;()?;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Again, this uses &lt;code&gt;rayon&lt;&#x2F;code&gt; for parallelization.
Since I mentioned the memory usage before, there is one subtle issue here.
Every running thread will rasterize some tracks into a layer, so the memory usage will depend on the available concurrency.
If some computation takes, say, 1 GB RAM, that&#x27;s not too bad until you start 32 of them at once.
So remember to pair CPUs with many cores with an appropriate amount of RAM, even if it sits mostly unused.&lt;&#x2F;p&gt;
&lt;p&gt;Then we finally run the accumulation step:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;images.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;sort_unstable&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;accumulate_images&lt;&#x2F;span&gt;&lt;span&gt;(bbox, &amp;amp;images)?;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And just one thing left to do:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; ffmpeg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -framerate&lt;&#x2F;span&gt;&lt;span&gt; 15&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -pattern_type&lt;&#x2F;span&gt;&lt;span&gt; glob&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -i &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;*.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -c&lt;&#x2F;span&gt;&lt;span&gt;:v libwebp_anim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -lossless&lt;&#x2F;span&gt;&lt;span&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -quality&lt;&#x2F;span&gt;&lt;span&gt; 100 gps_tracks.webp
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see the result below:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;performance&quot;&gt;Performance&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve only done rough measurements, but the whole process (except running &lt;code&gt;ffmpeg&lt;&#x2F;code&gt; at the end) takes 4.5 seconds on my system.
Replacing &lt;code&gt;into_par_iter&lt;&#x2F;code&gt; with &lt;code&gt;into_iter&lt;&#x2F;code&gt; brings that up to 10.5 seconds.&lt;&#x2F;p&gt;
&lt;p&gt;Out of the 4.5 s, calling into OSRM takes 1.3 s (6.5 s serially).
The rest of the time is spent in rasterization (which is quite fast), and PNG compression and decompression.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-words&quot;&gt;Closing words&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;ve followed through, thank you for reading.
You can find the code &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lnicola&#x2F;walker&quot;&gt;on GitHub&lt;&#x2F;a&gt;.
Props also to the &lt;a href=&quot;https:&#x2F;&#x2F;georust.org&#x2F;&quot;&gt;GeoRust&lt;&#x2F;a&gt; community, which owns all the geospatial-related crates I&#x27;ve used here.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Map data from &lt;a href=&quot;https:&#x2F;&#x2F;openstreetmap.org&#x2F;copyright&quot;&gt;OpenStreetMap&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Announcing the sd-notify crate</title>
        <published>2022-01-12T00:00:00+00:00</published>
        <updated>2022-01-12T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/introducing-sd-notify/" type="text/html" />
        <id>https://blog.dend.ro/introducing-sd-notify/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;This is a quick post announcing the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;sd-notify&quot;&gt;&lt;code&gt;sd-notify&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crate.
&lt;code&gt;sd-notify&lt;&#x2F;code&gt; is a Rust library for interacting with &lt;code&gt;systemd&lt;&#x2F;code&gt; or a compatible service manager.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re not running Linux or you don&#x27;t like &lt;code&gt;systemd&lt;&#x2F;code&gt;, this crate is not for you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;systemd-in-3-minutes&quot;&gt;systemd in 3 minutes&lt;&#x2F;h2&gt;
&lt;p&gt;Assuming you are running &lt;code&gt;systemd&lt;&#x2F;code&gt;, at some point you might find yourself with a program you want to automatically run on start-up.
Historically, this meant doing an intricate dance which includes calling &lt;code&gt;fork()&lt;&#x2F;code&gt; twice and writing your PID to a file, but fortunately, with &lt;code&gt;systemd&lt;&#x2F;code&gt; this is no longer required and is actually discouraged.&lt;&#x2F;p&gt;
&lt;p&gt;You can take your plain console application and make a &lt;code&gt;systemd&lt;&#x2F;code&gt; unit for it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ini &quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span&gt;=Monitors room temperature
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;User&lt;&#x2F;span&gt;&lt;span&gt;=stats
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span&gt;=&#x2F;usr&#x2F;local&#x2F;bin&#x2F;monitor-temperature
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Restart&lt;&#x2F;span&gt;&lt;span&gt;=on-failure
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RestartSec&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span&gt;=default.target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You then drop that file under &lt;code&gt;&#x2F;etc&#x2F;systemd&#x2F;system&#x2F;monitor-temperature.service&lt;&#x2F;code&gt;, run &lt;code&gt;systemctl daemon-reload&lt;&#x2F;code&gt;, &lt;code&gt;systemctl enable --now monitor-temperature&lt;&#x2F;code&gt; and you&#x27;re done.&lt;&#x2F;p&gt;
&lt;p&gt;For the effort, you get logs (&lt;code&gt;journalctl -efu monitor-temperature&lt;&#x2F;code&gt;), precise child process tracking (using control groups), CPU, memory and I&#x2F;O accounting, automatic restarts, and a way to manage your service across all the popular Linux distros.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;systemd-start-up-types&quot;&gt;systemd start-up types&lt;&#x2F;h2&gt;
&lt;p&gt;If your daemon has a long start-up sequence, &lt;code&gt;systemd&lt;&#x2F;code&gt; can tell you whether it is ready or not.
In order to do that, you can set the &lt;code&gt;Type&lt;&#x2F;code&gt; clause.&lt;&#x2F;p&gt;
&lt;p&gt;The simplest, and also the default, option is called &lt;code&gt;simple&lt;&#x2F;code&gt;.
It means that the daemon is marked as ready right after it starts.
Another useful option is &lt;code&gt;forking&lt;&#x2F;code&gt;, which means that the service does the classic double-fork dance.
You can read more about these two (any many others) in your &lt;a href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;systemd.service.html&quot;&gt;&lt;code&gt;systemd.service&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; documentation page.&lt;&#x2F;p&gt;
&lt;p&gt;What the &lt;code&gt;sd-notify&lt;&#x2F;code&gt; crate helps with is the &lt;code&gt;notify&lt;&#x2F;code&gt; start-up type.
This lets you do whatever initialization you want, then notify &lt;code&gt;systemd&lt;&#x2F;code&gt; that you are ready by sending a over a Unix socket.
Services can also say that they are reloading their settings, stopping, or even set a status message.
The protocol is described in detail &lt;a href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;sd_notify.html&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-sd-notify&quot;&gt;Using sd-notify&lt;&#x2F;h2&gt;
&lt;p&gt;The basic usage is quite simple.
You do your initialization steps, then call:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;_ = sd_notify::notify(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;, &amp;amp;[NotifyState::Ready]);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s all and now your daemon only shows as &quot;running&quot; when it finished starting up.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; systemctl status monitor-temperature
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Active:&lt;&#x2F;span&gt;&lt;span&gt; activating (start) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;since&lt;&#x2F;span&gt;&lt;span&gt; Wed 2022-01-12 20:36:02 EET; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;9s&lt;&#x2F;span&gt;&lt;span&gt; ago
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; systemctl status monitor-temperature
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Active:&lt;&#x2F;span&gt;&lt;span&gt; active (running) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;since&lt;&#x2F;span&gt;&lt;span&gt; Wed 2022-01-12 20:36:12 EET; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2s&lt;&#x2F;span&gt;&lt;span&gt; ago
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also include a status message:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;_ = sd_notify::notify(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;[
&lt;&#x2F;span&gt;&lt;span&gt;        NotifyState::Ready,
&lt;&#x2F;span&gt;&lt;span&gt;        NotifyState::Status(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Monitoring room temperature&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;),
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; systemctl status monitor-temperature
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Active:&lt;&#x2F;span&gt;&lt;span&gt; active (running) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;since&lt;&#x2F;span&gt;&lt;span&gt; Wed 2022-01-12 20:41:46 EET; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;782ms&lt;&#x2F;span&gt;&lt;span&gt; ago
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Status: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Monitoring room temperature&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[snip]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There&#x27;s also one advanced feature: you can retrieve file descriptors passed by the service manager, for socket-activated daemons.
You can read more on it &lt;a href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;sd_listen_fds.html&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;sd-notify&lt;&#x2F;code&gt; is written in pure Rust, has no dependencies and is available under a permissive license (MIT or Apache-2.0).
My intention is that it stays lightweight, but I&#x27;m not necessarily opposed to adding more features.&lt;&#x2F;p&gt;
&lt;p&gt;If you want more functionality today, try the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;libsystemd&quot;&gt;&lt;code&gt;libsystemd&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;systemd&quot;&gt;&lt;code&gt;rust-systemd&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crates.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Map matching using OSRM</title>
        <published>2022-01-08T00:00:00+00:00</published>
        <updated>2022-01-08T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/map-matching-osrm/" type="text/html" />
        <id>https://blog.dend.ro/map-matching-osrm/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;Hoping to be more active during the pandemic, I bought a Withings smart watch, and at some point got the idea of playing with the GPS tracks recorded when using it.
The manufacturer allows you to download your data by logging in to their web dashboard, going to settings, and choosing &quot;Download my data&quot;.
In 10 minutes or so, you will get a ZIP archive in your inbox.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-withings-data&quot;&gt;The Withings data&lt;&#x2F;h2&gt;
&lt;p&gt;I like to take long walks and I&#x27;m currently living in a small suburb near a larger city, so most of my walks were around the town.
Let&#x27;s look first at the format of the data.
There are 38 CSVs and a small &lt;code&gt;README.txt&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt; 303790 Jan  8 12:01 activities.csv
&lt;&#x2F;span&gt;&lt;span&gt;   8253 Jan  8 11:53 aggregates_calories_earned.csv
&lt;&#x2F;span&gt;&lt;span&gt;   8980 Jan  8 11:53 aggregates_calories_passive.csv
&lt;&#x2F;span&gt;&lt;span&gt;   8591 Jan  8 11:53 aggregates_distance.csv
&lt;&#x2F;span&gt;&lt;span&gt;   7029 Jan  8 11:53 aggregates_elevation.csv
&lt;&#x2F;span&gt;&lt;span&gt;    447 Jan  8 11:53 aggregates_manual_spo2.csv
&lt;&#x2F;span&gt;&lt;span&gt;   7274 Jan  8 11:53 aggregates_steps.csv
&lt;&#x2F;span&gt;&lt;span&gt;   2091 Jan  8 11:53 bp.csv
&lt;&#x2F;span&gt;&lt;span&gt;     55 Jan  8 11:53 height.csv
&lt;&#x2F;span&gt;&lt;span&gt;   1576 Jan  8 11:53 manual_spo2.csv
&lt;&#x2F;span&gt;&lt;span&gt;     30 Jan  8 12:01 note.csv
&lt;&#x2F;span&gt;&lt;span&gt; 821784 Jan  8 11:59 raw_bed_calories-earned.csv
&lt;&#x2F;span&gt;&lt;span&gt;2414611 Jan  8 11:59 raw_bed_hr.csv
&lt;&#x2F;span&gt;&lt;span&gt;     21 Jan  8 11:59 raw_bed_maximum_movement.csv
&lt;&#x2F;span&gt;&lt;span&gt;     21 Jan  8 11:59 raw_bed_movement_pim.csv
&lt;&#x2F;span&gt;&lt;span&gt;     21 Jan  8 11:59 raw_bed_respiratory-rate.csv
&lt;&#x2F;span&gt;&lt;span&gt;  59615 Jan  8 11:59 raw_bed_sleep-state.csv
&lt;&#x2F;span&gt;&lt;span&gt;     21 Jan  8 11:59 raw_bed_snoring.csv
&lt;&#x2F;span&gt;&lt;span&gt;7775984 Jan  8 11:53 raw_hr_hr.csv
&lt;&#x2F;span&gt;&lt;span&gt;2258790 Jan  8 11:56 raw_location_altitude.csv
&lt;&#x2F;span&gt;&lt;span&gt;     21 Jan  8 11:56 raw_location_direction.csv
&lt;&#x2F;span&gt;&lt;span&gt;2151043 Jan  8 11:56 raw_location_gps-speed.csv
&lt;&#x2F;span&gt;&lt;span&gt;2196946 Jan  8 11:56 raw_location_horizontal-radius.csv
&lt;&#x2F;span&gt;&lt;span&gt;2376827 Jan  8 11:56 raw_location_latitude.csv
&lt;&#x2F;span&gt;&lt;span&gt;2377039 Jan  8 11:56 raw_location_longitude.csv
&lt;&#x2F;span&gt;&lt;span&gt;1992700 Jan  8 11:56 raw_location_vertical-radius.csv
&lt;&#x2F;span&gt;&lt;span&gt; 293536 Jan  8 11:58 raw_spo2_auto_spo2.csv
&lt;&#x2F;span&gt;&lt;span&gt;2615639 Jan  8 11:58 raw_spo2_quality_score.csv
&lt;&#x2F;span&gt;&lt;span&gt;  13277 Jan  8 11:58 raw_swim_lap-pool.csv
&lt;&#x2F;span&gt;&lt;span&gt;1562522 Jan  8 11:54 raw_tracker_calories-earned.csv
&lt;&#x2F;span&gt;&lt;span&gt;1483782 Jan  8 11:54 raw_tracker_distance.csv
&lt;&#x2F;span&gt;&lt;span&gt;1303766 Jan  8 11:54 raw_tracker_elevation.csv
&lt;&#x2F;span&gt;&lt;span&gt;   5553 Jan  8 11:54 raw_tracker_lap-pool.csv
&lt;&#x2F;span&gt;&lt;span&gt; 116658 Jan  8 11:54 raw_tracker_sleep-state.csv
&lt;&#x2F;span&gt;&lt;span&gt;1337423 Jan  8 11:54 raw_tracker_steps.csv
&lt;&#x2F;span&gt;&lt;span&gt;   3323 Jan  8 12:01 README.txt
&lt;&#x2F;span&gt;&lt;span&gt;1650810 Jan  8 11:53 signal.csv
&lt;&#x2F;span&gt;&lt;span&gt;  39917 Jan  8 12:01 sleep.csv
&lt;&#x2F;span&gt;&lt;span&gt;   1048 Jan  8 11:53 weight.csv
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the basic-but-better-than-last-time docs, we see:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;raw_location_latitude.csv: Latitude data
&lt;&#x2F;span&gt;&lt;span&gt;· Duration: (seconds)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;raw_location_longitude.csv: Longitude data
&lt;&#x2F;span&gt;&lt;span&gt;· Duration: (seconds)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;# raw_location_latitude.csv
&lt;&#x2F;span&gt;&lt;span&gt;start,duration,value
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T12:50:26+01:00,[60],[44.XXX]
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T13:28:49+01:00,[60],[44.XXX]
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T13:28:59+01:00,[60],[44.XXX]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# raw_location_longitude.csv
&lt;&#x2F;span&gt;&lt;span&gt;start,duration,value
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T12:50:26+01:00,[60],[26.XXX]
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T13:28:49+01:00,[60],[26.XXX]
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T13:28:59+01:00,[60],[26.XXX]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;XXX&lt;&#x2F;code&gt;s are not in the original files, I&#x27;ve (quite pointlessly) masked the digits after the decimal point.
I don&#x27;t think we care about the durations, but the timestamps are not monotonic, which might matter later.
Fortunately, the timestamps appear to be correlated across the two files.
Otherwise it would be quite annoying to match the two values.
On the other hand, we have some weird-looking entries:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;# raw_location_latitude.csv
&lt;&#x2F;span&gt;&lt;span&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T13:45:36+01:00,&amp;quot;[60,60]&amp;quot;,&amp;quot;[44.XXX,657.XXX]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;2021-11-10T13:14:42+01:00,&amp;quot;[60,60]&amp;quot;,&amp;quot;[44.XXX,2021.XXX]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;2021-11-09T15:05:49+01:00,&amp;quot;[60,60]&amp;quot;,&amp;quot;[44.XXX,-217.XXX]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# raw_location_longitude.csv
&lt;&#x2F;span&gt;&lt;span&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;2022-01-06T13:45:36+01:00,&amp;quot;[60,60]&amp;quot;,&amp;quot;[26.XXX,277.XXX]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;2021-11-10T13:14:42+01:00,&amp;quot;[60,60]&amp;quot;,&amp;quot;[26.XXX,1448.XXX]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;[snip]
&lt;&#x2F;span&gt;&lt;span&gt;2021-11-09T15:05:49+01:00,&amp;quot;[60,60]&amp;quot;,&amp;quot;[26.XXX,-534.XXX]&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At first sight, those might appear to be two measurements merged into one entry, as the duration seems legit.
But the second coordinate values are clearly bogus.
There are no entries with three values, and those with a single one don&#x27;t have any outrageous outliers.
So whatever these are, we will make sure to ignore them.&lt;&#x2F;p&gt;
&lt;p&gt;I won&#x27;t show any code now, but let&#x27;s extract the points from there, open &lt;a href=&quot;https:&#x2F;&#x2F;qgis.org&#x2F;&quot;&gt;QGIS&lt;&#x2F;a&gt; and check whether the values (for one arbitrary day) appear to be correct:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-points.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-points.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes, there are a couple of outliers but overall it&#x27;s fine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;map-matching&quot;&gt;Map matching&lt;&#x2F;h2&gt;
&lt;p&gt;My hope was to match these points to road segments obtained from OpenStreetMap data.
It took me a while to stumble across a way to do this, but I managed to find the &lt;a href=&quot;http:&#x2F;&#x2F;project-osrm.org&#x2F;&quot;&gt;OSRM&lt;&#x2F;a&gt; project.
OSRM is open-source and they have a demo web service, but the strict query length limitation made trying it a was of time.&lt;&#x2F;p&gt;
&lt;p&gt;Looking at the docs, we find the &lt;a href=&quot;http:&#x2F;&#x2F;project-osrm.org&#x2F;docs&#x2F;v5.24.0&#x2F;api&#x2F;#match-service&quot;&gt;&lt;code&gt;match&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; endpoint.
It takes a set of coordinates and returns a list of route legs corresponding to them.
You can see an example if you follow the previous link.&lt;&#x2F;p&gt;
&lt;p&gt;I found a couple of sites that offered OSM exports, but couldn&#x27;t figure out quickly how to register for an API key.
In the end, I downloaded a &lt;code&gt;pbf&lt;&#x2F;code&gt; file for my whole country from &lt;a href=&quot;https:&#x2F;&#x2F;data.osm-hr.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;data.osm-hr.org&#x2F;&lt;&#x2F;a&gt;.
It was quite small, at 247 MB.&lt;&#x2F;p&gt;
&lt;p&gt;In order to use OSRM, we need to do some pre-processing steps, and also pick a profile.
&lt;code&gt;foot&lt;&#x2F;code&gt; is a good choice here because I don&#x27;t care about one-way streets and passable barriers.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; docker run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --rm -t -v &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;span&gt;:&#x2F;data osrm&#x2F;osrm-backend osrm-extract&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;opt&#x2F;foot.lua &#x2F;data&#x2F;romania.osm.pbf
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; docker run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --rm -t -v &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;span&gt;:&#x2F;data osrm&#x2F;osrm-backend osrm-partition &#x2F;data&#x2F;romania.osrm
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; docker run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --rm -t -v &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;span&gt;:&#x2F;data osrm&#x2F;osrm-backend osrm-customize &#x2F;data&#x2F;romania.osrm
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On my computer this took 33 seconds and used about 3.1 GB RAM at its peak.
Now we can start the OSRM routing service:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; docker run&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --rm -p&lt;&#x2F;span&gt;&lt;span&gt; 5000:5000&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -v &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;span&gt;:&#x2F;data osrm&#x2F;osrm-backend osrm-routed&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --algorithm&lt;&#x2F;span&gt;&lt;span&gt; mld&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --max-matching-size&lt;&#x2F;span&gt;&lt;span&gt; 5000 &#x2F;data&#x2F;romania.osrm
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s a bit weird, but &lt;code&gt;match&lt;&#x2F;code&gt; also expects a profile.
It doesn&#x27;t seem to matter (as you would expect, since we picked a profile during the pre-processing), and this was slightly confusing.
Does it work?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks-bad.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks-bad.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;No, that&#x27;s not great.
I tried a couple of things: displaying all the matched legs, changing the profile (I originally used the wrong one), sorting the points by timestamp, and even including the timestamps in the request:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks-better.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks-better.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is much better.
What if we also use the location accuracy, available in the &lt;code&gt;raw_location_horizontal-radius.csv&lt;&#x2F;code&gt; file from the archive?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks-not-better.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks-not-better.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This slows down the matching from &quot;apparently instant&quot; to almost 90 seconds, and introduces some errors.
Looking at the accuracy radius values, most of them are around 10 m, but some have suspicious values like 600 and 800 m.
Let&#x27;s keep the points with accuracy better than 50 m:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks-better-again.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks-better-again.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;With the old output in green, you can see that most of the extra segments are now gone.
But some are still missing and this confused me quite a bit until I looked at the OSM data.&lt;&#x2F;p&gt;
&lt;p&gt;Hint: don&#x27;t try open a &lt;code&gt;pbf&lt;&#x2F;code&gt; file directly; you can use &lt;a href=&quot;https:&#x2F;&#x2F;gdal.org&#x2F;&quot;&gt;GDAL&lt;&#x2F;a&gt; to convert it to a format with spatial index support:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; ogr2ogr romania.osm.gpkg romania.osm.pbf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks-osm-gaps.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks-osm-gaps.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s hard to see in the image, but there&#x27;s a visible gap near the top-left corner.
Could my OSM export have been too old?
Looking at that site again, the other files are from 2018.
My download probably triggered an update, since now the &lt;code&gt;pbf&lt;&#x2F;code&gt; shows a timestamp from today.&lt;&#x2F;p&gt;
&lt;p&gt;I searched for other ways to get the OSM data and &lt;a href=&quot;https:&#x2F;&#x2F;download.geofabrik.de&#x2F;&quot;&gt;Geofabrik&lt;&#x2F;a&gt; seems to be more popular.
Let&#x27;s see how it looks:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks-new-osm.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks-new-osm.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, some segments are still missing or wrong, even though this time they are present in the OSM data.
Checking one of them, it had an &lt;code&gt;access =&amp;gt; private&lt;&#x2F;code&gt; tag, which makes sense.
There are some residential buildings with barriers and I might have passed near some of them without noticing it wasn&#x27;t allowed.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;foot&lt;&#x2F;code&gt; profile has a list of blacklisted tags:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;access_tag_blacklist &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Set &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;no&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;agricultural&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;forestry&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;private&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;delivery&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I removed them, re-ran the OSRM pre-processing, and re-did the matching:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-tracks-not-bad.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-tracks-not-bad.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The missing segment is a foot path through an uncultivated area between two recently-built apartment buildings:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;gps-photo.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;gps-photo-thumb.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;But overall it&#x27;s quite decent, so I guess this is it for today.
Thanks for reading if you got to the end.&lt;&#x2F;p&gt;
&lt;p&gt;In the next post, I will try to show these tracks in a more interesting form.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Map data from &lt;a href=&quot;https:&#x2F;&#x2F;openstreetmap.org&#x2F;copyright&quot;&gt;OpenStreetMap&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Announcing the co2mon crate</title>
        <published>2021-12-30T00:00:00+00:00</published>
        <updated>2021-12-30T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/introducing-co2mon/" type="text/html" />
        <id>https://blog.dend.ro/introducing-co2mon/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;This is a couple of years too late, but I want to write a quick post announcing my first crate, &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;co2mon&quot;&gt;&lt;code&gt;co2mon&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. It&#x27;s a small library for reading data from Holtek and similar CO₂ USB monitors.
These are relatively popular, because the protocol &lt;a href=&quot;https:&#x2F;&#x2F;hackaday.io&#x2F;project&#x2F;5301-reverse-engineering-a-low-cost-usb-co-monitor&quot;&gt;was reverse-engineered&lt;&#x2F;a&gt; and it&#x27;s easy to communicate with them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;linux-prerequisites&quot;&gt;Linux prerequisites&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re on Linux, you will need permissions to access the device node.
The following &lt;code&gt;udev&lt;&#x2F;code&gt; rule will give permissions to every user on the system:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;ACTION==&amp;quot;add|change&amp;quot;, SUBSYSTEMS==&amp;quot;usb&amp;quot;, ATTRS{idVendor}==&amp;quot;04d9&amp;quot;, ATTRS{idProduct}==&amp;quot;a052&amp;quot;, MODE:=&amp;quot;0666&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;See the crate documentation for details on how to install it.
You can check the vendor and product id pair using the &lt;code&gt;lsusb&lt;&#x2F;code&gt; command.&lt;&#x2F;p&gt;
&lt;p&gt;If you get a linker error and you might need to install a &lt;code&gt;libusb-1.0-0-dev&lt;&#x2F;code&gt; or &lt;code&gt;libusb&lt;&#x2F;code&gt; package.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;&#x2F;h2&gt;
&lt;p&gt;Add the &lt;code&gt;co2mon&lt;&#x2F;code&gt; dependency to your &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;, then copy-paste the following code and try to run it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;co2mon::{Result, Sensor};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::thread;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::time::Duration;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Result&amp;lt;()&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; sensor = Sensor::open_default()?;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; sensor.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;            Ok(reading) =&amp;gt; println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{:.4}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; °C, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; ppm CO₂&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, reading.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;temperature&lt;&#x2F;span&gt;&lt;span&gt;(), reading.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;co2&lt;&#x2F;span&gt;&lt;span&gt;()),
&lt;&#x2F;span&gt;&lt;span&gt;            Err(e) =&amp;gt; eprintln!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, e),
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        thread::sleep(Duration::from_secs(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The sensor sends various types of messages, in an arbitrary order.
&lt;code&gt;Sensor::read&lt;&#x2F;code&gt; waits for a pair of temperature and CO₂ measurements and returns that.
There&#x27;s also a &lt;code&gt;Sensor::read_one&lt;&#x2F;code&gt; method, which returns a single message.
This can be useful for versions of the sensor that also measure the relative humidity.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;device-support&quot;&gt;Device support&lt;&#x2F;h2&gt;
&lt;p&gt;Tested using a TFA Dostmann &lt;a href=&quot;https:&#x2F;&#x2F;www.tfa-dostmann.de&#x2F;en&#x2F;product&#x2F;co2-monitor-airco2ntrol-mini-31-5006&#x2F;&quot;&gt;AIRCO2NTROL MINI&lt;&#x2F;a&gt;, but thanks to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lnicola&#x2F;co2mon&#x2F;pull&#x2F;6&quot;&gt;a kind contributor&lt;&#x2F;a&gt;, the crate should also work for newer versions like the &lt;a href=&quot;https:&#x2F;&#x2F;www.tfa-dostmann.de&#x2F;en&#x2F;product&#x2F;co2-monitor-airco2ntrol-coach-31-5009&#x2F;&quot;&gt;COACH&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-to-do-with-it&quot;&gt;What to do with it&lt;&#x2F;h2&gt;
&lt;p&gt;Open the windows.
The CO₂ levels you&#x27;ll find in a closed room aren&#x27;t exactly dangerous, but can still cause headaches, malaise and impair thinking skills.
At one point I took mine to the office and it showed an error because it only goes up to 3000 ppm.
Reading from USB still worked, giving concentrations around 3500 ppm.&lt;&#x2F;p&gt;
&lt;p&gt;Having a constant airflow in an office will also help against Covid, possibly even more than wearing masks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;&#x2F;h2&gt;
&lt;p&gt;My Grafana isn&#x27;t in the best of shapes these days, but here&#x27;s a screenshot:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;co2.webp&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;co2.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>My Rust 2020 wish list: playing nice</title>
        <published>2019-11-03T00:00:00+00:00</published>
        <updated>2019-11-03T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/my-rust-2020-wishlist/" type="text/html" />
        <id>https://blog.dend.ro/my-rust-2020-wishlist/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;This year I decided to jot down some thoughts for the &lt;a href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;2019&#x2F;10&#x2F;29&#x2F;A-call-for-blogs-2020.html&quot;&gt;Rust 2020 call for blog posts&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The major caveat here is that I&#x27;m just a language enthusiast.
I&#x27;m not using Rust professionally, and my skill in using the language is somewhat mediocre.
We are a pretty diverse bunch, and other people and teams will have different wishes and expectations.&lt;&#x2F;p&gt;
&lt;p&gt;I think the general theme here will be integration or &quot;playing well&quot;, on different levels.
A lot of these here are not language changes, and most of them already exist in some form.
Probably none of them are new ideas.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not going to assign priorities: priorities change, new issues are discovered, and contributors work on what they&#x27;re interested in, not necessarily roadmap items.
And some of the aspects I mention are requests for the community not the project members.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;debugging-experience&quot;&gt;Debugging experience&lt;&#x2F;h2&gt;
&lt;p&gt;Rust got a head start here because of its similarity to C and C++, and being able to use the debugging symbols implementation from LLVM.
With a bit of patience and skill you can make &lt;code&gt;gdb&lt;&#x2F;code&gt; or &lt;code&gt;lldb&lt;&#x2F;code&gt; work decently enough with Rust programs.
I think, however, that we could and should do better.
We shouldn&#x27;t aim to match the &lt;code&gt;gdb&lt;&#x2F;code&gt; experience for C++ programs, but rather for C# or Java-like integration.&lt;&#x2F;p&gt;
&lt;p&gt;A first step here would be to improve the existing debug visualizers, and make sure they play nice with the three major debuggers we have — &lt;code&gt;gdb&lt;&#x2F;code&gt;, &lt;code&gt;lldb&lt;&#x2F;code&gt; and &lt;code&gt;vsdbg&lt;&#x2F;code&gt;.
In the long run, I hope we will find a way to call existing &lt;code&gt;Debug&lt;&#x2F;code&gt; or &lt;code&gt;Display&lt;&#x2F;code&gt; implementations.
This is probably very hard, since the formatting code might have been dropped by the linker from the final executable.
Is there a way to leverage DWARF for it? I don&#x27;t know.&lt;&#x2F;p&gt;
&lt;p&gt;Relevant issues:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;50005&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;50005&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;36503&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;36503&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;40460&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;40460&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;linking-speed&quot;&gt;Linking speed&lt;&#x2F;h2&gt;
&lt;p&gt;This doesn&#x27;t apply to all projects, but a lot of users would be happier if &lt;code&gt;cargo&lt;&#x2F;code&gt; would use the LLVM linker (&lt;code&gt;lld&lt;&#x2F;code&gt;) by default.
In some cases, linking is by far the slowest step in a build, more so in an incremental one.
Using &lt;code&gt;lld&lt;&#x2F;code&gt; can dramatically cut down on link times, especially for large projects with a lot of debug information.&lt;&#x2F;p&gt;
&lt;p&gt;My understanding of the current status is that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;on MacOS it&#x27;s not worth using &lt;code&gt;lld&lt;&#x2F;code&gt; because it&#x27;s buggy and unmaintained&lt;&#x2F;li&gt;
&lt;li&gt;on Linux with GCC 9 or later it&#x27;s easy to use &lt;code&gt;lld&lt;&#x2F;code&gt; by adding &lt;code&gt;-C link-arg=-fuse-ld=lld&lt;&#x2F;code&gt; to &lt;code&gt;RUSTFLAGS&lt;&#x2F;code&gt; or your &lt;code&gt;.cargo&#x2F;config&lt;&#x2F;code&gt; file&lt;&#x2F;li&gt;
&lt;li&gt;on Windows it should work, but there&#x27;s a large chance that &lt;code&gt;cargo&lt;&#x2F;code&gt; will pick up the GCC packaged by the Rust toolchain, even if you have GCC 9 installed.
I&#x27;m not sure what&#x27;s the current situation with Visual Studio.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All of this info doesn&#x27;t seem to be documented, but can be found floating around GitHub and other forums.
Is there any hope of seeing &lt;code&gt;lld&lt;&#x2F;code&gt; as the default, at least on Linux?&lt;&#x2F;p&gt;
&lt;p&gt;Visual Studio also has incremental linking.
Can we get something like that?&lt;&#x2F;p&gt;
&lt;p&gt;Relevant issue: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;39915&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;39915&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compile-cache&quot;&gt;Compile cache&lt;&#x2F;h2&gt;
&lt;p&gt;A nice, relatively easy win is to have a global build-cache.
Supposedly, this is hard to implement, because it needs to handle different versions of compiler, crates, &lt;code&gt;cargo&lt;&#x2F;code&gt; features, conditional compilation and targets.
But &lt;code&gt;cargo&lt;&#x2F;code&gt; is already great at keeping track of those within a single project, so I don&#x27;t buy this argument.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s the &lt;code&gt;sccache&lt;&#x2F;code&gt; project that tries to offer this, but in my experience it&#x27;s a bit unreliable about tracking the compiler version, so I often need to nuke its cache manually after upgrades.
Somewhat worse, it doesn&#x27;t handle anything with build scripts or procedural macros (that is, a lot of slow to compile crates), presumably because it needs to support distributed compilation.
I think a local-only mode for &lt;code&gt;sccache&lt;&#x2F;code&gt; would be a huge win.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s also the disk space issue.
With incremental compilation, build files tend to take a huge amount of space.
With a global cache, the external crates could be stored only once, which would make a lot of people with 120 GB SSDs happy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;system-integration&quot;&gt;System integration&lt;&#x2F;h2&gt;
&lt;p&gt;Right now, &lt;code&gt;cargo&lt;&#x2F;code&gt; stores the crates.io registry under &lt;code&gt;~&#x2F;.cargo&#x2F;registry&lt;&#x2F;code&gt;, and maybe also under &lt;code&gt;~&#x2F;.cargo&#x2F;git&lt;&#x2F;code&gt;.
I&#x27;m not sure myself.
I&#x27;d very much like if &lt;code&gt;cargo&lt;&#x2F;code&gt; was a better team player here.
There are clear-cut guidelines for storing configuration and cached data, and &lt;code&gt;cargo&lt;&#x2F;code&gt; is not following them.
This makes it painful for people using backup programs, roaming user profiles, or who just want to free up some disk space.&lt;&#x2F;p&gt;
&lt;p&gt;This was quite heavily discussed and even implemented, but eventually fizzled out:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rfcs&#x2F;pull&#x2F;1615&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rfcs&#x2F;pull&#x2F;1615&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;12725&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;12725&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;1734&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;1734&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;1976&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;1976&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;pull&#x2F;5183&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;pull&#x2F;5183&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Notable here is the strong opposition from someone closely associated to the language.
I believe it&#x27;s in the interest of Rust to play nice with the platform expectations, instead of being its own special snowflake.
There&#x27;s nothing special to &lt;code&gt;~&#x2F;.cargo&#x2F;git&lt;&#x2F;code&gt; here, no deeper meaning, no potential for data loss if it removed.
It&#x27;s just a volatile directory, and should not be elevated to something that the users need or care to look at.&lt;&#x2F;p&gt;
&lt;p&gt;Mildly relevant: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rfcs&#x2F;pull&#x2F;2789&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rfcs&#x2F;pull&#x2F;2789&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;formal-grammar&quot;&gt;Formal grammar&lt;&#x2F;h2&gt;
&lt;p&gt;There is a working group for this, but it still seems to come up relatively often.
I think having a formal grammar and a parser crate that lives outside of &lt;code&gt;rustc&lt;&#x2F;code&gt; would make a lot of people feel more at ease with regards to the viability of another compiler implementation.
Personally, I don&#x27;t think we &lt;em&gt;need&lt;&#x2F;em&gt; another implementation at this point, but a grammar and parser would still be useful regardless of that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;language-features&quot;&gt;Language features&lt;&#x2F;h2&gt;
&lt;p&gt;I hope there will be progress on features like &lt;code&gt;impl Trait&lt;&#x2F;code&gt;, &lt;code&gt;async fn&lt;&#x2F;code&gt; in traits, const generics, streams, generators and perhaps specialization.
Probably everyone wants these, so there&#x27;s not much to say.&lt;&#x2F;p&gt;
&lt;p&gt;Maybe the next year the &lt;code&gt;chalk&lt;&#x2F;code&gt; and &lt;code&gt;polonius&lt;&#x2F;code&gt; work will finally bear some fruit, and perhaps there will be some resolution to the parallel compiler saga.
Speaking of which, can &lt;code&gt;salsa&lt;&#x2F;code&gt; replace or supplement the &lt;code&gt;rustc&lt;&#x2F;code&gt; query system?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sanitizers&quot;&gt;Sanitizers&lt;&#x2F;h2&gt;
&lt;p&gt;Using the LLVM sanitizers seems to be a bit of a mystery.
People talk about this, but nobody seems to be doing it.
Together with &lt;code&gt;miri&lt;&#x2F;code&gt;, sanitizers would be a powerful tool for dynamic checking of Rust programs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bringing-crates-into-std&quot;&gt;Bringing crates into &lt;code&gt;std&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This is something that comes up from time to time.
I think we should try to identify common patterns, especially in unsafe code, and offer good implementations in &lt;code&gt;libstd&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Relevant discussion: &lt;a href=&quot;https:&#x2F;&#x2F;internals.rust-lang.org&#x2F;t&#x2F;calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index&#x2F;11129&quot;&gt;https:&#x2F;&#x2F;internals.rust-lang.org&#x2F;t&#x2F;calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index&#x2F;11129&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;std-aware-cargo&quot;&gt;&lt;code&gt;std&lt;&#x2F;code&gt;-aware &lt;code&gt;cargo&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This is quite specific and is already requested, but I&#x27;d like to see &lt;code&gt;cargo&lt;&#x2F;code&gt; be able to build &lt;code&gt;libstd&lt;&#x2F;code&gt; instead of using a bundled version.
This would be very helpful for embedded projects, and will improve code generation in some setups like projects that use abort on panic.&lt;&#x2F;p&gt;
&lt;p&gt;Relevant issue: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;4959&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;4959&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;popular-cargo-plugins&quot;&gt;Popular &lt;code&gt;cargo&lt;&#x2F;code&gt; plugins&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve seen &lt;code&gt;cargo-vendor&lt;&#x2F;code&gt; get integrated into &lt;code&gt;cargo&lt;&#x2F;code&gt;, but there are a couple of other popular plugins that should follow the same route: &lt;code&gt;cargo-edit&lt;&#x2F;code&gt;, &lt;code&gt;cargo-outdated&lt;&#x2F;code&gt; and &lt;code&gt;cargo-tree&lt;&#x2F;code&gt; come to mind.&lt;&#x2F;p&gt;
&lt;p&gt;Relevant issue: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;4309&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;4309&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;paper-cuts&quot;&gt;Paper cuts&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m sure that everybody has some paper cuts they would like to see fixed.
The worst I can think of right now are probably the weird interaction between &lt;code&gt;cargo&lt;&#x2F;code&gt; workspaces and features, and &lt;code&gt;html_root_url&lt;&#x2F;code&gt; which so many people forget to update that it&#x27;s common to add a reminder about it in the manifest.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-principled-stance-on-unsafe&quot;&gt;A principled stance on &lt;code&gt;unsafe&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Right now we have two vocal minorities.
One, generally made of newcomers to the language, says that unsafe code is bad (and even that, by extension, the whole language is bad and useless because &lt;code&gt;libstd&lt;&#x2F;code&gt; uses &lt;code&gt;unsafe&lt;&#x2F;code&gt;).
The other, usually developers experienced in other languages, carelessly uses &lt;code&gt;unsafe&lt;&#x2F;code&gt; wherever the opportunity arises, not caring about the fact that their code is unsound.&lt;&#x2F;p&gt;
&lt;p&gt;None of the two groups are right, and that should be obvious.
A more subtle issue is that an overreaction to former group could normalize the idea that &lt;code&gt;unsafe&lt;&#x2F;code&gt; is perfectly fine if you say you know what you&#x27;re doing, thus validating the beliefs of the latter.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;crates-io-and-rustsec-integration&quot;&gt;crates.io and RustSec integration&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;rustsec.org&#x2F;&quot;&gt;RustSec&lt;&#x2F;a&gt; project has aggregated quite a few of vulnerabilities, some of them still unfixed.
It would be really cool if crates.io could query the RustSec database and display which crate versions are vulnerable or not.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-future-of-rls&quot;&gt;The future of RLS&lt;&#x2F;h2&gt;
&lt;p&gt;I was glad to watch &lt;code&gt;rust-analyzer&lt;&#x2F;code&gt; make great strides in the last year, from the nifty assists that were implemented, to &lt;code&gt;macro_rules&lt;&#x2F;code&gt; support and pretty decent method resolution.
Pending some &lt;code&gt;chalk&lt;&#x2F;code&gt; improvements, it might become almost as precise as RLS, but with much better responsiveness.&lt;&#x2F;p&gt;
&lt;p&gt;The one thing I&#x27;m worried about is visible in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-analyzer&#x2F;rust-analyzer&#x2F;graphs&#x2F;contributors&quot;&gt;contributors list&lt;&#x2F;a&gt;.
Not to discount the work of many people there, but the whole project is basically moving forward only through the effort of a couple of people.&lt;&#x2F;p&gt;
&lt;p&gt;In theory, &lt;code&gt;rust-analyzer&lt;&#x2F;code&gt; is an experiment to see if we can improve on RLS.
I think we&#x27;re quickly approaching a point where we need to answer that question.
Is it fit to replace RLS or not? In my opinion (and that of many nightly toolchain users, I&#x27;m sure) the answer is a resounding yes.
But I would like to see some official statement here.
If it&#x27;s deemed to be the way forward, maybe RLS should be put into maintenance mode, with those resources being allocated to &lt;code&gt;rust-analyzer&lt;&#x2F;code&gt; instead.&lt;&#x2F;p&gt;
&lt;p&gt;I believe that when &lt;code&gt;rust-analyzer&lt;&#x2F;code&gt; got started, there were some quite strong differences of opinion related to the long-term suitability of the RLS design.
Hopefully we&#x27;re over them by now, and we can make a decision that goes towards the best interest of the users.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-rfc-process&quot;&gt;The RFC process&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s probably well-understood that the RFC process has some limitations that make it scale poorly.
Perhaps a better approach here, which I&#x27;m sure was proposed before, would be to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;move most of the RFC discussions to separate repositories, using issues and pull requests&lt;&#x2F;li&gt;
&lt;li&gt;keep a long-running summary of these discussion with pros and cons in something like a HackMD document instead of GitHub comments&lt;&#x2F;li&gt;
&lt;li&gt;try to put some contingency measures in place in case some team members are unavailable or otherwise cannot vote on an RFC&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;the-communication-platform&quot;&gt;The communication platform&lt;&#x2F;h2&gt;
&lt;p&gt;The Rust project seems to have settled on Discord as a replacement for IRC.
I&#x27;ve never used that platform but, as a lot of others have pointed out, something like Matrix might be more in line with the values of the community.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;community-part-i&quot;&gt;Community (part I)&lt;&#x2F;h2&gt;
&lt;p&gt;Speaking of community, I&#x27;m pretty disappointed in how the new website project was handled.
I&#x27;m not going to repeat the complaints that others have had about the contents, lack of translations, design, and the site being more or less broken in not so subtle ways.
A lot of these were fixed in the last year.&lt;&#x2F;p&gt;
&lt;p&gt;But I think the launch of the new site was rushed out unnecessarily, and became a friction point that could have been avoided by saying &quot;okay, a lot of people are crying out about this change we&#x27;re making, maybe we should stop and re-think this for a while&quot;.
Instead, we&#x27;ve seen helpful pull requests being closed without thanks or reason.
Is that the impression we want to leave to new contributors? &lt;em&gt;If I had that experience with a project, I would be quite reluctant to get involved any further.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Speaking of which, some of us are probably &lt;a href=&quot;https:&#x2F;&#x2F;internals.rust-lang.org&#x2F;t&#x2F;website-retrospective&#x2F;9556&#x2F;7&quot;&gt;still waiting&lt;&#x2F;a&gt; for an honest post-mortem on it.
The point here is not to make heads roll, but to acknowledge that some mistakes were made, figure out what they were and what to do to prevent them from happening again.
I&#x27;d like to see some accountability and transparency on this front, more than others.&lt;&#x2F;p&gt;
&lt;p&gt;To wit, there is this blurb on the the &lt;a href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;governance&#x2F;teams&#x2F;community&quot;&gt;Community team&lt;&#x2F;a&gt; page:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Coordination and supporting events, content creation, running the RustBridge program, and conducting the survey.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I agree that those are important things to care about, but the community is more than that.
We should acknowledge the regular contributors, the crate authors, the enthusiasts that help people learn the language on the various forums, even those that submit a drive-by pull request once in a blue moon.&lt;&#x2F;p&gt;
&lt;p&gt;We do have the Rust Survey once a year, but no formal feedback channel otherwise.
Sure, some people will post on Discourse or Reddit, and some project members might notice and answer them, but I think there is some room for improvement here.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;roadmap&quot;&gt;Roadmap&lt;&#x2F;h2&gt;
&lt;p&gt;I think I would like to see a rough and very high-level list or board of things that the team is actively working on, or planning to.
Maybe the roadmap for 2020 could have a section of &quot;we will probably want these in the future, but cannot work on them now, maybe the next year&quot;.
Such a list could be updated during the year, as priorities and resources change.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;community-part-ii&quot;&gt;Community (part II)&lt;&#x2F;h2&gt;
&lt;p&gt;There is a very deep rift in the community in the shape of async run-times and related projects.
Much has been said about the two major implementations, yet to me it seems more and more that they are more similar than different.
I think it&#x27;s apparent here that the reasons for it are more social than technical.
Time will probably make them converge more and more on the technical side, but the current situation is not ideal.&lt;&#x2F;p&gt;
&lt;p&gt;There is much to say here about various aspects, from naming to timing, and generally the reasoning behind the projects started by the now-disbanded Async Ecosystem WG (nb. &lt;code&gt;async-std&lt;&#x2F;code&gt; was not an Async Ecosystem WG project, even though the same people are involved).
But these were already discussed a lot in different places, and I don&#x27;t want to add anything here.
Perhaps it is more important to ask:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;is the &lt;em&gt;status quo&lt;&#x2F;em&gt; of two very similar, but slightly incompatible run-times in the best interest of the users?&lt;&#x2F;li&gt;
&lt;li&gt;if yes, how do the two projects position themselves, which users are they catering to? It&#x27;s worth mentioning here that the goals of the two projects are quite similar according to their developers — offering async versions of the functionality present in the standard library. One of the two projects actually uses this as its tagline, which tends to confuse beginners.&lt;&#x2F;li&gt;
&lt;li&gt;if no, what can be done to close this rift? The answer here is clearly not technical, and it will require giving up some control and some ego, and actively trying to work with the other side. This is hard to do, harder than any technical challenge that the two projects might encounter.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I also want to say that there is a certain level of misinformation and FUD floating around, most likely unintentional.
We should work on that, because it can get toxic in the long run.
In addition, I was very disappointed to see a comment on a well-intended &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;withoutboats&#x2F;romio&#x2F;pull&#x2F;106&quot;&gt;pull request&lt;&#x2F;a&gt; that was quite aggressive towards the competing project.
It&#x27;s now deleted, but it went like:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;After 2 hours, this issue got 17 thumbs up. After 5 hours, it has 20. I recommend closing this issue as spam.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;(although initially it said &quot;obvious trolling&quot; in Russian, or something similar)&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s an awful way to speak about the competing project, which actually spawned both &lt;code&gt;romio&lt;&#x2F;code&gt; and the one you&#x27;re working on.
And I don&#x27;t think it&#x27;s in the best interest of &lt;code&gt;async-std&lt;&#x2F;code&gt; if its developers take this kind of position.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;&#x2F;strong&gt; unsurprisingly, this boiled over pretty bad.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;transparency&quot;&gt;Transparency&lt;&#x2F;h2&gt;
&lt;p&gt;Finally, I&#x27;m not sure how well the working group structure has panned out.
There are quite a lot of WGs, but I&#x27;m not sure how much progress they have been making.&lt;&#x2F;p&gt;
&lt;p&gt;I think the plan was to have regular progress meetings and keep minutes for each WG, but my impression is that these happened for a month or two, then they stopped.&lt;&#x2F;p&gt;
&lt;p&gt;Maybe the recently-announced &lt;a href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;inside-rust&#x2F;index.html&quot;&gt;Inside Rust&lt;&#x2F;a&gt; blog will be a simple solution to this problem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-future&quot;&gt;The future&lt;&#x2F;h2&gt;
&lt;p&gt;As &lt;a href=&quot;https:&#x2F;&#x2F;tim.mcnamara.nz&#x2F;post&#x2F;188733729327&#x2F;rust-2020-lets-embrace-the-eternal-september&quot;&gt;somebody else&lt;&#x2F;a&gt; has mentioned, I think our greater challenges have yet to come, brought by new production users (let&#x27;s not forget that the greatest mass of software developers is not visible in the Stack Overflow surveys) and maybe some internal tensions.
I still think that Rust is a quite nice local maximum of programming languages, but we must steel ourselves and prepare for new challenges, from inexperience users, to companies tying to get more control over the project, to competition for other languages like C# that are inching close and closer towards Rust and Go.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Even though I spoke more about things that aren&#x27;t quite working, we&#x27;ve made a nice amount of progress this year.
I&#x27;m not going to make a list here, as I&#x27;m sure others will be much better at it.&lt;&#x2F;p&gt;
&lt;p&gt;And while I&#x27;ve been somewhat negative on a couple of points, I still think we&#x27;re doing pretty well overall.
I&#x27;m only worried that social factors can prove to be a problem in the long run, and we — both the project members and the community — should focus a little on &lt;em&gt;resiliency&lt;&#x2F;em&gt; in the long run.
This means playing nice towards others, and being prepared for new users, more competition, and the potential for more conflicts.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Acknowledgements</title>
        <published>2018-08-05T00:00:00+00:00</published>
        <updated>2018-08-05T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/content/acknowledgements/" type="text/html" />
        <id>https://blog.dend.ro/content/acknowledgements/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;Site created with the &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; static site generator. Theme based on &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;themes&#x2F;hyde&#x2F;&quot;&gt;Hyde&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

</content>
    </entry>
    <entry xml:lang="en">
        <title>Rust and the Case of the Redundant Comparison</title>
        <published>2018-08-04T00:00:00+00:00</published>
        <updated>2018-08-04T00:00:00+00:00</updated>
        <link rel="alternate" href="https://blog.dend.ro/rust-and-the-case-of-the-redundant-comparison/" type="text/html" />
        <id>https://blog.dend.ro/rust-and-the-case-of-the-redundant-comparison/</id>
        <author>
            <name>Laurențiu Nicola</name>
        </author>
        <content type="html">
      &lt;p&gt;A couple of days ago I landed my &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;pull&#x2F;52908&quot;&gt;second pull request&lt;&#x2F;a&gt; in the &lt;a href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;&quot;&gt;Rust Programming Language&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;&quot;&gt;repository&lt;&#x2F;a&gt;.
This is the story of how that went.&lt;&#x2F;p&gt;
&lt;p&gt;This post is inspired by &lt;a href=&quot;https:&#x2F;&#x2F;llogiq.github.io&#x2F;2018&#x2F;08&#x2F;04&#x2F;improve.html&quot;&gt;other&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;blog.mozilla.org&#x2F;nnethercote&#x2F;&quot;&gt;posts&lt;&#x2F;a&gt; about improving the Rust compiler.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;&#x2F;strong&gt; I made a 20 lines PR to the Rust standard library.
If you&#x27;re so inclined, you should try doing the same.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-chase-after-unsafe-code&quot;&gt;The chase after unsafe code&lt;&#x2F;h2&gt;
&lt;p&gt;There&#x27;s been quite a bit of &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;8s7gei&#x2F;unsafe_rust_in_actixweb_other_libraries&#x2F;&quot;&gt;noise&lt;&#x2F;a&gt; recently about the amount of unsafe code in the &lt;a href=&quot;https:&#x2F;&#x2F;actix.rs&#x2F;&quot;&gt;&lt;code&gt;actix-web&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; framework.
I won&#x27;t discuss the merits of grabbing the pitchforks as soon as someone writes code of a buggy and unidiomatic nature &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#pitchforks&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
But my first encounter with &lt;code&gt;unsafe&lt;&#x2F;code&gt; in Rust was a hard to reproduce, Windows-only, crashing bug in a crate.
On that code path there was a single, seemingly innocuous, &lt;code&gt;unsafe&lt;&#x2F;code&gt; line.
It took me and the crate&#x27;s author maybe half an hour to find it, with the &lt;code&gt;unsafe&lt;&#x2F;code&gt; arrow pointing at it the whole time &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#unsafe&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To be fair, &lt;code&gt;actix-web&lt;&#x2F;code&gt; now lost a large chunk of its unsafe code, although it&#x27;s still not quite my cup of tea.
So I downloaded the source of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hyperium&#x2F;hyper&quot;&gt;&lt;code&gt;hyper&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, another popular, if much lower-level, HTTP library.
Unfortunately (‽), it had relatively few &lt;code&gt;unsafe&lt;&#x2F;code&gt; blocks, many of them in test code.
But one idiom caught my eye:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;Cursor&amp;lt;T&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span&gt;: T,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pos&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;Cursor&amp;lt;Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.pos = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.bytes.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;set_len&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code is trying to clear a &lt;code&gt;Vec&lt;&#x2F;code&gt; by forcefully setting its length to &lt;code&gt;0&lt;&#x2F;code&gt;.
That&#x27;s a bad idea if the elements of the vector implement &lt;code&gt;Drop&lt;&#x2F;code&gt;, because they won&#x27;t be destroyed.
Fortunately, &lt;code&gt;hyper&lt;&#x2F;code&gt; only did that for &lt;code&gt;u8&lt;&#x2F;code&gt; values, but the whole thing seemed unnecessary.&lt;&#x2F;p&gt;
&lt;p&gt;I almost sent a PR to nuke them, but the crate author said that &lt;code&gt;set_len(0)&lt;&#x2F;code&gt; might be faster than &lt;code&gt;clear()&lt;&#x2F;code&gt;.
That couldn&#x27;t be true, since &lt;code&gt;clear&lt;&#x2F;code&gt; has nothing to do besides setting the length, so I tried to prove it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;no_mangle&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub extern fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;test_set_len&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{ x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;set_len&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;); }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;no_mangle&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub extern fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;test_clear&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But I was surprised to see this in the generated code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;test_set_len:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    retq
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;test_clear:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    cmpq    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;je      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;.LBB4_2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;.LBB4_2:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    retq
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you&#x27;re not used to reading assembly, the &lt;code&gt;set_len&lt;&#x2F;code&gt; code sets the vector&#x27;s length to zero (&lt;code&gt;movq&lt;&#x2F;code&gt;) and returns.
&lt;code&gt;clear&lt;&#x2F;code&gt;, however, compares the current length with &lt;code&gt;0&lt;&#x2F;code&gt;.
If it&#x27;s empty, the code jumps to the end of the function (&lt;code&gt;je&lt;&#x2F;code&gt; stands for &quot;jump if equal&quot;).
Otherwise, the length gets set to &lt;code&gt;0&lt;&#x2F;code&gt; and the function returns.
That&#x27;s a useless comparison, the same as:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; len != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    len = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;LLVM is pretty good, so it&#x27;s a bit surprising to see it generate this &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#peepholes&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
In its favour, the debug version is much larger, so the optimizer is still doing a great job.&lt;&#x2F;p&gt;
&lt;p&gt;Do the extra two instructions matter in practice? I didn&#x27;t benchmark, but my intuition says no &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#intuition&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and the &lt;code&gt;set_len(0)&lt;&#x2F;code&gt; calls were mostly in test code.
However, the crate&#x27;s author seemed unconvinced and I didn&#x27;t want to be the one who slowed down &lt;code&gt;hyper&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;down-the-rabbit-hole&quot;&gt;Down the rabbit hole&lt;&#x2F;h2&gt;
&lt;p&gt;Disappointed by this turn of events, I searched for the implementation of &lt;code&gt;clear&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;inline&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;truncate&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;truncate&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; drop any extra elements
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt; len &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.len {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; decrement len before the drop_in_place(), so a panic on Drop
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; doesn&amp;#39;t re-drop the just-failed value.
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.len -= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; len = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.len;
&lt;&#x2F;span&gt;&lt;span&gt;            ptr::drop_in_place(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_unchecked_mut&lt;&#x2F;span&gt;&lt;span&gt;(len));
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code is a bit convoluted, because of the reason described in the comment.
&lt;code&gt;drop&lt;&#x2F;code&gt; can panic &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#panic&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, so the function must decrement the length before dropping an element.
In case of a panic, the last element of the &lt;code&gt;Vec&lt;&#x2F;code&gt; will be a valid one.&lt;&#x2F;p&gt;
&lt;p&gt;A quick test on the &lt;a href=&quot;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;&quot;&gt;Playground&lt;&#x2F;a&gt; shows that if we set the length at the end, the compiler generates the code that we expect:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;inline&lt;&#x2F;span&gt;&lt;span&gt;(never)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;truncate_wrong_dont_use&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;T&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; last = x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt; len &amp;lt; last {
&lt;&#x2F;span&gt;&lt;span&gt;            last -= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            ptr::drop_in_place(x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_unchecked_mut&lt;&#x2F;span&gt;&lt;span&gt;(last));
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;set_len&lt;&#x2F;span&gt;&lt;span&gt;(len);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;playground::truncate_wrong_dont_use:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;    retq
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But that won&#x27;t do.
At this point I filed an issue in the compiler repository, then dropped [sic!] it, waiting for someone else to come up with a fix.
Unfortunately, nobody did, so I gave it a little more thought.&lt;&#x2F;p&gt;
&lt;p&gt;If we could run some code at the end, even on panics, we might be able to set the length from there.
And we can, with a helper struct which applies the change when dropped.
It sounds harder for the compiler, but there&#x27;s only one way to check.
And if we scroll around the file, we find this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; The idea is: The length field in SetLenOnDrop is a local variable
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; that the optimizer will see does not alias with any stores through the Vec&amp;#39;s data
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; pointer. This is a workaround for alias analysis issue #32155
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;SetLenOnDrop&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;a mut usize&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;local_len&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; SetLenOnDrop&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;inline&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;a mut usize&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        SetLenOnDrop { local_len: *len, len: len }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;inline&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;increment_len&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;increment&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.local_len += increment;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; Drop &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;SetLenOnDrop&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;inline&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;drop&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        *&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.len = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.local_len;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The comment indicates that LLVM gets confused into thinking that modifying the vector&#x27;s data could change its length.
And that sounds exactly like our issue.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compiling-a-compiler&quot;&gt;Compiling a compiler&lt;&#x2F;h2&gt;
&lt;p&gt;I cloned the compiler repository and skimmed the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;blob&#x2F;master&#x2F;CONTRIBUTING.md&quot;&gt;contributing guide&lt;&#x2F;a&gt;.
I copied the sample configuration file and changed a couple of lines:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;diff --git 1&#x2F;config.toml.example 2&#x2F;config.toml
&lt;&#x2F;span&gt;&lt;span&gt;index 9907341633..477c558545 100644
&lt;&#x2F;span&gt;&lt;span&gt;--- 1&#x2F;config.toml.example
&lt;&#x2F;span&gt;&lt;span&gt;+++ 2&#x2F;config.toml
&lt;&#x2F;span&gt;&lt;span&gt;@@ -104,11 +104,11 @@
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; # Instead of downloading the src&#x2F;stage0.txt version of Cargo specified, use
&lt;&#x2F;span&gt;&lt;span&gt; # this Cargo binary instead to build all Rust code
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-#cargo = &amp;quot;&#x2F;path&#x2F;to&#x2F;bin&#x2F;cargo&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+cargo = &amp;quot;&#x2F;usr&#x2F;bin&#x2F;cargo&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; # Instead of downloading the src&#x2F;stage0.txt version of the compiler
&lt;&#x2F;span&gt;&lt;span&gt; # specified, use this rustc binary instead as the stage0 snapshot compiler.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-#rustc = &amp;quot;&#x2F;path&#x2F;to&#x2F;bin&#x2F;rustc&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+rustc = &amp;quot;&#x2F;usr&#x2F;bin&#x2F;rustc&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; # Flag to specify whether any documentation is built. If false, rustdoc and
&lt;&#x2F;span&gt;&lt;span&gt; # friends will still be compiled but they will not be used to generate any
&lt;&#x2F;span&gt;&lt;span&gt;@@ -250,6 +250,7 @@
&lt;&#x2F;span&gt;&lt;span&gt; # means &amp;quot;the number of cores on this machine&amp;quot;, and 1+ is passed through to the
&lt;&#x2F;span&gt;&lt;span&gt; # compiler.
&lt;&#x2F;span&gt;&lt;span&gt; #codegen-units = 1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+codegen-units = 0
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; # Whether or not debug assertions are enabled for the compiler and standard
&lt;&#x2F;span&gt;&lt;span&gt; # library. Also enables compilation of debug! and trace! logging macros.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I didn&#x27;t want to download another compiler, so I filled in the paths to mine.
The &lt;code&gt;codegen-units&lt;&#x2F;code&gt; setting makes the compiler produce code from multiple threads at once.
The trade-off involved is that the generated code is slower.
Initially, I went for an unoptimized build (which the comments advise against), but ended up cancelling it.&lt;&#x2F;p&gt;
&lt;p&gt;The way compilers are usually built, there are a couple of &lt;em&gt;stages&lt;&#x2F;em&gt;.
Stage 0 is an existing compiler, stage 1 is the compiler we are working on — built by the stage 0 one, and stage 2 is our version built by itself.
If we make the compiler generate faster — or more buggy — code, stage 1 won&#x27;t be affected, but stage 2 will.
I wasn&#x27;t planning to change anything in the compiler, so stage 1 was enough for me.&lt;&#x2F;p&gt;
&lt;p&gt;Apparently, there is a small complication: some stage 0 artefacts like &lt;code&gt;libstd&lt;&#x2F;code&gt; will still be rebuilt, triggering a cascade of rebuilds that I didn&#x27;t want.
After asking around on IRC, I found the command line I wanted:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.&#x2F;x.py --keep-stage&lt;&#x2F;span&gt;&lt;span&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --stage&lt;&#x2F;span&gt;&lt;span&gt; 1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is all described in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;blob&#x2F;master&#x2F;src&#x2F;bootstrap&#x2F;README.md&quot;&gt;bootstrapping documentation&lt;&#x2F;a&gt;, which I completely missed.
I also tried incremental builds (via &lt;code&gt;config.toml&lt;&#x2F;code&gt;, not the command line — not sure if it matters), which didn&#x27;t work out too well for me: an incremental build after touching a single file was just a tad faster than a non-incremental one including LLVM.
But there may have been something wrong with my build files, so it&#x27;s still worth trying.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;banishing-a-read&quot;&gt;Banishing a read&lt;&#x2F;h2&gt;
&lt;p&gt;There was no need to do an initial build, but I wanted to check that everything worked.
That took about 40 minutes on my laptop.
I then added the missing method to the &lt;code&gt;SetLenOnDrop&lt;&#x2F;code&gt; struct:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;inline&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;decrement_len&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;decrement&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.local_len -= decrement;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;truncate&lt;&#x2F;code&gt; took a couple of tries, but I ended up with the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;truncate&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; current_len = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.len;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;as_mut_ptr&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;offset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.len as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;isize&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Set the final length at the end, keeping in mind that
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; dropping an element might panic. Works around a missed
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; optimization, as seen in the following issue:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;51802
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; local_len = SetLenOnDrop::new(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.len);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; drop any extra elements
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;_ in len..current_len {
&lt;&#x2F;span&gt;&lt;span&gt;            local_len.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;decrement_len&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;            ptr = ptr.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;offset&lt;&#x2F;span&gt;&lt;span&gt;(-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;            ptr::drop_in_place(ptr);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code walks a pointer backwards, destroying each element.
Meanwhile, the helper struct is also keeping track of the remaining length.
The code does seem more complex (it&#x27;s counting twice), but does it work? Let&#x27;s check some assembly.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;no_mangle&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub extern fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;no_mangle&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub extern fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;bar&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;truncate&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;no_mangle&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub extern fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;baz&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;truncate&lt;&#x2F;span&gt;&lt;span&gt;(n);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The unpatched compiler version shows what we&#x27;ve already seen:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;00000000000460a0 &amp;lt;foo&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460a0:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 83 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;7f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10 00          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;cmpq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460a5:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;74 08                   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;je     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;460af &amp;lt;foo&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460a7:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;47 10 00 00 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460ae:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460af:       c3                      retq
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;00000000000460b0 &amp;lt;bar&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460b0:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 83 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;7f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10 06          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;cmpq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x6&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460b5:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;72 08                   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;jb     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;460bf &amp;lt;bar&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460b7:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;47 10 05 00 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460be:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460bf:       c3                      retq
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;00000000000460c0 &amp;lt;baz&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460c0:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 39 77 10             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;cmp    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsi&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460c4:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;76 04                   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;jbe    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;460ca &amp;lt;baz&lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xa&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460c6:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 77 10             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsi&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460ca:       c3                      retq
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   460cb:       0f 1f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44 00 00          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;nopl   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;How about the patched one?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;0000000000084d10 &amp;lt;foo&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d10:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;47 10 00 00 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;movq   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d17:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d18:       c3                      retq
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d19:       0f 1f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80 00 00 00 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;nopl   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;0000000000084d20 &amp;lt;bar&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d20:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;47 10             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d24:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 83 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;f8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;05             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;cmp    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d28:       b9 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;05 00 00 00          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ecx
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d2d:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;0f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c8             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;cmovb  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rcx
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d31:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;4f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rcx&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d35:       c3                      retq
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d36:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;66 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;2e 0f 1f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;84 00 00    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;nopw   %&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d3d:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00 00 00
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;0000000000084d40 &amp;lt;baz&amp;gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d40:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;8b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;47 10             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d44:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 39 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;f0                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;cmp    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsi&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d47:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;0f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;47 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;c6             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;cmova  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rsi&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d4b:       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 89 47 10             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mov    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;   84d4f:       c3                      retq
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;clear()&lt;&#x2F;code&gt; call works out nicely, it&#x27;s what we wanted to see (&lt;code&gt;nopl&lt;&#x2F;code&gt; is a &quot;no-operation&quot; instruction, used to align the functions) &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#zero&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
&lt;code&gt;truncate(n)&lt;&#x2F;code&gt; also seems fine: it takes the minimum of the current and new length, then writes it back.
The &lt;code&gt;truncate(5)&lt;&#x2F;code&gt; variant does the same thing, but loads &lt;code&gt;5&lt;&#x2F;code&gt; into the &lt;code&gt;ecx&lt;&#x2F;code&gt; register in an awkward way: &lt;code&gt;mov %rax, %rcx&lt;&#x2F;code&gt; might have been better.
Alas, it came out pretty well.&lt;&#x2F;p&gt;
&lt;p&gt;I also tested with a &lt;code&gt;Drop&lt;&#x2F;code&gt; type (&lt;code&gt;String&lt;&#x2F;code&gt;).
I didn&#x27;t try to make sense of the assembly output, but the new code was similar.
You can see it &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;pull&#x2F;52908#issue-205157661&quot;&gt;on GitHub&lt;&#x2F;a&gt;, if you&#x27;re curious.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wrapping-it-up&quot;&gt;Wrapping it up&lt;&#x2F;h2&gt;
&lt;p&gt;At this point I committed the code and opened a pull request on GitHub.
I got assigned a reviewer who reviewed my code in less than two hours.
He asked me to add a codegen test to make sure the compiler doesn&#x27;t revert to the worse code sequence in the future.
I&#x27;d never written one, but after looking at the existing ones, I put this up:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; compile-flags: -O
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#![&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;crate_type &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; CHECK-LABEL: @vec_clear
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;no_mangle&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;vec_clear&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; CHECK-NOT: load
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; CHECK-NOT: icmp
&lt;&#x2F;span&gt;&lt;span&gt;    x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Rust compiler produces what&#x27;s called LLVM IR as output.
It&#x27;s similar to, but more portable and higher-level than assembly language.
The IR gets passed to LLVM, which optimizes it and outputs a binary for the platform you&#x27;re targeting.
&lt;code&gt;load&lt;&#x2F;code&gt; and &lt;code&gt;icmp&lt;&#x2F;code&gt; are LLVM&#x27;s terms for &lt;code&gt;movq&lt;&#x2F;code&gt; and &lt;code&gt;cmpq&lt;&#x2F;code&gt;.
The test checks that the generated code doesn&#x27;t contain the two instructions.&lt;&#x2F;p&gt;
&lt;p&gt;To figure that out, I used the Playground to see my function&#x27;s IR:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;; Function Attrs: norecurse nounwind uwtable
&lt;&#x2F;span&gt;&lt;span&gt;define void @test_clear(%&amp;quot;alloc::vec::Vec&amp;lt;u8&amp;gt;&amp;quot;* noalias nocapture dereferenceable(24) %x) unnamed_addr #2 {
&lt;&#x2F;span&gt;&lt;span&gt;start:
&lt;&#x2F;span&gt;&lt;span&gt;  %0 = getelementptr inbounds %&amp;quot;alloc::vec::Vec&amp;lt;u8&amp;gt;&amp;quot;, %&amp;quot;alloc::vec::Vec&amp;lt;u8&amp;gt;&amp;quot;* %x, i64 0, i32 3
&lt;&#x2F;span&gt;&lt;span&gt;  %1 = load i64, i64* %0, align 8, !alias.scope !5
&lt;&#x2F;span&gt;&lt;span&gt;  %2 = icmp eq i64 %1, 0
&lt;&#x2F;span&gt;&lt;span&gt;  br i1 %2, label %&amp;quot;_ZN33_$LT$alloc..vec..Vec$LT$T$GT$$GT$5clear17hf92f022d73112116E.exit&amp;quot;, label %bb3.preheader.i.i
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;bb3.preheader.i.i:                                ; preds = %start
&lt;&#x2F;span&gt;&lt;span&gt;  store i64 0, i64* %0, align 8, !alias.scope !5
&lt;&#x2F;span&gt;&lt;span&gt;  br label %&amp;quot;_ZN33_$LT$alloc..vec..Vec$LT$T$GT$$GT$5clear17hf92f022d73112116E.exit&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;_ZN33_$LT$alloc..vec..Vec$LT$T$GT$$GT$5clear17hf92f022d73112116E.exit&amp;quot;: ; preds = %start, %bb3.preheader.i.i
&lt;&#x2F;span&gt;&lt;span&gt;  ret void
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s a mouthful, but you can find the length field address computation (&lt;code&gt;getelementptr&lt;&#x2F;code&gt;, affectionately called &lt;code&gt;gep&lt;&#x2F;code&gt;), the load and comparison, the branch and the store.
&lt;code&gt;%0&lt;&#x2F;code&gt; … &lt;code&gt;%5&lt;&#x2F;code&gt; are similar to variables, but are &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Static_single_assignment_form&quot;&gt;only assigned once&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I then tried to run my test:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.&#x2F;x.py&lt;&#x2F;span&gt;&lt;span&gt; test src&#x2F;test&#x2F;codegen&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --keep-stage&lt;&#x2F;span&gt;&lt;span&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --stage&lt;&#x2F;span&gt;&lt;span&gt; 1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But that &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;52337&quot;&gt;didn&#x27;t seem to work&lt;&#x2F;a&gt;, possibly due to me using a local compiler for stage 0 (remember those &lt;code&gt;config.toml&lt;&#x2F;code&gt; settings?).
So I crossed my fingers and pushed the code, waited for the relatively quick (half an hour) Travis tests to pass, pinged my reviewer and then it was out of my hands.
The Rust team uses &lt;a href=&quot;https:&#x2F;&#x2F;bors.tech&#x2F;&quot;&gt;bors&lt;&#x2F;a&gt; to merge one pull request at a time.
This is done to avoid cases when two PRs work independently, but not together.
The downside is that the whole process tends to be rather slow.
Someone from the Rust team takes the pull requests that seem &quot;harmless&quot;, merges them into a single one, then tries to land that.
In my case this failed a couple of times, then finally went through.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aftermath&quot;&gt;Aftermath&lt;&#x2F;h2&gt;
&lt;p&gt;My change missed the 1.29 deadline by a day, but should be included in 1.30.
After it was merged, I was finally able to send a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hyperium&#x2F;hyper&#x2F;pull&#x2F;1619&quot;&gt;pull request&lt;&#x2F;a&gt; to &lt;code&gt;hyper&lt;&#x2F;code&gt;, removing four measly (but a quarter of all!) &lt;code&gt;unsafe&lt;&#x2F;code&gt; blocks.&lt;&#x2F;p&gt;
&lt;p&gt;My changes didn&#x27;t make &lt;code&gt;hyper&lt;&#x2F;code&gt; safer &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#pitchforks-2&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, nor do I expect them to have a measurable impact on the compiled code.
But in the end, every little bit helps, while you might also call it a learning experience.
And if I managed, then so could you — so consider giving it a shot.
And if compilers aren&#x27;t your thing, there&#x27;s plenty of projects that could use a hand.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;pitchforks&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;As I&#x27;ve been known to do myself at times.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;unsafe&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Some detractors of Rust argue that, since the standard library and many crates use unsafe code, the whole language is unsafe.
&lt;code&gt;unsafe&lt;&#x2F;code&gt; is unavoidable, but it&#x27;s a declaration of &quot;Here be dragons&quot;, while you can trust the compiler to have your back for the rest of the code.
Compare that to C.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;peepholes&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Compilers have &quot;peephole optimization&quot; phases where they clean up sequences of instructions like these.
LLVM might be missing one for this specific case.
It might be an interesting exercise to analyze binaries generated by LLVM to check if this pattern occurs more often.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;intuition&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;And we&#x27;ve already seen how that goes.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;panic&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;Rust doesn&#x27;t have exceptions, except panics are totally like exceptions, but more exceptional.
You&#x27;re not supposed to panic without a good reason.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;zero&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;The extra &lt;code&gt;00&lt;&#x2F;code&gt; byte between &lt;code&gt;movq&lt;&#x2F;code&gt; and &lt;code&gt;retq&lt;&#x2F;code&gt; must be either a no-op, or part of &lt;code&gt;movq&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;pitchforks-2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Except maybe from the pitchfork mobs.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;

</content>
    </entry>
</feed>
