<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Rust on Clément Joly – Open-Source, Rust &amp; SQLite</title><link>https://joly.pw/tags/rust/</link><description>Recent content in Rust on Clément Joly – Open-Source, Rust &amp; SQLite</description><image><title>Clément Joly – Open-Source, Rust &amp; SQLite</title><url>https://joly.pw/images/open-graph-home-original.png</url><link>https://joly.pw/images/open-graph-home-original.png</link></image><generator>Hugo -- 0.154.3</generator><language>en</language><copyright>Clément Joly</copyright><lastBuildDate>Wed, 11 Mar 2026 03:32:38 +0000</lastBuildDate><atom:link href="https://joly.pw/tags/rust/index.xml" rel="self" type="application/rss+xml"/><item><title>Rust Crates</title><link>https://joly.pw/open-source/crates/</link><pubDate>Sun, 30 Mar 2025 00:00:23 +0200</pubDate><guid>https://joly.pw/open-source/crates/</guid><description>&lt;p&gt;List of my Rust crates.&lt;/p&gt;</description><content:encoded><![CDATA[<p>List of my Rust crates.</p>
<div class="projects">





<div class="projects-inner">

<article class="project-entry" onclick="location.href='https:\/\/cj.rs\/rusqlite_migration\/';" style="cursor:pointer;">
  <header class="entry-header">
    <h3>
        <a class="" 
            aria-label="post link to rusqlite_migration"
            data-goatcounter-click="ext-rusqlite_migration"
            data-goatcounter-referrer="crates"
            href="https://cj.rs/rusqlite_migration/">Rusqlite Migration</a>
    </h3>
  </header>
  <section class="entry-content">
    <p>↕️ Simple database schema migration library for rusqlite, written with performance in mind.</p>
  </section>
  <footer class="entry-footer project-footer">
      <p>
        <span class="project-circle">
        <svg  width="11" height="12">
          <circle cx="4" cy="7.5" r="4" fill="#dea584" />
        </svg>
        </span>
        Rust
        <span>&nbsp;★&nbsp;104</span>
      </p>
  </footer>
</article>


</div>


</div>

<h2 id="work-in-progress">Work in progress</h2>
<div class="projects">





<div class="projects-inner">

<article class="project-entry" onclick="location.href='https:\/\/github.com\/cljoly\/pure-sixel#readme';" style="cursor:pointer;">
  <header class="entry-header">
    <h3>
        <a class="" 
            aria-label="post link to pure-sixel"
            data-goatcounter-click="ext-pure-sixel"
            data-goatcounter-referrer="crates"
            href="https://github.com/cljoly/pure-sixel#readme">Pure Sixel</a>
    </h3>
  </header>
  <section class="entry-content">
    <p>Pure Rust sixel encoder</p>
  </section>
  <footer class="entry-footer project-footer">
      <p>
        <span class="project-circle">
        <svg  width="11" height="12">
          <circle cx="4" cy="7.5" r="4" fill="#dea584" />
        </svg>
        </span>
        Rust
        
      </p>
  </footer>
</article>


</div>


</div>]]></content:encoded></item><item><title>Rusqlite Snapshot Testing</title><link>https://joly.pw/rusqlite-snapshot-testing/</link><pubDate>Sat, 29 Mar 2025 17:32:05 +0000</pubDate><guid>https://joly.pw/rusqlite-snapshot-testing/</guid><description>Snapshot testing tool for rusqlite</description><content:encoded><![CDATA[
<p style="display: flex; justify-content: space-between">
  <a href="https://github.com/cljoly/rusqlite-snapshot-testing" data-goatcounter-click="ext-github-rusqlite-snapshot-testing" data-goatcounter-title="cljoly/rusqlite-snapshot-testing">
    <span class="svgicon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
    stroke-linecap="round" stroke-linejoin="round">
    <path
        d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22">
    </path>
</svg></span>&nbsp;cljoly/rusqlite-snapshot-testing
  </a>
  <a class="badges" href="https://github.com/cljoly/rusqlite-snapshot-testing" data-goatcounter-click="ext-stargithub-rusqlite-snapshot-testing" data-goatcounter-title="stars cljoly/rusqlite-snapshot-testing">
    <img src="https://img.shields.io/github/stars/cljoly/rusqlite-snapshot-testing?style=social" alt="Github stars for rusqlite-snapshot-testing">
  </a>
</p>


<div class="badges">


<p><a href="https://docs.rs/rusqlite-snapshot-testing">
<img alt="docs.rs" loading="lazy" src="https://img.shields.io/docsrs/rusqlite-snapshot-testing"></a>
<a href="https://crates.io/crates/rusqlite-snapshot-testing">
<img alt="Crates.io" loading="lazy" src="https://img.shields.io/crates/v/rusqlite-snapshot-testing"></a>

</div>

</p>
<p>Tool to perform snapshot testing on an SQLite database, using <a href="https://crates.io/crates/rusqlite">rusqlite</a>.</p>
<p>The goal is to expose both data and the schema in the snapshots. It is also compatible with <a href="https://insta.rs">Insta Snapshots</a></p>
<p><strong>This is experimental software, expect breaking changes between 0.x versions, consistent with the semver rules for Rust.</strong></p>
<h2 id="background-reading-on-snapshot-testing">Background reading on snapshot testing.</h2>
<ul>
<li><a href="https://ianthehenry.com/posts/my-kind-of-repl/">https://ianthehenry.com/posts/my-kind-of-repl/</a></li>
<li><a href="https://tigerbeetle.com/blog/2024-05-14-snapshot-testing-for-the-masses/">https://tigerbeetle.com/blog/2024-05-14-snapshot-testing-for-the-masses/</a></li>
<li><a href="https://blog.janestreet.com/the-joy-of-expect-tests/">https://blog.janestreet.com/the-joy-of-expect-tests/</a></li>
</ul>
]]></content:encoded></item><item><title>Rusqlite Changelog</title><link>https://joly.pw/rusqlite_migration_docs/changelog/</link><pubDate>Mon, 24 Mar 2025 20:32:05 +0000</pubDate><guid>https://joly.pw/rusqlite_migration_docs/changelog/</guid><description>&lt;p&gt;Release notes for the &lt;a href="https://cj.rs/rusqlite_migration"&gt;rusqlite_migration library&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="version-241"&gt;Version 2.4.1&lt;/h2&gt;
&lt;h3 id="documentation"&gt;Documentation&lt;/h3&gt;
&lt;p&gt;Attempt to fix the docs.rs build which started failing in 2.4.0.&lt;/p&gt;
&lt;h3 id="dependencies"&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;Update some dev dependencies, see git history for details.&lt;/p&gt;
&lt;h2 id="version-240"&gt;Version 2.4.0&lt;/h2&gt;
&lt;h3 id="dependencies-1"&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;Rusqlite was updated from 0.37.0 to 0.38.0.
Please see &lt;a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.38.0"&gt;the release notes for 0.38.0&lt;/a&gt;, there are a few breaking changes in this one.&lt;/p&gt;
&lt;p&gt;Update other dev dependencies, see git history for details.&lt;/p&gt;
&lt;h3 id="features"&gt;Features&lt;/h3&gt;
&lt;p&gt;Rusqlite 0.38 makes the cache statement optional. This feature was used for &lt;a href="https://docs.rs/rusqlite_migration/2.3.0/rusqlite_migration/struct.M.html#method.foreign_key_check"&gt;foreign key checks&lt;/a&gt;. The &lt;code&gt;rusqlite_migration&lt;/code&gt; library does not enable any features from rusqlite, not even the default one. This way, downstream users can freely chose which feature to enable based on their needs. As a result, &lt;code&gt;rusqlite_migration&lt;/code&gt; now handles statement caching for foreign key checks internally now. As side benefit, this also makes caching more efficient: the prepared statement is kept for the minimum time where it is needed and freed immediately, without taking space in the global cache used by rusqlite.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Release notes for the <a href="https://cj.rs/rusqlite_migration">rusqlite_migration library</a>.</p>
<h2 id="version-241">Version 2.4.1</h2>
<h3 id="documentation">Documentation</h3>
<p>Attempt to fix the docs.rs build which started failing in 2.4.0.</p>
<h3 id="dependencies">Dependencies</h3>
<p>Update some dev dependencies, see git history for details.</p>
<h2 id="version-240">Version 2.4.0</h2>
<h3 id="dependencies-1">Dependencies</h3>
<p>Rusqlite was updated from 0.37.0 to 0.38.0.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.38.0">the release notes for 0.38.0</a>, there are a few breaking changes in this one.</p>
<p>Update other dev dependencies, see git history for details.</p>
<h3 id="features">Features</h3>
<p>Rusqlite 0.38 makes the cache statement optional. This feature was used for <a href="https://docs.rs/rusqlite_migration/2.3.0/rusqlite_migration/struct.M.html#method.foreign_key_check">foreign key checks</a>. The <code>rusqlite_migration</code> library does not enable any features from rusqlite, not even the default one. This way, downstream users can freely chose which feature to enable based on their needs. As a result, <code>rusqlite_migration</code> now handles statement caching for foreign key checks internally now. As side benefit, this also makes caching more efficient: the prepared statement is kept for the minimum time where it is needed and freed immediately, without taking space in the global cache used by rusqlite.</p>
<h3 id="other">Other</h3>
<ul>
<li>Use scoped GitHub tokens in actions, with as little privileges as possible.</li>
<li>Improve test build time by removing some unused optional deps.</li>
<li>Update most dependencies after a cooldown (this does not apply to security updates).</li>
<li>Errors don’t use debug output anymore, they should be more friendly to humans. This is not considered a breaking change because <code>Dislay</code> of errors is meant for human consuption and not for flow control in the program.</li>
</ul>
<h2 id="version-230">Version 2.3.0</h2>
<h3 id="dependencies-2">Dependencies</h3>
<p>Rusqlite was updated from 0.36.0 to 0.37.0.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.37.0">the release notes for 0.37.0</a>.</p>
<h3 id="other-1">Other</h3>
<ul>
<li>Misc. clippy fixes</li>
<li>Minor improvements to the example in the Readme</li>
</ul>
<h2 id="version-220">Version 2.2.0</h2>




  
  
  
  

  <div class="alert alert-note">
    <p class="alert-heading">
      ℹ️
      
        Note
      
    </p>
    <p>The code of this version is identical to <a href="#version-220-beta-1">Version 2.2.0 Beta 1</a></p>
  </div>



<h3 id="features-1">Features</h3>
<ul>
<li>Implement the <code>Display</code> trait for <code>M</code>. This makes it easier to print errors pertaining to a particular migration (this feature is planned for the future, in the context of more extensive migration checks)</li>
</ul>
<h3 id="dependencies-3">Dependencies</h3>
<p>Rusqlite was updated from 0.35.0 to 0.36.0.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.36.0">the release notes for 0.36.0</a>.</p>
<h3 id="other-2">Other</h3>
<ul>
<li>Update development dependencies</li>
<li>Improve tests to cover more cases, in particular around downward migrations</li>
<li>Add docs.rs link to Cargo metadata</li>
<li>Fix clippy warning in rust 1.87.0</li>
</ul>
<h2 id="version-220-beta-1">Version 2.2.0 Beta 1</h2>
<h3 id="features-2">Features</h3>
<ul>
<li>Implement the <code>Display</code> trait for <code>M</code>. This makes it easier to print errors pertaining to a particular migration (this feature is planned for the future, in the context of more extensive migration checks)</li>
</ul>
<h3 id="dependencies-4">Dependencies</h3>
<p>Rusqlite was updated from 0.35.0 to 0.36.0.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.36.0">the release notes for 0.36.0</a>.</p>
<h3 id="other-3">Other</h3>
<ul>
<li>Update development dependencies</li>
<li>Improve tests to cover more cases, in particular around downward migrations</li>
<li>Add docs.rs link to Cargo metadata</li>
<li>Fix clippy warning in rust 1.87.0</li>
</ul>
<h2 id="version-210">Version 2.1.0</h2>
<h3 id="dependencies-5">Dependencies</h3>
<p>Rusqlite was updated from 0.34.0 to 0.34.0.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.35.0">the release notes for 0.35.0</a>.</p>
<h2 id="version-200">Version 2.0.0</h2>
<h3 id="breaking-changes">Breaking changes</h3>
<h4 id="remove-the-alpha-async-tokio-rusqlite-feature">Remove the <code>alpha-async-tokio-rusqlite</code> Feature</h4>
<p>As the name of the feature suggest, we have had experimental support for async using tokio for a while now. Supporting that feature has been quite a big burden, introducing some duplicated code in the <code>AsyncMigrations</code> struct in particular, as well as a whole set of very similar tests. Plus the benefit of async is limited here, because everything gets executed in a blocking fashion in sqlite anyway.</p>
<p>It turns out that we don’t need the async support in rusqlite_migration for folks to use async libraries. For instance, with tokio-rusqlite, you can define migrations like in the sync context and run:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span>    <span style="color:#e06c75">async_conn</span>
</span></span><span style="display:flex;"><span>        .<span style="color:#e06c75">call_unwrap</span>(<span style="color:#56b6c2">|</span><span style="color:#e06c75">conn</span><span style="color:#56b6c2">|</span> <span style="color:#e06c75">MIGRATIONS</span>.<span style="color:#e06c75">to_latest</span>(<span style="color:#e06c75">conn</span>))
</span></span><span style="display:flex;"><span>        .<span style="color:#c678dd">await</span><span style="color:#56b6c2">?</span>;
</span></span></code></pre></div><p>See <a href="https://github.com/cljoly/rusqlite_migration/blob/master/examples/async/src/main.rs">the updated async example</a> for details, in particular why it’s fine to call <a href="https://docs.rs/tokio-rusqlite/0.6.0/tokio_rusqlite/struct.Connection.html#method.call_unwrap">a method</a> with unwrap in its name.</p>
<h4 id="make-the-builder-finalizer-method-not-generic">Make the Builder <code>Finalizer</code> Method Not Generic</h4>
<p>On a related note, now that we have removed the <code>AsyncMigrations</code> (see the section right above) struct, we only have <code>Migrations</code> so there is no need for the <code>MigrationsBuilder.finalize</code> method to be generic. Thus we removed the generic argument. To update your code, you can just do this:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span><span style="color:#e06c75">-        .finalize::&lt;Migrations&gt;());
</span></span></span><span style="display:flex;"><span><span style="color:#98c379;font-weight:bold">+        .finalize());
</span></span></span></code></pre></div><h4 id="remove-migrationsnew_iter">Remove <code>Migrations::new_iter</code></h4>
<p>This function has been deprecated for a while now, remove it as a part of the major version bump. You can use the standard <code>FromIter</code> trait implementation instead.</p>
<h3 id="behavior-change">Behavior Change</h3>
<ul>
<li>When the <a href="https://www.sqlite.org/fileformat.html#user_version_number">user version field</a> is altered by other code in your application, we are now returning an explicit error (<code>Error::InvalidUserVersion</code>) when this can be detected. Previously, the library would silently misbehave.</li>
</ul>
<h3 id="features-3">Features</h3>
<ul>
<li>Add the new <a href="https://docs.rs/rusqlite_migration/2.0.0-beta.1/rusqlite_migration/struct.Migrations.html#method.from_slice"><code>Migrations::from_slice</code></a> constructor, which is <code>const</code> and takes a slice, so that it can be constructed in global constant, without using <code>LazyLock</code> or similar. Internally, this is possible because we now use a <a href="https://doc.rust-lang.org/std/borrow/enum.Cow.html"><code>Cow</code></a> structure to hold migrations.</li>
<li>Add <a href="https://docs.rs/rusqlite_migration/2.0.0-beta.1/rusqlite_migration/struct.Migrations.html#method.pending_migrations"><code>Migrations::pending_migrations</code></a> which returns the number of migrations that would be applied. This is mostly useful to take a backup of the database prior to applying migrations (and do nothing if no migrations will be applied).</li>
</ul>
<h3 id="dependencies-6">Dependencies</h3>
<p>Rusqlite was updated from 0.32.1 to 0.34.0.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.34.0">the release notes for 0.34.0</a> and
<a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.33.0">the release notes for 0.33.0</a>.
Tokio Rusqlite was removed as a dependency.</p>
<h3 id="minimum-rust-version">Minimum Rust Version</h3>
<p>Rust 1.84.</p>
<p>Moving forward, we expect to keep this aligned with rusqlite itself, now that it has a <a href="https://github.com/rusqlite/rusqlite?tab=readme-ov-file#minimum-supported-rust-version-msrv">policy</a> (introduced in <a href="https://github.com/rusqlite/rusqlite/pull/1576">october 2024</a>).</p>
<h2 id="version-200-beta-1">Version 2.0.0 Beta 1</h2>
<h3 id="features-4">Features</h3>
<ul>
<li>Add the new <a href="https://docs.rs/rusqlite_migration/2.0.0-beta.1/rusqlite_migration/struct.Migrations.html#method.from_slice"><code>Migrations::from_slice</code></a> constructor, which is <code>const</code> and takes a slice, so that it can be constructed in global constant, without using <code>LazyLock</code> or similar. Internally, this is possible because we now use a <a href="https://doc.rust-lang.org/std/borrow/enum.Cow.html"><code>Cow</code></a> structure to hold migrations.</li>
<li>Add <a href="https://docs.rs/rusqlite_migration/2.0.0-beta.1/rusqlite_migration/struct.Migrations.html#method.pending_migrations"><code>Migrations::pending_migrations</code></a> which returns the number of migrations that would be applied. This is mostly useful to take a backup of the database prior to applying migrations (and do nothing if no migrations will be applied).</li>
</ul>
<h2 id="version-200-alpha-1">Version 2.0.0 Alpha 1</h2>
<h3 id="breaking-changes-1">Breaking changes</h3>
<h4 id="remove-the-alpha-async-tokio-rusqlite-feature-1">Remove the <code>alpha-async-tokio-rusqlite</code> Feature</h4>
<p>As the name of the feature suggest, we have had experimental support for async using tokio for a while now. Supporting that feature has been quite a big burden, introducing some duplicated code in the <code>AsyncMigrations</code> struct in particular, as well as a whole set of very similar tests. Plus the benefit of async is limited here, because everything gets executed in a blocking fashion in sqlite anyway.</p>
<p>It turns out that we don’t need the async support in rusqlite_migration for folks to use async libraries. For instance, with tokio-rusqlite, you can define migrations like in the sync context and run:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span>    <span style="color:#e06c75">async_conn</span>
</span></span><span style="display:flex;"><span>        .<span style="color:#e06c75">call_unwrap</span>(<span style="color:#56b6c2">|</span><span style="color:#e06c75">conn</span><span style="color:#56b6c2">|</span> <span style="color:#e06c75">MIGRATIONS</span>.<span style="color:#e06c75">to_latest</span>(<span style="color:#e06c75">conn</span>))
</span></span><span style="display:flex;"><span>        .<span style="color:#c678dd">await</span><span style="color:#56b6c2">?</span>;
</span></span></code></pre></div><p>See <a href="https://github.com/cljoly/rusqlite_migration/blob/master/examples/async/src/main.rs">the updated async example</a> for details, in particular why it’s fine to call <a href="https://docs.rs/tokio-rusqlite/0.6.0/tokio_rusqlite/struct.Connection.html#method.call_unwrap">a method</a> with unwrap in its name.</p>
<h4 id="make-the-builder-finalizer-method-not-generic-1">Make the Builder <code>Finalizer</code> Method Not Generic</h4>
<p>On a related note, now that we have removed the <code>AsyncMigrations</code> (see the section right above) struct, we only have <code>Migrations</code> so there is no need for the <code>MigrationsBuilder.finalize</code> method to be generic. Thus we removed the generic argument. To update your code, you can just do this:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span><span style="color:#e06c75">-        .finalize::&lt;Migrations&gt;());
</span></span></span><span style="display:flex;"><span><span style="color:#98c379;font-weight:bold">+        .finalize());
</span></span></span></code></pre></div><h4 id="remove-migrationsnew_iter-1">Remove <code>Migrations::new_iter</code></h4>
<p>This function has been deprecated for a while now, remove it as a part of the major version bump. You can use the standard <code>FromIter</code> trait implementation instead.</p>
<h3 id="behavior-change-1">Behavior Change</h3>
<ul>
<li>When the <a href="https://www.sqlite.org/fileformat.html#user_version_number">user version field</a> is altered by other code in your application, we are now returning an explicit error (<code>Error::InvalidUserVersion</code>) when this can be detected. Previously, the library would silently misbehave.</li>
</ul>
<h3 id="dependencies-7">Dependencies</h3>
<p>Rusqlite was updated from 0.32.1 to 0.34.0.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.34.0">the release notes for 0.34.0</a> and
<a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.33.0">the release notes for 0.33.0</a>.
Tokio Rusqlite was removed as a dependency.</p>
<h3 id="features-5">Features</h3>
<ul>
<li><code>Migrations::new</code> is now <code>const</code></li>
</ul>
<h3 id="minimum-rust-version-1">Minimum Rust Version</h3>
<p>Rust 1.84.</p>
<p>Moving forward, we expect to keep this aligned with rusqlite itself, now that it has a <a href="https://github.com/rusqlite/rusqlite?tab=readme-ov-file#minimum-supported-rust-version-msrv">policy</a> (introduced in <a href="https://github.com/rusqlite/rusqlite/pull/1576">october 2024</a>).</p>
<h2 id="version-131">Version 1.3.1</h2>
<p>The only change is a fix to the deps.rs badge in the documentation.</p>
<h2 id="version-130">Version 1.3.0</h2>




  
  
  
  

  <div class="alert alert-note">
    <p class="alert-heading">
      ℹ️
      
        Note
      
    </p>
    <p>The code of this version is identical to <a href="#version-130-beta-1">Version 1.3.0 Beta 1</a></p>
  </div>



<p>Rusqlite was updated from 0.31.0 to 0.32.1.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.32.0">the release notes for 0.32.0</a> and
<a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.32.1">for 0.32.1</a>.
Tokio Rusqlite was updated from 0.5.1 to 0.6.0.
Please see the <a href="https://github.com/programatik29/tokio-rusqlite/releases/tag/v0.6.0">release notes</a>.</p>
<h3 id="minimum-rust-version-2">Minimum Rust Version</h3>
<p>Rust 1.77</p>
<h3 id="documentation-1">Documentation</h3>
<p>Various documentation improvements and clarification. In particular, call out that if a rusqlite error is encountered during a migration, the next migrations in the list are not applied.</p>
<h3 id="other-4">Other</h3>
<ul>
<li>Apply minor or patch updates to the dependencies</li>
<li>Update development dependencies</li>
<li>Make CI testing more reproducible by forcing the use of Cargo.lock</li>
</ul>
<h2 id="version-130-beta-1">Version 1.3.0 Beta 1</h2>
<p>This reintroduces the async features temporarily removed from <a href="#version-130-alpha-without-tokio-1">Version 1.3.0 Alpha-Without-Tokio 1</a></p>
<p>Rusqlite was updated from 0.31.0 to 0.32.1.
Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.32.0">the release notes for 0.32.0</a> and
<a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.32.1">for 0.32.1</a>.
Tokio Rusqlite was updated from 0.5.1 to 0.6.0.
Please see the <a href="https://github.com/programatik29/tokio-rusqlite/releases/tag/v0.6.0">release notes</a>.</p>
<h3 id="minimum-rust-version-3">Minimum Rust Version</h3>
<p>Rust 1.77</p>
<h3 id="documentation-2">Documentation</h3>
<p>Various documentation improvements and clarification. In particular, call out that if a rusqlite error is encountered during a migration, the next migrations in the list are not applied.</p>
<h3 id="other-5">Other</h3>
<ul>
<li>Apply minor or patch updates to the dependencies</li>
<li>Update development dependencies</li>
<li>Make CI testing more reproducible by forcing the use of Cargo.lock</li>
</ul>
<h2 id="version-130-alpha-without-tokio-1">Version 1.3.0 Alpha-Without-Tokio 1</h2>
<h3 id="major-changes">Major Changes</h3>
<p>This is an alpha version to start integrating rusqlite 0.32.1. Unfortunately, at this time, tokio-rusqlite is did not update to rusqlite 0.32.1. So we are temporarily removing the async features, while we figure out a way to bring them back. <strong>To be clear, we intend to support the async features going forward, this is a temporary change in a specifically tagged version</strong>.</p>
<p>Rusqlite was updated from 0.31.0 to 0.32.1. Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.32.0">the release notes for 0.32.0</a> and
<a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.32.1">for 0.32.1</a></p>
<h3 id="minimum-rust-version-4">Minimum Rust Version</h3>
<p>Rust 1.77</p>
<h3 id="documentation-3">Documentation</h3>
<p>Various documentation improvements and clarification. In particular, call out that if a rusqlite error is encountered during a migration, the next migrations in the list are not applied.</p>
<h3 id="other-6">Other</h3>
<ul>
<li>Apply minor or patch updates to the dependencies</li>
<li>Update development dependencies</li>
<li>Make CI testing more reproducible by forcing the use of Cargo.lock</li>
</ul>
<h2 id="version-120">Version 1.2.0</h2>
<p><em>Same code as version 1.2.0-beta.1</em></p>
<h3 id="documentation-4">Documentation</h3>
<ul>
<li>Improved the badges a little bit</li>
</ul>
<h2 id="version-120-beta-1">Version 1.2.0 Beta 1</h2>
<p>Small release, mainly to update dependencies.</p>
<h3 id="minimum-rust-version-5">Minimum Rust Version</h3>
<p>Now using edition 2021, but the minimum rust version is still 1.70</p>
<h3 id="new-features">New Features</h3>
<p>No new features.</p>
<h3 id="other-7">Other</h3>
<ul>
<li>Update rusqlite to 0.31</li>
<li>Update various development dependencies</li>
<li>Improve CI build time</li>
<li>Impove documentation</li>
<li>Fix some broken examples</li>
</ul>
<h3 id="see-also">See also</h3>
<p>Rusqlite was updated from 0.30 to 0.31. Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.31.0">its release notes</a></p>
<h2 id="version-110">Version 1.1.0</h2>
<p><em>Same code as version 1.1.0-beta.1</em></p>
<h3 id="minimum-rust-version-6">Minimum Rust Version</h3>
<p>Rust 1.70</p>
<h3 id="new-features-1">New Features</h3>
<ul>
<li>Support for tokio-rusqlite behind the feature named <code>alpha-async-tokio-rusqlite</code>thanks to <a href="https://github.com/czocher">@czocher</a>. See <a href="https://github.com/cljoly/rusqlite_migration/tree/c54951d22691432fbfd511cc68f1c5b8a2306737/examples/async">the example</a>. This feature is alpha, meaning that compatibility in future minor versions is not guaranteed.</li>
<li>Create migrations from directories holding SQL files thanks to <a href="https://github.com/czocher">@czocher</a>. See <a href="https://github.com/cljoly/rusqlite_migration/tree/af4da527ff75e3b8c089d2300cab7fbe66096411/examples/from-directory">the example</a>.</li>
<li>Add up/down hooks to run custom Rust code during migrations (<a href="https://github.com/cljoly/rusqlite_migration/pull/28">PR</a> thanks to <a href="https://github.com/matze">@matze</a>)</li>
<li>Add foreign_key_check method to migrations (<a href="https://github.com/cljoly/rusqlite_migration/pull/20">PR</a> thanks to <a href="https://github.com/Jokler">@Jokler</a>)</li>
<li>Make <code>Migration</code> functions const (<a href="https://github.com/cljoly/rusqlite_migration/pull/19">PR</a> thanks to <a href="https://github.com/fkaa">@fkaa</a>)</li>
<li>Make <code>Migrations</code> serializable (using the Debug serializer) with <a href="https://insta.rs">insta</a>.</li>
</ul>
<h3 id="depreciation">Depreciation</h3>
<ul>
<li>Mark <code>Migrations::from_iter</code> as deprecated</li>
</ul>
<h3 id="other-8">Other</h3>
<ul>
<li>Documentation improvements
<ul>
<li>Repository metadata improvements</li>
</ul>
</li>
<li>Code quality improvements
<ul>
<li>Introduce cargo mutants &amp; fix bugs found</li>
<li>Clippy warning fixes and other linter improvements</li>
<li>Report on test coverage &amp; improve test coverage</li>
<li>Add benchmarks</li>
</ul>
</li>
<li>Made errors returned more precise</li>
<li>Updated dependencies</li>
</ul>
<h3 id="see-also-1">See also</h3>
<p>Rusqlite was updated from 0.29.0 to 0.30.0. Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.30.0">its release notes</a></p>
<h2 id="version-110-beta-1">Version 1.1.0 Beta 1</h2>
<p><strong>⚠️ The APIs exposed in this version may be unstable.</strong></p>
<p>Summing up all the changes from the previous Alpha versions.</p>
<h3 id="minimum-rust-version-7">Minimum Rust Version</h3>
<p>Rust 1.70</p>
<h3 id="new-features-2">New Features</h3>
<ul>
<li>Support for tokio-rusqlite behind the feature named <code>alpha-async-tokio-rusqlite</code>thanks to <a href="https://github.com/czocher">@czocher</a>. See <a href="https://github.com/cljoly/rusqlite_migration/tree/c54951d22691432fbfd511cc68f1c5b8a2306737/examples/async">the example</a>. This feature is alpha, meaning that compatibility in future minor versions is not guaranteed.</li>
<li>Create migrations from directories holding SQL files thanks to <a href="https://github.com/czocher">@czocher</a>. See <a href="https://github.com/cljoly/rusqlite_migration/tree/af4da527ff75e3b8c089d2300cab7fbe66096411/examples/from-directory">the example</a>.</li>
<li>Add up/down hooks to run custom Rust code during migrations (<a href="https://github.com/cljoly/rusqlite_migration/pull/28">PR</a> thanks to <a href="https://github.com/matze">@matze</a>)</li>
<li>Add foreign_key_check method to migrations (<a href="https://github.com/cljoly/rusqlite_migration/pull/20">PR</a> thanks to <a href="https://github.com/Jokler">@Jokler</a>)</li>
<li>Make <code>Migration</code> functions const (<a href="https://github.com/cljoly/rusqlite_migration/pull/19">PR</a> thanks to <a href="https://github.com/fkaa">@fkaa</a>)</li>
<li>Make <code>Migrations</code> serializable (using the Debug serializer) with <a href="https://insta.rs">insta</a>.</li>
</ul>
<h3 id="depreciation-1">Depreciation</h3>
<ul>
<li>Mark <code>Migrations::from_iter</code> as deprecated</li>
</ul>
<h3 id="other-9">Other</h3>
<ul>
<li>Documentation improvements
<ul>
<li>Repository metadata improvements</li>
</ul>
</li>
<li>Code quality improvements
<ul>
<li>Introduce cargo mutants &amp; fix bugs found</li>
<li>Clippy warning fixes and other linter improvements</li>
<li>Report on test coverage &amp; improve test coverage</li>
<li>Add benchmarks</li>
</ul>
</li>
<li>Made errors returned more precise</li>
<li>Updated dependencies</li>
</ul>
<h3 id="see-also-2">See also</h3>
<p>Rusqlite was updated from 0.29.0 to 0.30.0. Please see <a href="https://github.com/rusqlite/rusqlite/releases/tag/v0.30.0">its release notes</a></p>
<h2 id="version-110-alpha-2">Version 1.1.0 Alpha 2</h2>
<p><strong>⚠️ The APIs exposed in this version may be unstable.</strong></p>
<h3 id="minimum-rust-version-8">Minimum Rust Version</h3>
<p>Rust 1.64</p>
<h3 id="new-features-3">New Features</h3>
<ul>
<li>Create migrations from directories holding SQL files. See <a href="https://github.com/cljoly/rusqlite_migration/tree/af4da527ff75e3b8c089d2300cab7fbe66096411/examples/from-directory">the example</a>.</li>
</ul>
<h3 id="depreciation-2">Depreciation</h3>
<ul>
<li>Mark <code>Migrations::from_iter</code> as deprecated</li>
</ul>
<h3 id="other-10">Other</h3>
<ul>
<li>Documentation improvements</li>
<li>Code quality improvements
<ul>
<li>Introduce cargo mutants &amp; fix bugs found</li>
<li>Clippy warning fixes</li>
<li>Report on test coverage &amp; improve test coverage</li>
<li>Add benchmarks</li>
</ul>
</li>
<li>Made errors returned more precise</li>
<li>Update dependencies</li>
</ul>
<h2 id="version-110-alpha-1">Version 1.1.0 Alpha 1</h2>
<p><strong>⚠️ The APIs exposed in this version may be unstable.</strong></p>
<h3 id="minimum-rust-version-9">Minimum Rust Version</h3>
<p>Rust 1.61</p>
<h3 id="new-features-4">New Features</h3>
<ul>
<li>Add up/down hooks to run custom Rust code during migrations (<a href="https://github.com/cljoly/rusqlite_migration/pull/28">PR</a> thanks to <a href="https://github.com/matze">@matze</a>)
<ul>
<li>The purpose of this release is to get feedback on the new API. Please feel free to comment on <a href="https://github.com/cljoly/rusqlite_migration/discussions/36">this discussion</a>!</li>
</ul>
</li>
<li>Add foreign_key_check method to migrations (<a href="https://github.com/cljoly/rusqlite_migration/pull/20">PR</a> thanks to <a href="https://github.com/Jokler">@Jokler</a>)
<ul>
<li>Please beware of the <a href="https://github.com/cljoly/rusqlite_migration/issues/4#issuecomment-1166363260">follow up work needed on this</a></li>
</ul>
</li>
<li>Make <code>Migration</code> functions const (<a href="https://github.com/cljoly/rusqlite_migration/pull/19">PR</a> thanks to <a href="https://github.com/fkaa">@fkaa</a>)</li>
</ul>
<h3 id="other-11">Other</h3>
<ul>
<li>CI improvements</li>
<li>Linter improvements</li>
<li>Repository metadata improvements</li>
<li>Documentation improvements</li>
<li>Dev dependencies update (not dependencies of the library when used in another crate)</li>
</ul>
<h2 id="version-102">Version 1.0.2</h2>
<h3 id="bug-fix">Bug fix</h3>
<ul>
<li>fix: adapt to rusqlite 0.29 and tighten dependency requirements for rusqlite (see <a href="https://github.com/cljoly/rusqlite_migration/issues/68#issuecomment-1485795284">this discussion</a>)</li>
</ul>
<h2 id="version-101">Version 1.0.1</h2>
<h3 id="bug-fix-1">Bug Fix</h3>
<ul>
<li>fix: error instead of panicking on higher migration level (see commit ad57d92d1677420eb81c4e25635be1884f9b7ce7)</li>
</ul>
<h3 id="other-12">Other</h3>
<ul>
<li>Documentation improvements</li>
</ul>
<h2 id="version-100">Version 1.0.0</h2>
<h3 id="breaking-changes-2">Breaking changes</h3>
<ul>
<li>Remove deprecated symbols (<code>Migrations.latest</code>, <code>SchemaVersionError::MigrateToLowerNotSupported</code>)</li>
</ul>
<h3 id="other-13">Other</h3>
<ul>
<li>Documentation improvements</li>
</ul>
<h2 id="version-051">Version 0.5.1</h2>
<h3 id="potentially-breaking-changes">Potentially Breaking Changes</h3>
<ul>
<li>Update the <code>rusqlite</code> crate (to protect agaisnt <a href="https://rustsec.org/advisories/RUSTSEC-2020-0014.html">RUSTSEC-2020-0014</a>)</li>
</ul>
<h3 id="other-14">Other</h3>
<ul>
<li>Improve the documentation</li>
</ul>
<h2 id="version-050">Version 0.5.0</h2>
<ul>
<li>Update the <code>env_logger</code> dependency</li>
<li>Improve the documentation</li>
</ul>
<h2 id="version-041--042">Version 0.4.1 / 0.4.2</h2>
<ul>
<li>Update documentation</li>
</ul>
<h2 id="version-040">Version 0.4.0</h2>
<h3 id="new-features-5">New features</h3>
<ul>
<li>Add downward migrations, i.e. migrations to go to past schema version of the database. Thanks @MightyPork!</li>
<li>Unsafe code is now forbidden.</li>
</ul>
<h3 id="breaking-changes-3">Breaking changes</h3>
<ul>
<li>Rename <code>latest</code> to <code>to_latest</code>. The old symbol is deprecated and will be removed eventually.</li>
<li>An error is now returned when a migration is attempted while no migrations exist.</li>
</ul>
<h3 id="other-15">Other</h3>
<ul>
<li>Improve general rust API documentation.</li>
<li>Generate parts of the readme based on rust comments, for increased consistency with the docs.rs content.</li>
<li>Various refactoring and clean-ups.</li>
</ul>
<h2 id="version-031">Version 0.3.1</h2>
<p>Fix in readme, for crates.io</p>
<h2 id="version-03">Version 0.3</h2>
<h3 id="new-features-6">New features</h3>
<ul>
<li>Multi line sql statements like:
<pre tabindex="0"><code>M::up(r#&#34;
CREATE TABLE t1(a, b);
CREATE TABLE t2(a, b);
&#34;#)
</code></pre>are now fully supported</li>
</ul>
<h3 id="other-16">Other</h3>
<ul>
<li>Various doc &amp; CI improvements</li>
<li>Fix a case of failure with silent errors.</li>
</ul>
]]></content:encoded></item><item><title>Cargo Info in Neovim, or How Simple Features Go a Long Way</title><link>https://joly.pw/blog/cargo-info-in-neovim/</link><pubDate>Mon, 21 Oct 2024 22:39:34 +0100</pubDate><guid>https://joly.pw/blog/cargo-info-in-neovim/</guid><description>Integrate Vim and Cargo info with just a few lines of Lua using keywordprg.</description><content:encoded><![CDATA[



  
  
  
  

  <div class="alert alert-tldr">
    <p class="alert-heading">
      ⚡
      
        TL;DR
      
    </p>
    <p>Open <code>cargo info</code> in Vim or neovim for the package under the cursor using <a href="#introducing-keywordprg">these 4 lines of Lua</a>.</p>
  </div>



<h2 id="cargo-info">Cargo info</h2>
<p><a href="https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#whats-in-1820-stable">Rust 1.82</a> was released a couple of days ago.
It’s packed with improvements, but one in particular caught my eye.
Cargo now has a <code>info</code> sub-command.
It displays details about a package in the registry from the comfort of your terminal.
Here is an example:</p>
<pre tabindex="0"><code>$ cargo info lazy_static
lazy_static #macro #lazy #static
A macro for declaring lazily evaluated statics in Rust.
version: 1.5.0
license: MIT OR Apache-2.0
rust-version: unknown
documentation: https://docs.rs/lazy_static
repository: https://github.com/rust-lang-nursery/lazy-static.rs
crates.io: https://crates.io/crates/lazy_static/1.5.0
features:
  spin        = [dep:spin]
  spin_no_std = [spin]
note: to see how you depend on lazy_static, run `cargo tree --invert --package lazy_static@1.5.0`
</code></pre><p>Vim and neovim generally composes well with other terminal tools.
So how can we easily integrate <code>cargo info</code> and <code>neovim</code>?</p>
<h2 id="demo">Demo</h2>
<p>The goal is to press a key and display the <code>cargo info</code> for the crate under the cursor in a <code>Cargo.toml</code> file.
Like this:</p>
<div id="demo3"></div>
<script>
AsciinemaPlayer.create("/blog/cargo-info-in-neovim/demo.json", document.getElementById('demo3'), {
"idleTimeLimit":  1 ,"poster": "npt:3","preload":  1 ,"speed": "1.5",
});
</script>
<noscript><blockquote><p>To run this asciicast without javascript, use <code>asciinema play https://joly.pw/blog/cargo-info-in-neovim/demo.json</code> with <a href="https://asciinema.org/">Asciinema</a></p></blockquote></noscript>

<h2 id="introducing-keywordprg">Introducing <code>keywordprg</code></h2>
<p>In the above demonstration, we press <a href="https://neovim.io/doc/user/various.html#K"><code>K</code></a> over a crates name. Then neovim executes the program set in <a href="https://neovim.io/doc/user/options.html#'keywordprg'"><code>keywordprg</code></a>, appending the work under the cursor. So if the cursor is on <code>lazy_static</code></p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#e06c75">dev-dependencies</span>]
</span></span><span style="display:flex;"><span><span style="color:#e06c75">iai</span> = <span style="color:#98c379">&#34;0.1&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#e06c75">insta</span> = <span style="color:#98c379">&#34;1.40.0&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#e06c75">lazy_static</span> = <span style="color:#98c379">&#34;1.5.0&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#7f848e">#   ^ cursor is here when we press K</span>
</span></span><span style="display:flex;"><span><span style="color:#e06c75">mktemp</span> = <span style="color:#98c379">&#34;0.5&#34;</span>
</span></span></code></pre></div><p>and <code>keywordprg</code> is set to <code>cargo info</code>, the command <code>cargo info lazy_static</code> is executed in a new terminal.</p>
<p>We can further improve this.
Since we want a fast answer (without checking the remote repository), let’s use <code>cargo info --offline</code>.
And we would like pretty colors, let’s force that using <code>--color=always</code>.</p>
<p>We only want to alter <code>keywordprg</code> when a <code>Cargo.toml</code> file is edited, because it makes no sense to call <code>cargo info</code> in a Python file.
We can use a <a href="https://neovim.io/doc/user/usr_41.html#ftplugin"><code>ftplugin</code></a> for toml files for that<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, so that the plugin is only loaded and executed when a toml file is executed.
Furthermore we can change the setting only when opening a file named “Cargo.toml”, instead of changing it for every toml file.
We can put the necessary configuration in <code>~/.config/nvim/ftplugin/toml.lua</code><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, like so:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#c678dd">if</span> <span style="color:#e06c75">vim.endswith</span>(<span style="color:#e06c75">vim.fn</span>.<span style="color:#e06c75">bufname</span>(), <span style="color:#98c379">&#34;Cargo.toml&#34;</span>) <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span>  <span style="color:#e06c75">vim.opt_local</span>.<span style="color:#e06c75">keywordprg</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">&#34;cargo info --color=always --offline&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#7f848e">-- Add chars that are often part of keys, especially in rust crates</span>
</span></span><span style="display:flex;"><span><span style="color:#7f848e">-- (https://toml.io/en/v1.0.0#keys)</span>
</span></span><span style="display:flex;"><span><span style="color:#e06c75">vim.opt_local</span>.<span style="color:#e06c75">iskeyword</span>:<span style="color:#e06c75">append</span> <span style="color:#98c379">&#34;-&#34;</span>
</span></span></code></pre></div><p>The Lua code above also changes the <a href="https://neovim.io/doc/user/options.html#'iskeyword'"><code>iskeyword</code></a> preference.
This is so that <code>tokio-test</code> is considered as one word (a “keyword” in Vim parlance), instead of two (<code>tokio</code> and <code>test</code>).
With this set, doing <code>K</code> on <code>tokio-test</code> will behave properly, because <code>tokio-test</code> is passed to the command, instead of just <code>tokio</code>.</p>
<p>One final note: the above configuration was the only thing sourced in the demo.
All the rest is default, vanilla, neovim 0.10.2.
And this does not even require recent neovim features, it has been supported in Vim for many years.</p>
<h2 id="learnings">Learnings</h2>
<p>Obviously this could be further refined.
Other options could be passed to <code>cargo info</code>, like <code>-v</code> to make it more verbose and list dependencies.
Some more scripting could add useful features to further improve the integration.
For this particular problem, there are even <a href="https://github.com/saecki/crates.nvim">a full plugin</a> with many more features.
But the point is to showcase a simple and robust integration<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, applicable in a wide variety of contexts.
In particular when the use case is too niche, a full plugin is too costly to write and maintain for the benefits it provides.</p>
<p>Let’s highlight the takeaways from this post that are applicable in a wide variety of contexts.</p>
<p>First, a number of Neovim commands can do something with the keyword under the cursor.
Adjusting what counts as a keyword boundary is often, but not always, done in the syntax file of a particular language.
Or you may just want to make a different trade off and set your own <code>iskeyword</code> value.</p>
<p>Second, the <a href="https://neovim.io/doc/user/various.html#K"><code>K</code></a> mapping is often used to look up a word in a documentation (it is set to open man pages by default).
It even works in visual mode, looking up the selected text.
And arbitrary Vim or shell commands can be used, instead of the default <code>:Man</code>.</p>
<p>Please do read the corresponding parts of the Vim manual linked in this section to learn more.
Next time, you may come up with your own quick integration between Vim and another tool.
Happy hacking!</p>




  
  
  
  

  <div class="alert alert-edit">
    <p class="alert-heading">
      ✏
      
        Edit
      
    </p>
    <p>2024-10-22: Clarify why we use nvim settings instead of a plugin like <a href="https://github.com/saecki/crates.nvim">crates.nvim</a></p>
  </div>



<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>To keep the example simple, we don’t clean-up the local preferences that are set here. See the <a href="https://neovim.io/doc/user/usr_41.html#ftplugin">documentation</a> for best practices when sharing ftplugins.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>It’s also possible to do this in Vimscript instead of Lua.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Thanks to <a href="https://fosstodon.org/@dpom">@dpom@fosstodon.org</a> <a href="https://fosstodon.org/@dpom/113347670141692005">for pointing out</a> that crates.nvim has that feature already.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Rust Default Values for Maintainability</title><link>https://joly.pw/blog/rust-default-values-for-maintainability/</link><pubDate>Sat, 25 Jun 2022 14:41:55 +0000</pubDate><guid>https://joly.pw/blog/rust-default-values-for-maintainability/</guid><description>Hidden benefits of the humble Default trait</description><content:encoded><![CDATA[



  
  
  
  

  <div class="alert alert-tldr">
    <p class="alert-heading">
      ⚡
      
        TL;DR
      
    </p>
    <p>The <a href="https://doc.rust-lang.org/std/default/trait.Default.html"><code>Default</code></a> trait can enhance the maintainability of your code. Default values for common types are <a href="#quick-reference">listed</a> at the end.</p>
  </div>



<h2 id="a-pr-review">A PR Review</h2>
<p>Recently, while reviewing a <a href="https://github.com/cljoly/rusqlite_migration/pull/20/files">PR</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, I noticed that part of the patch was introducing a new field to a struct:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 1</span><span>diff --git a/src/lib.rs b/src/lib.rs
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 2</span><span>index eba9a3a..8619e06 100644
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 3</span><span><span style="color:#e06c75">--- a/src/lib.rs
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 4</span><span><span style="color:#98c379;font-weight:bold">+++ b/src/lib.rs
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 5</span><span>@@ -106,8 +108,9 @@ use std::{
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 6</span><span> #[derive(Debug, PartialEq, Clone)]
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 7</span><span> pub struct M&lt;&#39;u&gt; {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 8</span><span>     up: &amp;&#39;u str,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 9</span><span>     down: Option&lt;&amp;&#39;u str&gt;,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">10</span><span><span style="color:#98c379;font-weight:bold">+    foreign_key_check: bool,
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">11</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">12</span><span> 
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">13</span><span> impl&lt;&#39;u&gt; M&lt;&#39;u&gt; {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">14</span><span>@@ -137,8 +140,9 @@ impl&lt;&#39;u&gt; M&lt;&#39;u&gt; {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">15</span><span>     pub const fn up(sql: &amp;&#39;u str) -&gt; Self {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">16</span><span>         Self {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">17</span><span>             up: sql,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">18</span><span>             down: None,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">19</span><span><span style="color:#98c379;font-weight:bold">+            foreign_key_check: false,
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">20</span><span>         }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">21</span><span>     }
</span></span></code></pre></div><p>That prompted me to reflect on the code I had initially written.
Prior to the patch, it looked roughly<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 1</span><span><span style="color:#7f848e">#[derive(Debug, PartialEq, Clone)]</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 2</span><span><span style="color:#c678dd">pub</span> <span style="color:#c678dd">struct</span> <span style="color:#e5c07b">M</span><span style="color:#56b6c2">&lt;</span><span style="color:#e06c75">&#39;u</span><span style="color:#56b6c2">&gt;</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 3</span><span>    <span style="color:#e06c75">up</span>: <span style="color:#c678dd">&amp;</span><span style="color:#e06c75">&#39;u</span> <span style="color:#e5c07b">str</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 4</span><span>    <span style="color:#e06c75">down</span>: <span style="color:#e5c07b">Option</span><span style="color:#56b6c2">&lt;&amp;</span><span style="color:#e06c75">&#39;u</span> <span style="color:#e5c07b">str</span><span style="color:#56b6c2">&gt;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 5</span><span>}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 6</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 7</span><span><span style="color:#c678dd">impl</span><span style="color:#56b6c2">&lt;</span><span style="color:#e06c75">&#39;u</span><span style="color:#56b6c2">&gt;</span> <span style="color:#e06c75">M</span><span style="color:#56b6c2">&lt;</span><span style="color:#e06c75">&#39;u</span><span style="color:#56b6c2">&gt;</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 8</span><span>    <span style="color:#c678dd">pub</span> <span style="color:#c678dd">const</span> <span style="color:#c678dd">fn</span> <span style="color:#61afef;font-weight:bold">up</span>(<span style="color:#e06c75">sql</span>: <span style="color:#c678dd">&amp;</span><span style="color:#e06c75">&#39;u</span> <span style="color:#e5c07b">str</span>) -&gt; <span style="color:#e5c07b">Self</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 9</span><span>        <span style="color:#e5c07b">Self</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">10</span><span>            <span style="color:#e06c75">up</span>: <span style="color:#e5c07b">sql</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">11</span><span>            <span style="color:#e06c75">down</span>: <span style="color:#e5c07b">None</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">12</span><span>        }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">13</span><span>    }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">14</span><span>}
</span></span></code></pre></div><h2 id="the-default-trait">The <code>Default</code> Trait</h2>
<p>What if I had used the <a href="https://doc.rust-lang.org/std/default/trait.Default.html"><code>Default</code></a> trait here?
The code could have looked like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;"><code class="language-rust" data-lang="rust"><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 1</span><span><span style="color:#7f848e">#[derive(Debug, Default, PartialEq, Clone)]</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 2</span><span><span style="color:#c678dd">pub</span> <span style="color:#c678dd">struct</span> <span style="color:#e5c07b">M</span><span style="color:#56b6c2">&lt;</span><span style="color:#e06c75">&#39;u</span><span style="color:#56b6c2">&gt;</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 3</span><span>    <span style="color:#e06c75">up</span>: <span style="color:#c678dd">&amp;</span><span style="color:#e06c75">&#39;u</span> <span style="color:#e5c07b">str</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 4</span><span>    <span style="color:#e06c75">down</span>: <span style="color:#e5c07b">Option</span><span style="color:#56b6c2">&lt;&amp;</span><span style="color:#e06c75">&#39;u</span> <span style="color:#e5c07b">str</span><span style="color:#56b6c2">&gt;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 5</span><span>}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 6</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 7</span><span><span style="color:#c678dd">impl</span><span style="color:#56b6c2">&lt;</span><span style="color:#e06c75">&#39;u</span><span style="color:#56b6c2">&gt;</span> <span style="color:#e06c75">M</span><span style="color:#56b6c2">&lt;</span><span style="color:#e06c75">&#39;u</span><span style="color:#56b6c2">&gt;</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 8</span><span>    <span style="color:#c678dd">pub</span> <span style="color:#c678dd">const</span> <span style="color:#c678dd">fn</span> <span style="color:#61afef;font-weight:bold">up</span>(<span style="color:#e06c75">sql</span>: <span style="color:#c678dd">&amp;</span><span style="color:#e06c75">&#39;u</span> <span style="color:#e5c07b">str</span>) -&gt; <span style="color:#e5c07b">Self</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 9</span><span>        <span style="color:#e5c07b">Self</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">10</span><span>            <span style="color:#e06c75">up</span>: <span style="color:#e5c07b">sql</span>,
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">11</span><span>            <span style="color:#56b6c2">..</span><span style="color:#e5c07b">Default</span>::<span style="color:#e06c75">default</span>()
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">12</span><span>        }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">13</span><span>    }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">14</span><span>}
</span></span></code></pre></div><p>On the first line, the <a href="https://doc.rust-lang.org/reference/attributes/derive.html"><code>#[derive(Default)]</code></a> attribute makes the structure <code>M</code> implement the <code>Default</code> trait.
Thanks to this trait, a call to <code>M::default()</code> will create a struct with default values for its fields: <code>M { up: &quot;&quot;, down: None }</code>. Note that when a structure <code>M</code> is expected, <code>Default::default()</code> is equivalent to <code>M::default()</code>.</p>
<p>We then need to initialize the two fields of that structure, overriding some defaults:</p>
<ul>
<li><code>up</code> is defined directly as before. That’s the value we want to override.</li>
<li><code>down</code> is set by the <code>Default</code> trait. This is done by <code>..Default::default()</code> on line 11. <code>Default::default()</code> provides the values. Then the <a href="https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax"><code>..</code></a> syntax fills out the fields that were not directly set. <code>down</code> is thus set to the same value as before, <code>None</code>.</li>
</ul>
<p>The code is just as long as before, when we were not using the <code>Default</code> trait.
But then, <a href="#a-pr-review">line 19 of the above patch</a> would have been unnecessary: <code>false</code> is the default for a <code>bool</code>, so the new <code>foreign_key_check</code> field would have been covered by the <code>..Default::default()</code>.</p>
<p>This results in a shorter patch:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 1</span><span>diff --git a/src/lib.rs b/src/lib.rs
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 2</span><span>index eba9a3a..8619e06 100644
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 3</span><span><span style="color:#e06c75">--- a/src/lib.rs
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 4</span><span><span style="color:#98c379;font-weight:bold">+++ b/src/lib.rs
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 5</span><span>@@ -106,8 +108,9 @@ use std::{
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 6</span><span> #[derive(Debug, PartialEq, Clone)]
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 7</span><span> pub struct M&lt;&#39;u&gt; {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 8</span><span>     up: &amp;&#39;u str,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 9</span><span>     down: Option&lt;&amp;&#39;u str&gt;,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">10</span><span><span style="color:#98c379;font-weight:bold">+    foreign_key_check: bool,
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">11</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">12</span><span> 
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">13</span><span> impl&lt;&#39;u&gt; M&lt;&#39;u&gt; {
</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>In the example of this post, we are doing only one instantiation of that particular struct, and it has very few fields anyway.
But if there were many instantiations of that struct, we would have had to change all of those.
Then, using <code>Default</code> would have been quite beneficial.</p>
<p><a href="https://cs.github.com/rust-lang/rust/blob/10f4ce324baf7cfb7ce2b2096662b82b79204944/compiler/rustc_target/src/spec/hermit_base.rs#L21">This</a>
<a href="https://cs.github.com/rust-lang/rust/blob/10f4ce324baf7cfb7ce2b2096662b82b79204944/compiler/rustc_target/src/spec/solaris_base.rs#L15">pattern</a>
<a href="https://cs.github.com/rust-lang/rust-analyzer/blob/6fc5c3cd2117a29981ba9b7cef8a51c1d6804089/crates/ide-completion/src/render.rs#L68">were</a>
<a href="https://cs.github.com/rust-lang/rustc-perf/blob/434ba59ca9fbd793ba2b6d02e65704c108479069/collector/benchmarks/clap-3.1.6/src/build/possible_value.rs#L56">the</a>
<a href="https://cs.github.com/rust-lang/rustup/blob/20ed5d9803ca237c39fbbcba8971c4558be4acca/src/diskio/immediate.rs#L34">return</a>
<a href="https://cs.github.com/rust-lang/mdBook/blob/0547868d4d25e1c840a871f9e17b2b4c2078596b/src/book/book.rs#L89">type</a>
is
<a href="https://cs.github.com/rust-lang/rust/blob/10f4ce324baf7cfb7ce2b2096662b82b79204944/compiler/rustc_target/src/spec/redox_base.rs#L16">built</a>
<a href="https://cs.github.com/rust-lang/docs.rs/blob/1ce3fd876a0f5fd5b52c9962cf7ae9df137e6366/src/web/releases.rs#L653">with</a>
a
<a href="https://cs.github.com/rust-lang/rust/blob/10f4ce324baf7cfb7ce2b2096662b82b79204944/compiler/rustc_target/src/spec/l4re_base.rs#L13">call</a>
to
<code>Default::default()</code>
seems
relatively
common
in
the
<a href="https://github.com/rust-lang">Rust organization</a>.
It can enhance maintainability, much more than I initially thought.</p>
<p>Of course this is a balancing act.
For instance, this pattern could be abused by <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=ae7553d16b481951bd8e3418b82fcd27">defining custom default values</a> on primitive types for a particular structure.
That would lead to <code>Default::default()</code> filling surprising values and the code would be less predictable.</p>




  
  
  
  

  <div class="alert alert-edit">
    <p class="alert-heading">
      ✏
      
        Edit
      
    </p>
    <p>2022-07-29: As SpudnikV <a href="https://www.reddit.com/r/rust/comments/vkozed/comment/idtbgit/?utm_source=share&amp;utm_medium=web2x&amp;context=3">pointed out</a>, using defaults as explained in this post can hide the implications of a change made to a structure. There could be code in various places relying on invariants that may break due to the change. Without <code>Default::default()</code>, the change might make visible edits in these places, drawing the attention of reviewers on these invariants.</p>
<p>That’s another case where it might not be wise to use the <code>Default</code> trait. Again, it’s a balancing act!</p>
  </div>



<hr>
<h2 id="appendix-defaults-for-some-common-types-with-derive">Appendix: Defaults for Some Common Types With <code>derive</code></h2>
<p>Why did I not use the <code>Default</code> trait initially?
Part of it might be the fear of introducing incorrect code.
It was slightly unclear to me what <code>derive</code> uses as a default value for common primitive types.
And you don’t want a field set explicitly to <code>false</code> becoming a <code>true</code> once you use <code>Default</code>, right?</p>
<p>Let’s take a closer look by running the following program:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#7f848e">#[derive(Debug, Default)]</span>
</span></span><span style="display:flex;"><span><span style="color:#c678dd">struct</span> <span style="color:#e5c07b">D</span><span style="color:#56b6c2">&lt;</span><span style="color:#e06c75">&#39;a</span><span style="color:#56b6c2">&gt;</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">b</span>: <span style="color:#e5c07b">bool</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">c</span>: <span style="color:#e5c07b">char</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">o</span>: <span style="color:#e5c07b">Option</span><span style="color:#56b6c2">&lt;</span><span style="color:#e5c07b">usize</span><span style="color:#56b6c2">&gt;</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">string</span>: <span style="color:#e5c07b">String</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e5c07b">str</span>: <span style="color:#c678dd">&amp;</span><span style="color:#e06c75">&#39;a</span> <span style="color:#e5c07b">str</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">v</span>: <span style="color:#e5c07b">Vec</span><span style="color:#56b6c2">&lt;</span><span style="color:#e5c07b">usize</span><span style="color:#56b6c2">&gt;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">a</span>: [<span style="color:#e5c07b">usize</span>; <span style="color:#d19a66">10</span>],
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">s</span>: <span style="color:#c678dd">&amp;</span><span style="color:#e06c75">&#39;a</span> [<span style="color:#e5c07b">u32</span>],
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">f</span>: <span style="color:#e5c07b">f64</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">u</span>: (<span style="color:#e5c07b">usize</span>, <span style="color:#e5c07b">u32</span>, <span style="color:#e5c07b">u64</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#c678dd">fn</span> <span style="color:#61afef;font-weight:bold">main</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#56b6c2;font-weight:bold">println!</span>(<span style="color:#98c379">&#34;</span><span style="color:#98c379">{:#?}</span><span style="color:#98c379">&#34;</span>, <span style="color:#e06c75">D</span>::<span style="color:#e06c75">default</span>());
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Output:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#e06c75">D</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">b</span>: <span style="color:#e5c07b">false</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">c</span>: <span style="color:#e06c75">&#39;</span>\<span style="color:#d19a66">0</span><span style="color:#e06c75">&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">o</span>: <span style="color:#e5c07b">None</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">string</span>: <span style="color:#98c379">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e5c07b">str</span>: <span style="color:#98c379">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">v</span>: [],
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">a</span>: [
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>    ],
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">s</span>: [],
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">f</span>: <span style="color:#d19a66">0.0</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">u</span>: (
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span>    ),
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>It turns out that in general, the default for common types in the standard library is a 0 byte in the underlying data structure.
Note that arrays are fixed size in rust and thus the default is an array of the right size, filled with defaults for the inner type.
That’s quite similar to <a href="https://go.dev/ref/spec#The_zero_value">go</a>.</p>
<h3 id="quick-reference">Quick Reference</h3>
<p>Here is a table for future reference:</p>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Default value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>bool</code></td>
          <td><code>false</code></td>
      </tr>
      <tr>
          <td><code>char</code></td>
          <td><code>'\0'</code></td>
      </tr>
      <tr>
          <td><code>Option</code></td>
          <td><code>None</code></td>
      </tr>
      <tr>
          <td><code>String</code>, <code>&amp;str</code></td>
          <td><code>&quot;&quot;</code></td>
      </tr>
      <tr>
          <td><code>Vec&lt;usize&gt;</code></td>
          <td><code>[]</code></td>
      </tr>
      <tr>
          <td><code>[usize; N]</code></td>
          <td><code>[0, 0, …, 0]</code></td>
      </tr>
      <tr>
          <td><code>&amp;[u32]</code></td>
          <td><code>[]</code></td>
      </tr>
      <tr>
          <td><code>f64</code>, <code>f32…</code></td>
          <td><code>0.</code></td>
      </tr>
      <tr>
          <td><code>usize</code>, <code>u32…</code></td>
          <td><code>0</code></td>
      </tr>
  </tbody>
</table>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Please don’t take anything in this post as critical of the PR’s author work. I’m very grateful that they took some time to contribute to <a href="https://cj.rs/rusqlite_migration/">the project</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I’ve slightly edited the patch and the code samples from <a href="https://cj.rs/rusqlite_migration/">rusqlite_migration</a> to make those shorter and easier to grasp.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Rusqlite Migration</title><link>https://joly.pw/rusqlite_migration/</link><pubDate>Sat, 21 Aug 2021 15:32:05 +0100</pubDate><guid>https://joly.pw/rusqlite_migration/</guid><description>↕️ Simple database schema migration library for rusqlite, written with performance in mind.</description><content:encoded><![CDATA[
<p style="display: flex; justify-content: space-between">
  <a href="https://github.com/cljoly/rusqlite_migration" data-goatcounter-click="ext-github-rusqlite_migration" data-goatcounter-title="cljoly/rusqlite_migration">
    <span class="svgicon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
    stroke-linecap="round" stroke-linejoin="round">
    <path
        d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22">
    </path>
</svg></span>&nbsp;cljoly/rusqlite_migration
  </a>
  <a class="badges" href="https://github.com/cljoly/rusqlite_migration" data-goatcounter-click="ext-stargithub-rusqlite_migration" data-goatcounter-title="stars cljoly/rusqlite_migration">
    <img src="https://img.shields.io/github/stars/cljoly/rusqlite_migration?style=social" alt="Github stars for rusqlite_migration">
  </a>
</p>


<div class="badges">


<p><a href="https://docs.rs/rusqlite_migration">
<img alt="docs.rs" loading="lazy" src="https://img.shields.io/docsrs/rusqlite_migration"></a>
<a href="https://crates.io/crates/rusqlite_migration">
<img alt="Crates.io" loading="lazy" src="https://img.shields.io/crates/v/rusqlite_migration"></a>
<a href="https://cj.rs/rusqlite_migration/changelog">

  <img alt="Changelog" loading="lazy" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2OSIgaGVpZ2h0PSIyMCIgcm9sZT0iaW1nIiBhcmlhLWxhYmVsPSJDaGFuZ2Vsb2ciPjx0aXRsZT5DaGFuZ2Vsb2c8L3RpdGxlPjxsaW5lYXJHcmFkaWVudCBpZD0icyIgeDI9IjAiIHkyPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNiYmIiIHN0b3Atb3BhY2l0eT0iLjEiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3Atb3BhY2l0eT0iLjEiLz48L2xpbmVhckdyYWRpZW50PjxjbGlwUGF0aCBpZD0iciI+PHJlY3Qgd2lkdGg9IjY5IiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iI2ZmZiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI3IpIj48cmVjdCB3aWR0aD0iMCIgaGVpZ2h0PSIyMCIgZmlsbD0icHVycGxlIi8+PHJlY3QgeD0iMCIgd2lkdGg9IjY5IiBoZWlnaHQ9IjIwIiBmaWxsPSJwdXJwbGUiLz48cmVjdCB3aWR0aD0iNjkiIGhlaWdodD0iMjAiIGZpbGw9InVybCgjcykiLz48L2c+PGcgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1mYW1pbHk9IlZlcmRhbmEsR2VuZXZhLERlamFWdSBTYW5zLHNhbnMtc2VyaWYiIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIGZvbnQtc2l6ZT0iMTEwIj48dGV4dCBhcmlhLWhpZGRlbj0idHJ1ZSIgeD0iMzQ1IiB5PSIxNTAiIGZpbGw9IiMwMTAxMDEiIGZpbGwtb3BhY2l0eT0iLjMiIHRyYW5zZm9ybT0ic2NhbGUoLjEpIiB0ZXh0TGVuZ3RoPSI1OTAiPkNoYW5nZWxvZzwvdGV4dD48dGV4dCB4PSIzNDUiIHk9IjE0MCIgdHJhbnNmb3JtPSJzY2FsZSguMSkiIGZpbGw9IiNmZmYiIHRleHRMZW5ndGg9IjU5MCI+Q2hhbmdlbG9nPC90ZXh0PjwvZz48L3N2Zz4="></a>
<a href="https://github.com/rust-secure-code/safety-dance/">

  <img alt="unsafe forbidden" loading="lazy" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTAiIGhlaWdodD0iMjAiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0idW5zYWZlOiBmb3JiaWRkZW4iPjx0aXRsZT51bnNhZmU6IGZvcmJpZGRlbjwvdGl0bGU+PGxpbmVhckdyYWRpZW50IGlkPSJzIiB4Mj0iMCIgeTI9IjEwMCUiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2JiYiIgc3RvcC1vcGFjaXR5PSIuMSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1vcGFjaXR5PSIuMSIvPjwvbGluZWFyR3JhZGllbnQ+PGNsaXBQYXRoIGlkPSJyIj48cmVjdCB3aWR0aD0iMTEwIiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iI2ZmZiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI3IpIj48cmVjdCB3aWR0aD0iNDciIGhlaWdodD0iMjAiIGZpbGw9IiM1NTUiLz48cmVjdCB4PSI0NyIgd2lkdGg9IjYzIiBoZWlnaHQ9IjIwIiBmaWxsPSIjNGMxIi8+PHJlY3Qgd2lkdGg9IjExMCIgaGVpZ2h0PSIyMCIgZmlsbD0idXJsKCNzKSIvPjwvZz48ZyBmaWxsPSIjZmZmIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iVmVyZGFuYSxHZW5ldmEsRGVqYVZ1IFNhbnMsc2Fucy1zZXJpZiIgdGV4dC1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiIgZm9udC1zaXplPSIxMTAiPjx0ZXh0IGFyaWEtaGlkZGVuPSJ0cnVlIiB4PSIyNDUiIHk9IjE1MCIgZmlsbD0iIzAxMDEwMSIgZmlsbC1vcGFjaXR5PSIuMyIgdHJhbnNmb3JtPSJzY2FsZSguMSkiIHRleHRMZW5ndGg9IjM3MCI+dW5zYWZlPC90ZXh0Pjx0ZXh0IHg9IjI0NSIgeT0iMTQwIiB0cmFuc2Zvcm09InNjYWxlKC4xKSIgZmlsbD0iI2ZmZiIgdGV4dExlbmd0aD0iMzcwIj51bnNhZmU8L3RleHQ+PHRleHQgYXJpYS1oaWRkZW49InRydWUiIHg9Ijc3NSIgeT0iMTUwIiBmaWxsPSIjMDEwMTAxIiBmaWxsLW9wYWNpdHk9Ii4zIiB0cmFuc2Zvcm09InNjYWxlKC4xKSIgdGV4dExlbmd0aD0iNTMwIj5mb3JiaWRkZW48L3RleHQ+PHRleHQgeD0iNzc1IiB5PSIxNDAiIHRyYW5zZm9ybT0ic2NhbGUoLjEpIiBmaWxsPSIjZmZmIiB0ZXh0TGVuZ3RoPSI1MzAiPmZvcmJpZGRlbjwvdGV4dD48L2c+PC9zdmc+"></a>
<a href="https://coveralls.io/github/cljoly/rusqlite_migration">
<img alt="Coveralls" loading="lazy" src="https://img.shields.io/coverallsCoverage/github/cljoly/rusqlite_migration"></a></p>

</div>


<p>Rusqlite Migration is a performant and simple schema migration library for <a href="https://crates.io/crates/rusqlite">rusqlite</a>.</p>
<ul>
<li><strong>Performance</strong>:
<ul>
<li><em>Fast database opening</em>: to keep track of the current migration state, most tools create one or more tables in the database. These tables require parsing by SQLite and are queried with SQL statements. This library uses the <a href="https://sqlite.org/pragma.html#pragma_user_version"><code>user_version</code></a> value instead. It’s much lighter as it is just an integer at a <a href="https://www.sqlite.org/fileformat.html#user_version_number">fixed offset</a> in the SQLite file.</li>
<li><em>Fast compilation</em>: this crate is very small and does not use macros to define the migrations.</li>
</ul>
</li>
<li><strong>Simplicity</strong>: this crate strives for simplicity. Just define a set of SQL statements as strings in your Rust code. Add more SQL statements over time as needed. No external CLI required. Additionally, rusqlite_migration works especially well with other small libraries complementing rusqlite, like <a href="https://crates.io/crates/serde_rusqlite">serde_rusqlite</a>.</li>
</ul>
<h2 id="example">Example</h2>
<p>Here, we define SQL statements to run with <a href="https://docs.rs/rusqlite_migration/latest/rusqlite_migration/struct.Migrations.html#method.new"><code>Migrations::new()</code></a> and run these (if necessary) with <a href="https://docs.rs/rusqlite_migration/latest/rusqlite_migration/struct.Migrations.html#method.to_latest"><code>Migrations::to_latest()</code></a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#c678dd">use</span> <span style="color:#e06c75">rusqlite</span>::{<span style="color:#e06c75">params</span>, <span style="color:#e06c75">Connection</span>};
</span></span><span style="display:flex;"><span><span style="color:#c678dd">use</span> <span style="color:#e06c75">rusqlite_migration</span>::{<span style="color:#e06c75">Migrations</span>, <span style="color:#e06c75">M</span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#7f848e">// 1️⃣ Define migrations
</span></span></span><span style="display:flex;"><span><span style="color:#c678dd">const</span> <span style="color:#e06c75">MIGRATIONS_SLICE</span>: <span style="color:#c678dd">&amp;</span>[<span style="color:#e06c75">M</span><span style="color:#56b6c2">&lt;</span><span style="color:#e5c07b">&#39;_</span><span style="color:#56b6c2">&gt;</span>] <span style="color:#56b6c2">=</span> <span style="color:#56b6c2">&amp;</span>[
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">M</span>::<span style="color:#e06c75">up</span>(<span style="color:#98c379">&#34;CREATE TABLE friend(name TEXT NOT NULL);&#34;</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#7f848e">// In the future, add more migrations here:
</span></span></span><span style="display:flex;"><span>    <span style="color:#7f848e">//M::up(&#34;ALTER TABLE friend ADD COLUMN email TEXT;&#34;),
</span></span></span><span style="display:flex;"><span>];
</span></span><span style="display:flex;"><span><span style="color:#c678dd">const</span> <span style="color:#e06c75">MIGRATIONS</span>: <span style="color:#e5c07b">Migrations</span><span style="color:#56b6c2">&lt;</span><span style="color:#e5c07b">&#39;_</span><span style="color:#56b6c2">&gt;</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">Migrations</span>::<span style="color:#e06c75">from_slice</span>(<span style="color:#e06c75">MIGRATIONS_SLICE</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#c678dd">fn</span> <span style="color:#61afef;font-weight:bold">main</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#c678dd">let</span> <span style="color:#c678dd">mut</span> <span style="color:#e06c75">conn</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">Connection</span>::<span style="color:#e06c75">open_in_memory</span>().<span style="color:#e06c75">unwrap</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#7f848e">// Apply some PRAGMA, often better to do it outside of migrations
</span></span></span><span style="display:flex;"><span>    <span style="color:#e06c75">conn</span>.<span style="color:#e06c75">pragma_update_and_check</span>(<span style="color:#e5c07b">None</span>, <span style="color:#98c379">&#34;journal_mode&#34;</span>, <span style="color:#56b6c2">&amp;</span><span style="color:#98c379">&#34;WAL&#34;</span>, <span style="color:#56b6c2">|</span><span style="color:#e06c75">_</span><span style="color:#56b6c2">|</span> <span style="color:#e5c07b">Ok</span>(()))
</span></span><span style="display:flex;"><span>        .<span style="color:#e06c75">unwrap</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#7f848e">// 2️⃣ Update the database schema, atomically
</span></span></span><span style="display:flex;"><span>    <span style="color:#e06c75">MIGRATIONS</span>.<span style="color:#e06c75">to_latest</span>(<span style="color:#56b6c2">&amp;</span><span style="color:#c678dd">mut</span> <span style="color:#e06c75">conn</span>).<span style="color:#e06c75">unwrap</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#7f848e">// 3️⃣ Use the database 🥳
</span></span></span><span style="display:flex;"><span>    <span style="color:#e06c75">conn</span>.<span style="color:#e06c75">execute</span>(<span style="color:#98c379">&#34;INSERT INTO friend (name) VALUES (?1)&#34;</span>, <span style="color:#56b6c2;font-weight:bold">params!</span>[<span style="color:#98c379">&#34;John&#34;</span>])
</span></span><span style="display:flex;"><span>        .<span style="color:#e06c75">unwrap</span>();
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Please see the <a href="https://github.com/cljoly/rusqlite_migrate/tree/master/examples">examples</a> folder for more, in particular:</p>
<ul>
<li>migrations with multiple SQL statements (using for instance <code>r#&quot;…&quot;</code> or <code>include_str!(…)</code>)</li>
<li>migrations defined <a href="https://github.com/cljoly/rusqlite_migration/tree/master/examples/from-directory">from a directory</a> with SQL files</li>
<li>migrations to <a href="https://github.com/cljoly/rusqlite_migration/blob/master/examples/simple/src/main.rs">previous versions (downward migrations)</a></li>
<li>migrations <a href="https://github.com/cljoly/rusqlite_migration/blob/master/examples/async/src/main.rs">when using <code>async</code></a></li>
</ul>
<p>I’ve also made a <a href="https://cj.rs/blog/sqlite-pragma-cheatsheet-for-performance-and-consistency/">cheatsheet of SQLite pragma for improved performance and consistency</a>.</p>
<h3 id="built-in-tests">Built-in tests</h3>
<p>To test that the migrations are working, you can add this in your test module:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#7f848e">#[test]</span>
</span></span><span style="display:flex;"><span><span style="color:#c678dd">fn</span> <span style="color:#61afef;font-weight:bold">migrations_test</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#56b6c2;font-weight:bold">assert!</span>(<span style="color:#e06c75">MIGRATIONS</span>.<span style="color:#e06c75">validate</span>().<span style="color:#e06c75">is_ok</span>());
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The migrations object is also suitable for serialisation with <a href="https://insta.rs/">insta</a>, using the <code>Debug</code> serialisation. You can store a snapshot of your migrations like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#7f848e">#[test]</span>
</span></span><span style="display:flex;"><span><span style="color:#c678dd">fn</span> <span style="color:#61afef;font-weight:bold">migrations_insta_snapshot</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#c678dd">let</span> <span style="color:#e06c75">migrations</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">Migrations</span>::<span style="color:#e06c75">new</span>(<span style="color:#56b6c2;font-weight:bold">vec!</span>[
</span></span><span style="display:flex;"><span>        <span style="color:#7f848e">// ...
</span></span></span><span style="display:flex;"><span>    ]);
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">insta</span>::<span style="color:#56b6c2;font-weight:bold">assert_debug_snapshot!</span>(<span style="color:#e06c75">migrations</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="optional-features">Optional Features</h2>
<p>Rusqlite migration provides several <a href="https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section">Cargo features</a>. They are:</p>
<ul>
<li><code>from-directory</code>: enable loading migrations from *.sql files in a given directory</li>
</ul>
<h2 id="active-users">Active Users</h2>

<div class="badges">


<p><a href="https://crates.io/crates/rusqlite_migration">
<img alt="Crates.io Downloads" loading="lazy" src="https://img.shields.io/crates/d/rusqlite_migration?style=social"></a> <a href="https://crates.io/crates/rusqlite_migration">
<img alt="Crates.io Downloads (recent)" loading="lazy" src="https://img.shields.io/crates/dr/rusqlite_migration?style=social"></a></p>

</div>


<p>This crate is actively used in a number of projects. You can find up-to-date list of those on:</p>
<ul>
<li><a href="https://crates.io/crates/rusqlite_migration/reverse_dependencies">crates.io</a> / <a href="https://lib.rs/crates/rusqlite_migration/rev">lib.rs</a></li>
<li><a href="https://github.com/cljoly/rusqlite_migration/network/dependents?dependent_type=REPOSITORY">GitHub’s list of dependent repositories</a></li>
</ul>
<p>A number of contributors are also reporting issues as they arise, another indicator of active use.</p>
<h2 id="minimum-supported-rust-version-msrv">Minimum Supported Rust Version (MSRV)</h2>
<p>This crate extends rusqlite and as such is tightly integrated with it. Thus, it supports the <a href="https://github.com/rusqlite/rusqlite?tab=readme-ov-file#minimum-supported-rust-version-msrv">same MSRV</a> as rusqlite. At the time of writing, this means:</p>




  <figure>
    <blockquote >
      <p>Latest stable Rust version at the time of release. It might compile with older versions.</p>

    </blockquote>
    
  </figure>



<h2 id="limits">Limits</h2>
<ol>
<li>
<p>Since this crate uses the <a href="https://www.sqlite.org/fileformat.html#user_version_number"><code>user_version</code></a> field, if your program or any other library changes it, this library will behave in an unspecified way: it may return an error, apply the wrong set of migrations, do nothing at all&hellip;</p>
</li>
<li>
<p>The <a href="https://www.sqlite.org/fileformat.html#user_version_number"><code>user_version</code></a> field is effectively a i32, so there is a theoretical limit (about two billion) on the number of migrations that can be applied by this library. You are likely to hit memory limits well before that though, so in practice, you can think of the number of migrations as limitless. And you would need to create 10 000 new migrations, every day, for over 5 centuries, before getting close to the limit.</p>
</li>
</ol>
<h2 id="contributing">Contributing</h2>
<p>Contributions (documentation or code improvements in particular) are welcome, see <a href="https://cj.rs/docs/contribute/">contributing</a>!</p>
<p>We use various tools for testing that you may find helpful to install locally (e.g. to fix failing CI checks):</p>
<ul>
<li><a href="https://crates.io/crates/cargo-insta">cargo-insta</a></li>
<li><a href="https://mutants.rs/installation.html">cargo-mutants</a></li>
</ul>
<h2 id="acknowledgments">Acknowledgments</h2>
<p>I would like to thank all the contributors, as well as the authors of the dependencies this crate uses.</p>
<p>Thanks to <a href="https://www.migadu.com/">Migadu</a> for offering a discounted service to support this project. It is not an endorsement by Migadu though.</p>
]]></content:encoded></item><item><title>Sesters</title><link>https://joly.pw/sesters/</link><pubDate>Sat, 21 Aug 2021 04:48:15 +0100</pubDate><guid>https://joly.pw/sesters/</guid><description>💱 Fast, offline currency converter 💴 💷 💶 💵</description><content:encoded><![CDATA[
<p style="display: flex; justify-content: space-between">
  <a href="https://github.com/cljoly/sesters" data-goatcounter-click="ext-github-sesters" data-goatcounter-title="cljoly/sesters">
    <span class="svgicon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
    stroke-linecap="round" stroke-linejoin="round">
    <path
        d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22">
    </path>
</svg></span>&nbsp;cljoly/sesters
  </a>
  <a class="badges" href="https://github.com/cljoly/sesters" data-goatcounter-click="ext-stargithub-sesters" data-goatcounter-title="stars cljoly/sesters">
    <img src="https://img.shields.io/github/stars/cljoly/sesters?style=social" alt="Github stars for sesters">
  </a>
</p>


<div class="badges">
<a href="https://cj.rs/sesters#getting-started"><img src="https://img.shields.io/badge/🚀 getting-started-yellow?style=flat-square" class="badges" alt="Crates.io" /></a> </a><a href="#contribute"><img src="https://img.shields.io/github/license/cljoly/sesters.svg?color=blueviolet&label=contribute&style=flat-square&logo=gnu" alt="LICENCE" /></a> <a href="https://github.com/cljoly/sesters/actions/"><img src="https://img.shields.io/github/workflow/status/cljoly/sesters/CI?label=CI&logo=github&style=flat-square" alt="Continuous Integration" /></a> <a href="https://crates.io/crates/sesters"><img src="https://img.shields.io/crates/v/sesters.svg?color=blue&style=flat-square" alt="Crates.io" /></a> <a href="https://crates.io/crates/sesters"><img alt="undefined" src="https://img.shields.io/crates/d/sesters.svg?color=brightgreen&style=flat-square"></a>

</div>


<hr>
<h2 id="getting-started">Getting started</h2>
<p>Install the latest version:</p>
<pre tabindex="0"><code>$ cargo install sesters
</code></pre><p>Exemple of plain text conversion:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ sesters convert a price burried <span style="color:#d19a66">1</span> USD in text
</span></span><span style="display:flex;"><span>USD 1.00 ➜ EUR 0.89
</span></span><span style="display:flex;"><span>$ sesters convert -- -1 €
</span></span><span style="display:flex;"><span>EUR -1.00 ➜ USD -1.10
</span></span><span style="display:flex;"><span>$ sesters convert
</span></span><span style="display:flex;"><span>I can <span style="color:#e5c07b">type</span> and press enter EUR <span style="color:#d19a66">2356</span>
</span></span><span style="display:flex;"><span>EUR 2345.00 ➜ USD 2586.53
</span></span></code></pre></div><p>It is then visible in the history:</p>
<pre tabindex="0"><code>$ sesters history list
╔═══╦═══════════════════════════════════╦═════════════════════════════════════╦═══════════════════════════╗
║ 1 ║ 2021-10-09 22:36:54.733991464 UTC ║ a price burried 1 USD in text       ║ USD 1.00 ➜ EUR 0.86       ║
╠═══╬═══════════════════════════════════╬═════════════════════════════════════╬═══════════════════════════╣
║ 2 ║ 2021-10-09 22:36:58.147102167 UTC ║ -1 €                                ║ EUR -1.00 ➜ USD -1.16     ║
╠═══╬═══════════════════════════════════╬═════════════════════════════════════╬═══════════════════════════╣
║ 3 ║ 2021-10-09 22:37:06.656527072 UTC ║ I can type and press enter EUR 2356 ║ EUR 2356.00 ➜ USD 2727.15 ║
╚═══╩═══════════════════════════════════╩═════════════════════════════════════╩═══════════════════════════╝
</code></pre><h2 id="features">Features</h2>
<ul>
<li>Find prices in plain text with several currencies</li>
<li>Store exchange rates locally for a while, to speed up future conversions</li>
<li>Save recent conversion history. The history is automatically deleted after a while</li>
</ul>
<h2 id="about-the-name">About the name</h2>
<p>Inspired by this <a href="https://en.wikipedia.org/wiki/Sestertius">coin</a>.</p>


<p><a href="https://commons.wikimedia.org/wiki/File:Sestertius_Hostilian-s2771.jpg#/media/File:Sestertius_Hostilian-s2771.jpg"><img src="https://upload.wikimedia.org/wikipedia/commons/f/f3/Sestertius_Hostilian-s2771.jpg" alt="Sestertius Hostilian-s2771.jpg"></a><br>By Classical Numismatic Group, Inc. <a rel="nofollow" class="external free" href="http://www.cngcoins.com">http://www.cngcoins.com</a>, <a href="http://creativecommons.org/licenses/by-sa/3.0/" title="Creative Commons Attribution-Share Alike 3.0">CC BY-SA 3.0</a>, <a href="https://commons.wikimedia.org/w/index.php?curid=380116">Link</a></p>



<h2 id="contribute">Contribute</h2>
<p>Contributions are welcome, see this <a href="https://cj.rs/docs/contribute/">document</a>!</p>
<p><a href="https://github.com/cljoly/sesters/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22">
<img loading="lazy" src="https://img.shields.io/github/issues/cljoly/sesters/good%20first%20issue"></a></p>
<h2 id="licence">Licence</h2>
<p>
<img alt="GPLv3" loading="lazy" src="https://www.gnu.org/graphics/gplv3-127x51.png"></p>
<p>Sesters is licensed under <a href="https://www.gnu.org/licenses/gpl.html">GNU General Public License</a> Version 3 or later.</p>




  <figure>
    <blockquote >
      <p>Copyright (C) 2018-2019  Clément Joly <a href="mailto:oss+sesters@131719.xyz">oss+sesters@131719.xyz</a></p>
<p>This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.</p>
<p>This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.</p>
<p>You should have received a copy of the GNU General Public License
along with this program.  If not, see <a href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a>.
,</p>

    </blockquote>
    
  </figure>



]]></content:encoded></item></channel></rss>