<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title> - Nicola Papale&#x27;s technical blog</title>
    <link rel="self" type="application/atom+xml" href="https://nicopap.ch/blogs/snaps-of-bafflement/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-10-27T00:00:00+00:00</updated>
    <id>https://nicopap.ch/blogs/snaps-of-bafflement/atom.xml</id>
    <entry xml:lang="en">
        <title>Bit fields for everyone</title>
        <published>2025-10-27T00:00:00+00:00</published>
        <updated>2025-10-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/bit-fields-rustfest24/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/bit-fields-rustfest24/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/bit-fields-rustfest24/">&lt;blockquote&gt;
&lt;p&gt;This is an edited version of the &lt;a href=&quot;https:&#x2F;&#x2F;rustfest.ch&#x2F;talks&#x2F;psa-you-too-can-pack-structs&#x2F;&quot;&gt;talk I gave at RustFest Zurich 2024&lt;&#x2F;a&gt;. Titled “PSA: You too can pack structs”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Bit fields is a way of putting data together to save memory. Not merly 10%, we are talking about dividing memory usage by 2, 10, in one personal case, it divided by 100 memory usage!&lt;&#x2F;p&gt;
&lt;p&gt;How to do it? Read on!&lt;&#x2F;p&gt;
&lt;p&gt;Here is why you would want to use bit fields:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Reduce memory usage&lt;&#x2F;li&gt;
&lt;li&gt;Reduce battery usage&lt;&#x2F;li&gt;
&lt;li&gt;Reduce bandwidth usage&lt;&#x2F;li&gt;
&lt;li&gt;Support older and cheaper devices&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Why not use bit fields? Well, mostly you should use them.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, it’s not widdely known. It should be, as it’s an easy solution to a lot of problems, and has been arround since the dawn of computing.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s start with some code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;hdr&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tonemap_in_shader&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;deband_dither&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;depth_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;normal_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;deferred_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;motion_vector_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;may_discard&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;environment_map&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;screen_space_ambient_occlusion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;depth_clamp_ortho&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;temporal_jitter&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;morph_targets&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;reads_view_transmission_texture&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;lightmapped&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;irradiance_volume&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;blend&lt;&#x2F;span&gt;&lt;span&gt;: Blend,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;msaa&lt;&#x2F;span&gt;&lt;span&gt;: Msaa,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;primitive_topology&lt;&#x2F;span&gt;&lt;span&gt;: PrimitiveTopology,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;shadow_filter_method&lt;&#x2F;span&gt;&lt;span&gt;: ShadowFilterMethod,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;screen_space_specular_transmission&lt;&#x2F;span&gt;&lt;span&gt;: SsstQuality,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;view_projection&lt;&#x2F;span&gt;&lt;span&gt;: ViewProjection,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tonemap_method&lt;&#x2F;span&gt;&lt;span&gt;: TonemapMethod,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is taken from the &lt;a href=&quot;https:&#x2F;&#x2F;bevy.org&#x2F;&quot;&gt;Bevy&lt;&#x2F;a&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; game engine.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Bevy is an amazing engine. It let you write games in Rust, like pygame, but with type safety and performance. It’s open source, so no nasty license backstabs, and if the documentation is lacking in place, you just press enter in the IDE and get a direct look at the code.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;In Bevy, &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt; is part of the rendering engine, it associates a mesh to a material. Each frame – so, probably 120 times per seconds – we check the material of all our meshes, a Bevy game can have from 4 meshes to 10K, even 100K meshes.&lt;&#x2F;p&gt;
&lt;p&gt;There is about a million hash and comparison per second. And &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt; is just a tinny little bit of the whole engine, and beyond the engine, we still have &lt;em&gt;your&lt;&#x2F;em&gt; whole game to run. This needs to go damn fast.&lt;&#x2F;p&gt;
&lt;p&gt;With this struct, &lt;em&gt;it doesn’t go damn fast&lt;&#x2F;em&gt;. Why? CPUs are perfect at hashing (especially with the right algorithm) and comparing, it takes a single instruction! But &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt; is 23 bytes long, and a CPU can’t compare 23 bytes in one go, it has to load this in two different registers, then keep the hash result and compare it.&lt;&#x2F;p&gt;
&lt;p&gt;This is quite fast, but it’s not enough, it’s not &lt;em&gt;damn fast&lt;&#x2F;em&gt;. What would be damn fast? Using a primitive, like &lt;code&gt;u32&lt;&#x2F;code&gt;, a hash and comparison would be 1 instruction, if not less than 1!&lt;&#x2F;p&gt;
&lt;p&gt;Can we use an &lt;code&gt;u32&lt;&#x2F;code&gt; instead of this large struct? In the first place, why does it take 23 bytes?&lt;&#x2F;p&gt;
&lt;p&gt;Each field take one byte. &lt;code&gt;bool&lt;&#x2F;code&gt; in Rust takes one byte, not one bit, as you could expect. This is because &lt;code&gt;bool&lt;&#x2F;code&gt;s are addressable, and addresses work on bytes, not bits. Otherwise, how would you do &lt;code&gt;&amp;amp;bool&lt;&#x2F;code&gt;?&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Ok, this isn’t a good reason, since references in Rust aren’t addresses.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Here is how it looks in memory:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img style=&quot;width:100%&quot; src=&quot;&#x2F;blog-assets&#x2F;bit-fields-rustfest24&#x2F;mem-repr-naive.svg&quot;
  alt=&quot;Memory representation of MeshPipelineKey, represented bit by bit. Each field is represented by a differently-colored row of 8 boxes. Only the first few boxes are full, the other ones are crossed-out.&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The same is true for the other fields. They are all enums with a tinny number of variants. They could be encoded in as few as 2 bits. For example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;TonemapMethod {
&lt;&#x2F;span&gt;&lt;span&gt;    None                           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b000&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    Reinhard                       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b001&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    ReinhardLuminance              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b010&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    AcesFitted                     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b011&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    Agx                            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b100&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    SomewhatBoringDisplayTransform &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b101&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    TonyMcMapface                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b110&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    BlenderFilmic                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b111&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That represents 7*16=112 unused bits (ie bits we are going to hash but don’t care about). That’s about 87.5% of the struct. So many wasted bits!&lt;&#x2F;p&gt;
&lt;p&gt;Can we do better than Rust here? Of course.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of declaring a whole struct, let’s use a &lt;code&gt;u32&lt;&#x2F;code&gt;. Then, we can assign fields to one, two, or three bits. As opposed to using one byte per field.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img style=&quot;width:100%&quot; src=&quot;&#x2F;blog-assets&#x2F;bit-fields-rustfest24&#x2F;mem-repr-packed.svg&quot;
  alt=&quot;Memory representation of MeshPipelineKey with the imagined &#x27;optimal&#x27; layout, represented bit by bit. Each field is represented by a differently-colored box. Unlike the unoptimized version, a single byte may contain more than one field, there is no more crossed out boxes, as all bits are used.&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nice visual and all, but in code, what does that look like?&lt;&#x2F;p&gt;
&lt;p&gt;One way of doing it is with masks. We define a constant for each of our “field” that represents the bits we use to store the field in the &lt;code&gt;u32&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To read a field, we have to “single out” the field from the rest of the struct, by masking with the &lt;code&gt;&amp;amp;&lt;&#x2F;code&gt; operator. Then, if we choose carefully our representation, we have the final value.&lt;&#x2F;p&gt;
&lt;p&gt;To set a field value, we need to clear the value and then set the bits with the &lt;code&gt;|&lt;&#x2F;code&gt; operator.&lt;&#x2F;p&gt;
&lt;p&gt;Well, this will take a couple more CPU instructions than directly loading from memory. But memory loads are already a couple of instructions, and can take &lt;em&gt;hundreds&lt;&#x2F;em&gt; if you are hitting something out of cache.&lt;&#x2F;p&gt;
&lt;p&gt;In code what does that look like?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;repr&lt;&#x2F;span&gt;&lt;span&gt;(u32)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;Blend {
&lt;&#x2F;span&gt;&lt;span&gt;    Opaque &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b00 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    PremultipliedAlpha &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b01 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    Multiply &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b10 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    Alpha &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b11 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b11 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;TryFrom&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;Blend {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;try_from&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Result&amp;lt;Blend, ()&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;set_blend&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;mesh_pipeline_key&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;blend&lt;&#x2F;span&gt;&lt;span&gt;: Blend) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; blend_offset &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; blend &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;as u32&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    (mesh_pipeline_key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp; !&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; blend_offset
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;get_blend&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;mesh_pipeline_key&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Blend {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; masked &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; mesh_pipeline_key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    masked.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;try_into&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Gosh, what horror. This sure is code, but that looks dangerous and error prone&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;In fact, the original code I used in the presentation contained an error that I only corrected when cleaning up for this blog post.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;So, how does that look like in the wild? Maybe Bevy has better code quality?&lt;&#x2F;p&gt;
&lt;p&gt;Bevy uses the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;bitflags&quot;&gt;bitflags&lt;&#x2F;a&gt; crate, let’s see how that looks:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;bitflags::bitflags&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;! &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey: u32 {
&lt;&#x2F;span&gt;&lt;span&gt;        const HDR                               = 1 &amp;lt;&amp;lt; 0;
&lt;&#x2F;span&gt;&lt;span&gt;        const TONEMAP_IN_SHADER                 = 1 &amp;lt;&amp;lt; 1;
&lt;&#x2F;span&gt;&lt;span&gt;        const DEBAND_DITHER                     = 1 &amp;lt;&amp;lt; 2;
&lt;&#x2F;span&gt;&lt;span&gt;        const DEPTH_PREPASS                     = 1 &amp;lt;&amp;lt; 3;
&lt;&#x2F;span&gt;&lt;span&gt;        const NORMAL_PREPASS                    = 1 &amp;lt;&amp;lt; 4;
&lt;&#x2F;span&gt;&lt;span&gt;        const DEFERRED_PREPASS                  = 1 &amp;lt;&amp;lt; 5;
&lt;&#x2F;span&gt;&lt;span&gt;        const MOTION_VECTOR_PREPASS             = 1 &amp;lt;&amp;lt; 6;
&lt;&#x2F;span&gt;&lt;span&gt;        const MAY_DISCARD                       = 1 &amp;lt;&amp;lt; 7;
&lt;&#x2F;span&gt;&lt;span&gt;        const ENVIRONMENT_MAP                   = 1 &amp;lt;&amp;lt; 8;
&lt;&#x2F;span&gt;&lt;span&gt;        const SCREEN_SPACE_AMBIENT_OCCLUSION    = 1 &amp;lt;&amp;lt; 9;
&lt;&#x2F;span&gt;&lt;span&gt;        const DEPTH_CLAMP_ORTHO                 = 1 &amp;lt;&amp;lt; 10;
&lt;&#x2F;span&gt;&lt;span&gt;        const TEMPORAL_JITTER                   = 1 &amp;lt;&amp;lt; 11;
&lt;&#x2F;span&gt;&lt;span&gt;        const MORPH_TARGETS                     = 1 &amp;lt;&amp;lt; 12;
&lt;&#x2F;span&gt;&lt;span&gt;        const READS_VIEW_TRANSMISSION_TEXTURE   = 1 &amp;lt;&amp;lt; 13;
&lt;&#x2F;span&gt;&lt;span&gt;        const LIGHTMAPPED                       = 1 &amp;lt;&amp;lt; 14;
&lt;&#x2F;span&gt;&lt;span&gt;        const IRRADIANCE_VOLUME                 = 1 &amp;lt;&amp;lt; 15;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; etc.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Starting with the boolean fields, we convert the struct into a newtype, and declare associated constants, one per field. Then, to read and write to the packed struct, we do as we did earlier, but with named constants instead of magic numbers. Here is how it looks like when reading&#x2F;writing to a &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;HDR &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;MAY_DISCARD &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;IRRADIANCE_VOLUME&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt; 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; Note that unlike C, and other C-derived language,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; operations follow the correct operator precedence.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;IRRADIANCE_VOLUME
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;IRRADIANCE_VOLUME &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; do irradiance volume
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As a developer, I don’t like this code. While it is “type safe” the code doesn’t reflect what we are doing. It is ostensibly manipulating bits, or bit twiddling, but what we &lt;em&gt;mean&lt;&#x2F;em&gt; to do is not manipulating bits, but rather check a boolean value, no?&lt;&#x2F;p&gt;
&lt;p&gt;In any case, we should look at how to handle enums with this.&lt;&#x2F;p&gt;
&lt;p&gt;Please keep in mind that &lt;strong&gt;this is an anti-pattern&lt;&#x2F;strong&gt;. Do not reproduce it at home or at work, not even in the presence of a trained professional.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_RESERVED_BITS       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK_BITS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_OPAQUE              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_PREMULTIPLIED_ALPHA &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MULTIPLY            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_ALPHA               &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;3 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK_BITS&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b11&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32 =
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;PRIMITIVE_TOPOLOGY_SHIFT_BITS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;- Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK_BITS&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;count_ones&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For enums, we just define additional constants for each variant. We then check for the variant this way:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|= &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MULTIPLY&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_RESERVED_BITS
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_OPAQUE &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; do opaque blend
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Very similar to booleans, just checking against variants. Straightforward isn’t it? But haven’t you noticed something?&lt;&#x2F;p&gt;
&lt;p&gt;First off, the &lt;code&gt;BLEND_&lt;&#x2F;code&gt; prefix, very reminiscent of C enums. Second, we have lost exhaustivity check!&lt;&#x2F;p&gt;
&lt;p&gt;Consider what happens when we add a new blend mode. We add a new constant, and then, of course, we should update every place that checks the value of the blend bits. But since this is an if&#x2F;else, the compiler can’t remind us to do it if we forget. Furthermore, we forgot to add a bit to the mask &lt;code&gt;BLEND_MASK_BITS&lt;&#x2F;code&gt;, because we now need 3 bits to encode our blend variants, and again, the compiler couldn’t help us.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_RESERVED_BITS       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK_BITS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_OPAQUE              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_PREMULTIPLIED_ALPHA &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MULTIPLY            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_ALPHA               &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;3 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; vvv new variant
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_ADDITIVE            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK_BITS&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b11&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_SHIFT_BITS&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32 =
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;PRIMITIVE_TOPOLOGY_SHIFT_BITS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;- Self&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MASK_BITS&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;count_ones&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; Then when accessing:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|= &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_MULTIPLY&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_RESERVED_BITS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_OPAQUE &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; do opaque blend
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; vvv new variant check
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt; key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_RESERVED_BITS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;BLEND_ADDITIVE &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; do additive blend
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I can tell you, the Bevy rendering code is &lt;em&gt;littered&lt;&#x2F;em&gt; with bit twiddling  like that. And every time there is a change to the rendering code, there is a massive thousand lines diff that conflicts with everything else. It makes unanimity, ask anyone they will tell you they dislike this code.&lt;&#x2F;p&gt;
&lt;p&gt;Also, personally, I found this to be extremely confusing, I had to learn (on top of learning graphics programming) what the hell was going on, and why the silly.&lt;&#x2F;p&gt;
&lt;p&gt;But we finally managed to use a &lt;code&gt;u32&lt;&#x2F;code&gt; for our &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt;. Our hash is indeed &lt;em&gt;dang fast&lt;&#x2F;em&gt;, in fact, it’s order of magnitudes faster. But, that was at the cost of maintainability, which we still pay to this day.&lt;&#x2F;p&gt;
&lt;p&gt;Seemingly, there is a tradeoff between maintainability and performance. We got performance, but we lost:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Readability, accessing a field is now a boolean operation with C-style manual namespacing&lt;&#x2F;li&gt;
&lt;li&gt;We lost exhaustiveness checking&lt;&#x2F;li&gt;
&lt;li&gt;It’s easy to forget to update field offsets and masks&lt;&#x2F;li&gt;
&lt;li&gt;We now depend on the &lt;code&gt;bitflags&lt;&#x2F;code&gt; crate.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But dang! We are using the Rust programming language! What Rust did is tell us that no, we don’t have to choose between performance and maintainability, we can do both! Emphatically!&lt;&#x2F;p&gt;
&lt;p&gt;Engineering is not just about making decision, it knowing about &lt;strong&gt;which&lt;&#x2F;strong&gt; decisions you &lt;strong&gt;can&lt;&#x2F;strong&gt; make.&lt;&#x2F;p&gt;
&lt;p&gt;So let’s make the right decision here and use the nearly forgotten art of bit fields.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll be using a Rust crate called &lt;code&gt;bitbybit&lt;&#x2F;code&gt;. There is a variety of bit field crates, but I choose this one because I can vouch for it, I’ve thouroughfully reviewed it. I’m being told however, that there are better crates you can use.&lt;&#x2F;p&gt;
&lt;p&gt;You remember the asterisk in the “list of drawbacks” slide? There is actually a drawback here. Can you guess at it? It is an additional dependency. Still, compared to &lt;code&gt;bitflags&lt;&#x2F;code&gt;, it’s just &lt;em&gt;a different&lt;&#x2F;em&gt; dependency. But you should be careful about which dependencies you use, and, like me, verify them before using them.&lt;&#x2F;p&gt;
&lt;p&gt;So let’s see how it looks like with &lt;code&gt;bitbybit&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bitfield&lt;&#x2F;span&gt;&lt;span&gt;(u32)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey {
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(0)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;hdr&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(1)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tonemap_in_shader&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(2)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;deband_dither&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(3)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;depth_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(4)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;normal_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(5)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;deferred_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(6)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;motion_vector_prepass&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(7)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;may_discard&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(8)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;environment_map&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(9)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;screen_space_ambient_occlusion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(10)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;depth_clamp_ortho&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(11)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;temporal_jitter&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(12)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;morph_targets&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(13)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;reads_view_transmission_texture&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(14)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;lightmapped&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bit&lt;&#x2F;span&gt;&lt;span&gt;(15)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;irradiance_volume&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; etc.
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This looks very similar to the original struct declaration. Under the cover though, we are doing the exact same bit twiddling as before. In fact, the macro declares &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt; as a newtype over a &lt;code&gt;u32&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Notice that we have an attribute &lt;code&gt;#[bit(x)]&lt;&#x2F;code&gt;. Here, &lt;code&gt;x&lt;&#x2F;code&gt; represents the &lt;em&gt;position&lt;&#x2F;em&gt; in the &lt;code&gt;u32&lt;&#x2F;code&gt; of the field.&lt;&#x2F;p&gt;
&lt;p&gt;Do we really care about where our fields go? &lt;em&gt;Actually yes&lt;&#x2F;em&gt;: Network and hardware protocols use bit fields, where the precise location of bits and their meaning is specified into an RFC or burried in dusty manuals.&lt;&#x2F;p&gt;
&lt;p&gt;C has &lt;a href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;cpp&#x2F;c-language&#x2F;c-bit-fields?view=msvc-170&quot;&gt;a &lt;em&gt;special syntax&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; just for bit fields. But because you cannot control where each bit goes (it is &lt;em&gt;implementation defined&lt;&#x2F;em&gt; because of course everything in C is implementation defined) everybody will tell you to never use bit fields in C. Hence, this is the likely reason no one uses bit fields nowadays anymore.&lt;&#x2F;p&gt;
&lt;p&gt;But here, unlike in C, &lt;em&gt;we have control&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;How do we read and write to fields now? The fields are declared as methods on &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt;. If we were to &lt;em&gt;expand&lt;&#x2F;em&gt; the &lt;code&gt;bitfield&lt;&#x2F;code&gt; macro, it would look as follow:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;set_irradiance_volume&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;irradiance_volume&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;irradiance_volume&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; etc.
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To use them, we just call the methods:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey::builder()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;with_irradiance_volume&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; key.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;irradiance_volume&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; do irradiance volume
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No more bit fiddling, no more weird constants. You just access data with a getter, like the wise Java sages taught you at school. They work the way you expect them to work.&lt;&#x2F;p&gt;
&lt;p&gt;What about enums? bitflags’ devious limitations were brought to light with enums, how does bitbybit handle enums?&lt;&#x2F;p&gt;
&lt;p&gt;So, this is how the rest of the &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt; struct looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bitfield&lt;&#x2F;span&gt;&lt;span&gt;(u32)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MeshPipelineKey {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; bits ..
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(16..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;17)]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;blend&lt;&#x2F;span&gt;&lt;span&gt;: BlendMask,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(18..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;20)]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;msaa&lt;&#x2F;span&gt;&lt;span&gt;: Msaa,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(21..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;23)]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;primitive_topology&lt;&#x2F;span&gt;&lt;span&gt;: PrimitiveTopology,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(24..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;26)]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tonemap_method&lt;&#x2F;span&gt;&lt;span&gt;: TonemapMethod,
&lt;&#x2F;span&gt;&lt;span&gt;    #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(27..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;28)]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;shadow_filter_method&lt;&#x2F;span&gt;&lt;span&gt;: ShadowFilterMethod,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; etc.
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; The enum declarations:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bitenum&lt;&#x2F;span&gt;&lt;span&gt;(u2, exhaustive &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; true)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;Blend {
&lt;&#x2F;span&gt;&lt;span&gt;    Opaque &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b00&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    PremultipliedAlpha &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b01&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    Multiply &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b10&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    Alpha &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0b11&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Instead of specifying a unique bit, we specify a range of bits. We also have to add the &lt;code&gt;bitenum&lt;&#x2F;code&gt; attribute to our enums. With this, &lt;code&gt;bitbybit&lt;&#x2F;code&gt; can tell you if the range is enough to hold the enum in question, and refuses to compile if not. With nice and detailed error messages at compile time and all (I would know, I wrote them). &lt;code&gt;bitbybit&lt;&#x2F;code&gt; can also tell you if the target size of the struct is not enough to hold all the fields.&lt;&#x2F;p&gt;
&lt;p&gt;And we access an enum field as we would expect it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;key.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;set_blend&lt;&#x2F;span&gt;&lt;span&gt;(BlendMask::Opaque);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; key.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;blend&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    BlendMask::Opaque &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;* do opaque blend *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; other blend modes
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We match on an enum, that means that we still have exhaustiveness checking!&lt;&#x2F;p&gt;
&lt;p&gt;OK, it’s &lt;em&gt;technically&lt;&#x2F;em&gt; less efficient.&lt;&#x2F;p&gt;
&lt;p&gt;To find out why, I’ll let you scroll up to the third code listing, the one where we manually do masking, without any external crates. Notice the values of the variants of the &lt;code&gt;Blend&lt;&#x2F;code&gt; enum. They are “pre-shifted”, and when comparing against the value extracted from &lt;code&gt;mesh_pipeline_key&lt;&#x2F;code&gt;, we don’t do any more shifting.&lt;&#x2F;p&gt;
&lt;p&gt;That’s like one less instruction. I mean, in this specific case, the compiler should be able to optimize it.&lt;&#x2F;p&gt;
&lt;p&gt;The moral of the story is that (rarely, but indeed sometimes) we don’t have to chose between maintainability and performance. This time, we picked both.&lt;&#x2F;p&gt;
&lt;p&gt;Don’t let yourself be blinded by false dichotomies.&lt;&#x2F;p&gt;
&lt;p&gt;Remember: engineering is &lt;strong&gt;not just&lt;&#x2F;strong&gt; about making choices. It’s also about knowing &lt;strong&gt;which choices&lt;&#x2F;strong&gt; you can make.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-packed-representation&quot;&gt;On packed representation&lt;&#x2F;h2&gt;
&lt;p&gt;The original talk title was “PSA: you too can pack structs”.&lt;&#x2F;p&gt;
&lt;p&gt;Here, for clarity, I kept using “bit fields”. But in the literature, “packed” is often used interchangeably with “bit fields” (that wouldn’t be the first time CS has confusing naming schemes)&lt;&#x2F;p&gt;
&lt;p&gt;In Rust, you might know of the &lt;code&gt;#[repr(packed)]&lt;&#x2F;code&gt; attribute. It’s the weaker version of bit fields.&lt;&#x2F;p&gt;
&lt;p&gt;I focused on &lt;code&gt;MeshPipelineKey&lt;&#x2F;code&gt; – where &lt;code&gt;packed&lt;&#x2F;code&gt; isn’t relevant – because it was a practical use case with real world application. Here is a different scenario:&lt;&#x2F;p&gt;
&lt;p&gt;We are building the cheese panopticon. A database of the cheese stashes of every person on earth. We start by making a struct to represent cheese stashes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;CheeseType {
&lt;&#x2F;span&gt;&lt;span&gt;    Gruyere,
&lt;&#x2F;span&gt;&lt;span&gt;    Vacherin,
&lt;&#x2F;span&gt;&lt;span&gt;    Raclette,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Cheese {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: CheeseType,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;aged&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;weight_kg&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We are going to have &lt;em&gt;billions&lt;&#x2F;em&gt; of copies of &lt;code&gt;Cheese&lt;&#x2F;code&gt; in memory, so better not take too much memory. Let’s see how many bytes it takes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, std::mem::size_of::&amp;lt;Cheese&amp;gt;());
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; -&amp;gt; 16
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sixteen! This means that Rust uses 128 bits to represent a &lt;code&gt;Cheese&lt;&#x2F;code&gt; datastructure. Let’s see why. We have three fields:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kind&lt;&#x2F;code&gt; is an enum with three variants, 1 byte&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;aged&lt;&#x2F;code&gt; is a boolean value, 1 byte&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;weight_kg&lt;&#x2F;code&gt; is a &lt;code&gt;u64&lt;&#x2F;code&gt;, so 8 bytes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I count 10 bytes, so what’s up? Why is Rust wasting 6 whole bytes for my &lt;code&gt;Cheese&lt;&#x2F;code&gt;?!&lt;&#x2F;p&gt;
&lt;p&gt;Let me explain. You know that in Rust, a reference cannot be null. Specifically, &lt;em&gt;they are always well formed&lt;&#x2F;em&gt;. What does it take for a reference to be well formed?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Can’t be null&lt;&#x2F;li&gt;
&lt;li&gt;Always points to valid data&lt;&#x2F;li&gt;
&lt;li&gt;It respects the &lt;em&gt;alignment&lt;&#x2F;em&gt; of the data type it’s pointing to.&lt;&#x2F;li&gt;
&lt;li&gt;Some other hooey gooey stuff that is a constant headache if you are ever to use &lt;code&gt;unsafe&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So what’s alignment? In short, some machine instructions only work (or are much faster) if the address of an integer it’s loading is a multiple of 1, 2, 4, 8, 16 etc. That address coefficient is what we call “alignment”. If you have ever written C code for ARM devices, you might have encountered a mysterious “Bus Error”. It comes from alignment.&lt;&#x2F;p&gt;
&lt;p&gt;All Rust types have an alignment. For &lt;code&gt;u8&lt;&#x2F;code&gt;, it’s 1, for &lt;code&gt;u16&lt;&#x2F;code&gt; 2, &lt;code&gt;u32&lt;&#x2F;code&gt; 4 and &lt;code&gt;u64&lt;&#x2F;code&gt; 8. (same as its size). When it comes to composite types (ie: struct), the size of the composite must be divisible by all it’s component type’s alignment. In particular, since all alignments are power of two, it just needs to be divisible by its highest component’s alignment. And its alignment will be that.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of &lt;code&gt;Cheese&lt;&#x2F;code&gt;, &lt;code&gt;weight_kg: u64&lt;&#x2F;code&gt; has an alignment of 8. So &lt;code&gt;Cheese&lt;&#x2F;code&gt;, which contains &lt;code&gt;weight_kg&lt;&#x2F;code&gt;, must itself have a size that is divisible by 8. 10 is not divisible by 8, the next best one is 16. So Rust adds 6 bytes of &lt;strong&gt;padding&lt;&#x2F;strong&gt; to each instace of the &lt;code&gt;Cheese&lt;&#x2F;code&gt; struct. Padding is just blank data that has no purpose (in fact, reading it is undefined behavior).&lt;&#x2F;p&gt;
&lt;p&gt;Thanks to this, when your struct is in an array, its fields will always be aligned (ie: you can create valid references to them that won’t trigger bus errors (which are very similar to segmentation faults in term of fun to debug))&lt;&#x2F;p&gt;
&lt;p&gt;In Rust, &lt;code&gt;#[repr(packed)]&lt;&#x2F;code&gt; allows you eliminate padding:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;repr&lt;&#x2F;span&gt;&lt;span&gt;(packed)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Cheese {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: CheeseType,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;aged&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;weight_kg&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; -&amp;gt; size: 10 bytes
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But that &lt;em&gt;does&lt;&#x2F;em&gt; mean that we lose alignment. Since it’s undefined behavior to read from unaligned memory, we actually can’t create references to &lt;code&gt;weight_kg&lt;&#x2F;code&gt; in &lt;code&gt;Cheese&lt;&#x2F;code&gt;, &lt;code&gt;&amp;amp;cheese.weight_kg&lt;&#x2F;code&gt; is a compiler error.&lt;&#x2F;p&gt;
&lt;p&gt;When the struct is not packed, we have this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img style=&quot;width:100%&quot; src=&quot;&#x2F;blog-assets&#x2F;bit-fields-rustfest24&#x2F;alignment-sane.svg&quot;
  alt=&quot;Memory representation for a struct Example that contains a u8 and a u16. In memory, it is represented as 4 bytes, one of them is &#x27;padding&#x27;. A diagram shows that an array of Example represented in memory allows the u16 to always be &#x27;aligned&#x27;.&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;With the &lt;code&gt;#[repr(packed)]&lt;&#x2F;code&gt; attributes, we have the following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img style=&quot;width:100%&quot; src=&quot;&#x2F;blog-assets&#x2F;bit-fields-rustfest24&#x2F;alignment-packed.svg&quot;
  alt=&quot;Memory representation for a struct Example that contains a u8 and a u16. This time, it has the packed attribute. In memory, it is represented as 3 bytes, no more padding. A diagram shows that an array of Example will sometimes have the u16 not correctly aligned.&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So, indeed, &lt;code&gt;#[repr(packed)]&lt;&#x2F;code&gt; can drastically reduce memory usage! Instead of storing 8 &lt;code&gt;Example&lt;&#x2F;code&gt; in our array, we stored 10.&lt;&#x2F;p&gt;
&lt;p&gt;You’ll notice that &lt;code&gt;bitbybit&lt;&#x2F;code&gt; requires a backing storage type. We used &lt;code&gt;u32&lt;&#x2F;code&gt;. But imagine just a second that your data fits perfectly in 33 bits. Would you need to use a &lt;code&gt;u64&lt;&#x2F;code&gt;? There is no padding, but that’s still a lot of wasted memory.&lt;&#x2F;p&gt;
&lt;p&gt;Some bit field crates allow using arrays as backing storage, making it possible to have – for example – &lt;code&gt;[u8; 5]&lt;&#x2F;code&gt; as backing storage. That minimizes memory usage, at the cost of slightly more complex generated code.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The quest for a perfect quasi-random sequence</title>
        <published>2023-07-16T00:00:00+00:00</published>
        <updated>2023-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/quasi-random-sequence/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/quasi-random-sequence/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/quasi-random-sequence/">&lt;p&gt;We want a function that maps sequential values (entities concurrently living
in a scene &lt;em&gt;usually&lt;&#x2F;em&gt; have ids that are sequential) into very different colors
(the hue component of the color, to be specific)&lt;&#x2F;p&gt;
&lt;p&gt;What we are looking for is a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Low-discrepancy_sequence&quot;&gt;so-called “low discrepancy” sequence&lt;&#x2F;a&gt;.
ie: a function &lt;code&gt;f&lt;&#x2F;code&gt; such as for integers in a given range (eg: 101, 102, 103…),
&lt;code&gt;f(i)&lt;&#x2F;code&gt; returns a rational number in the [0..1] range, such as
&lt;code&gt;|f(i) - f(i±1)| ≈ 0.5&lt;&#x2F;code&gt;
(maximum difference of images for neighboring preimages)&lt;&#x2F;p&gt;
&lt;p&gt;AHash is a good random hasher, but it has relatively high discrepancy, so we
need something else. Known good low discrepancy sequences are:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;the-van-der-corput-sequence&quot;&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Van_der_Corput_sequence&quot;&gt;Van Der Corput sequence&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;van_der_corput&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;f32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; leading_zeros &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= if&lt;&#x2F;span&gt;&lt;span&gt; bits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{ bits.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;leading_zeros&lt;&#x2F;span&gt;&lt;span&gt;() };
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; nominator &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; bits.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;reverse_bits&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; leading_zeros;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; denominator &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; bits.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;next_power_of_two&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    nominator &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;as f32 &#x2F;&lt;&#x2F;span&gt;&lt;span&gt; denominator &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;as f32
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;the-gold-kronecker-sequence&quot;&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;extremelearning.com.au&#x2F;unreasonable-effectiveness-of-quasirandom-sequences&#x2F;&quot;&gt;Gold Kronecker sequence&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Note that the implementation suggested in the linked post assumes floats, we have integers&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;gold_kronecker&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;f32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;U64_MAX_F&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;f32 = u64&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;MAX &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;as f32&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; (u64::MAX &#x2F; Φ) rounded down
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;FRAC_U64MAX_GOLDEN_RATIO&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u64 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;11400714819323198485&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    bits.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;wrapping_mul&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;FRAC_U64MAX_GOLDEN_RATIO&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;as f32 &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;U64_MAX_F
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;comparison-of-the-sequences&quot;&gt;Comparison of the sequences&lt;&#x2F;h3&gt;
&lt;p&gt;So they are both pretty good. Both only have a single (!) division and two
&lt;code&gt;u64 as f32&lt;&#x2F;code&gt; conversions.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Both do not care much about the generation (consider that &lt;code&gt;entity.to_bits()&lt;&#x2F;code&gt;
will usually be a value in the form ‘x·2³² + y’)&lt;&#x2F;li&gt;
&lt;li&gt;Kronecker is resilient to regular sequence (eg: 100, 102, 104, 106) while this
kills Van Der Corput (consider that potentially one entity out of two spawned
might be a mesh)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I made a small app to compare the two sequences, available at: https:&#x2F;&#x2F;gist.github.com&#x2F;nicopap&#x2F;5dd9bd6700c6a9a9cf90c9199941883e&lt;&#x2F;p&gt;
&lt;p&gt;At the top, we have Van Der Corput, at the bottom we have the Gold Kronecker. In the video, we spawn a vertical line at the position on screen where the x coordinate is the image of the sequence. The preimages are 1,2,3,4,… The ideal algorithm would always have the largest possible gap between each line (imagine the screen x coordinate as the color hue):&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;assets&#x2F;26321040&#x2F;349aa8f8-f669-43ba-9842-f9a46945e25c&lt;&#x2F;p&gt;
&lt;p&gt;Here, we repeat the experiment, but with with &lt;code&gt;entity.to_bits()&lt;&#x2F;code&gt; instead of a sequence:&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;assets&#x2F;26321040&#x2F;516cea27-7135-4daa-a4e7-edfd1781d119&lt;&#x2F;p&gt;
&lt;p&gt;Notice how Van Der Corput tend to bunch the lines on a single side of the screen. This is because we always skip odd-numbered entities.&lt;&#x2F;p&gt;
&lt;p&gt;The kronecker sequence seems better, so I used it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>What I make of ChatGPT</title>
        <published>2022-12-06T00:00:00+00:00</published>
        <updated>2022-12-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/chat-gpt-first-contact/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/chat-gpt-first-contact/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/chat-gpt-first-contact/">&lt;p&gt;I guess I’ll put my grain to the massive pile of comments regarding Open AI’s
new &lt;a href=&quot;https:&#x2F;&#x2F;chat.openai.com&#x2F;chat&quot;&gt;ChatGPT&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Here is an example:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a command for a POSIX system. &lt;code&gt;fd&lt;&#x2F;code&gt; is an utility similar to &lt;code&gt;find&lt;&#x2F;code&gt;. Describe what it does&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;fd -e&lt;&#x2F;span&gt;&lt;span&gt; png . assets&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span&gt; file &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;cut -d&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt; -f2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;#39;x&amp;#39; &amp;#39;*&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;bc &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;awk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;#39;{x+=$1}END{print(x)}&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The response:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This command uses the fd utility to search for files with the .png extension
within the assets&#x2F; directory and all of its subdirectories. It then pipes the
output of fd to xargs, which is used to run the file command on each of the
files found by fd. The output of file is then passed to cut, which is used to
extract the second field from each line (delimited by commas).&lt;&#x2F;p&gt;
&lt;p&gt;Next, the output of cut is passed to tr, which is used to replace all
occurrences of the letter x with an asterisk (*). The output of tr is then
passed to the bc command, which is a command-line calculator that evaluates
the mathematical expressions passed to it. In this case, the expressions are
the result of replacing the x characters with * symbols in the output of cut.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, the output of bc is passed to awk, which is used to sum up the
values and print the total. The awk command uses the x+=$1 expression to add
the value of the first field on each line to the x variable. At the end, the
END keyword is used to print the value of x, which contains the sum of all
the numbers.&lt;&#x2F;p&gt;
&lt;p&gt;In summary, this command searches for all .png files within the assets&#x2F;
directory and its subdirectories, runs the file command on each file to
extract some information, performs some transformations on the output of
&lt;code&gt;file&lt;&#x2F;code&gt;, calculates the sum of the resulting values using bc and awk, and finally
prints the total.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Hmm, it seems it needs something, let’s do this&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The output of &lt;code&gt;file&lt;&#x2F;code&gt; when ran on a &lt;code&gt;.png&lt;&#x2F;code&gt; file is:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre style=&quot;background-color:#fafafa;color:#383a42;&quot;&gt;&lt;code&gt;&lt;span&gt;assets&#x2F;character.png: PNG image data, 407 x 408, 8-bit&#x2F;color RGB, non-interlaced
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Please reformulate your description taking this into account&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Response:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…]&lt;&#x2F;p&gt;
&lt;p&gt;The output of file is then passed to cut, which is used to extract the
second field from each line (delimited by commas). This field contains
information about the dimensions and color depth of the image, such as
407 x 408, 8-bit&#x2F;color RGB.&lt;&#x2F;p&gt;
&lt;p&gt;[…] This effectively replaces
the x character used to separate the dimensions of the image (e.g. 407 x 408)
with an asterisk, which is used as the multiplication operator in the bc
calculator. For example, the output of tr for the example file output above
would be 407 * 408, 8-bit&#x2F;color RGB.&lt;&#x2F;p&gt;
&lt;p&gt;[…] [Is] then passed to the bc command […] the result of replacing the x
characters with * symbols in the output of cut, and they represent the
dimensions of the image. For example, 407 * 408 would be calculated by bc
to give the total number of pixels in the image.&lt;&#x2F;p&gt;
&lt;p&gt;[…]
In summary, […] calculates the total number of pixels in all the images
using bc and awk, and finally prints the total.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It’s not exactly accurate, but it gets the idea at the end.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rust-pitfall&quot;&gt;Rust pitfall&lt;&#x2F;h2&gt;
&lt;p&gt;Here is a short interaction for code gen&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The following function takes a mutable reference to a slice and two indices
&lt;code&gt;a&lt;&#x2F;code&gt; and &lt;code&gt;b&lt;&#x2F;code&gt;, It returns two mutable references to elements of &lt;code&gt;slice&lt;&#x2F;code&gt;, the
first is the element at index &lt;code&gt;a&lt;&#x2F;code&gt; and the second at index &lt;code&gt;b&lt;&#x2F;code&gt;. Please
replace the TODO comment with the actual implementation&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;two_muts_of_slice&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; [T], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; T, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; T) {
&lt;&#x2F;span&gt;&lt;span&gt;  assert_ne!(a, b);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; TODO
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Response:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;two_muts_of_slice&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; [T], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; T, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; T) {
&lt;&#x2F;span&gt;&lt;span&gt;  assert_ne!(a, b);
&lt;&#x2F;span&gt;&lt;span&gt;  assert!(a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(first, second) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;split_at_mut&lt;&#x2F;span&gt;&lt;span&gt;(b);
&lt;&#x2F;span&gt;&lt;span&gt;  (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; first[a], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; second[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ahah! Can you spot the mistake?&lt;&#x2F;p&gt;
&lt;p&gt;Well here is what happens next. I ask:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is this code correct if a &amp;gt; b?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It responds:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;No, the code would not work correctly if a is greater than b. This is
because the &lt;code&gt;split_at_mut()&lt;&#x2F;code&gt; method splits the slice at index b and returns a
mutable reference to the elements before index b as the first sub-slice,
and a mutable reference to the elements at and after index b as the second
sub-slice. If a is greater than b, the element at index a would be in the
second sub-slice, not the first.&lt;&#x2F;p&gt;
&lt;p&gt;Here is an updated implementation that works correctly for any values of a and b:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;two_muts_of_slice&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; [T], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; T, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; T) {
&lt;&#x2F;span&gt;&lt;span&gt;  assert_ne!(a, b);
&lt;&#x2F;span&gt;&lt;span&gt;  assert!(a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; b {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(first, second) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;split_at_mut&lt;&#x2F;span&gt;&lt;span&gt;(b);
&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; first[a], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; second[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(first, second) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;split_at_mut&lt;&#x2F;span&gt;&lt;span&gt;(a);
&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; second[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; first[b])
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Also notice how it’s almost gaslighting me, I somehow get the feeling it’s my
fault if I didn’t tell it to account for the obvious (for me at least) “edge
case”.&lt;&#x2F;p&gt;
&lt;p&gt;The updated code is very close to what I would have written myself, so
congratulation!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;other-prompts&quot;&gt;Other prompts&lt;&#x2F;h2&gt;
&lt;p&gt;There is a few more tasks I played with ChatGPT. It’s &lt;strong&gt;really good&lt;&#x2F;strong&gt; at
manipulating code. For example, I got it to refactor duplicate code, or extract
multiple &lt;code&gt;println&lt;&#x2F;code&gt;s into a single constant string. It’s also pretty
decent at describing programs, even non-trivial ones. Especially useful for
bash scripts I think, but also seemingly obfuscated optimized code. It’s also a
nice crutch if you want a starting point from where to write some code (good
riddance, writer’s block!).&lt;&#x2F;p&gt;
&lt;p&gt;In general, it’s just excellent when you know exactly what you want and&#x2F;or have
the expertise necessary to nudge it in the right direction. But it’s just awful
when you don’t know what pitfall to look for. It’s also downright consistently
wrong when asking for guidance or recommendations on specialized topics. It’s
output is still useful as a way to navigate a sort of concept tree. It’s much
easier to learn about rolling hash interactively through ChatGPT that trying to
decipher the Wikipedia article, although ChatGPT has been both
consistently and persistently wrong in its applicability. Same with Yocto
Linux.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cyberiadic-ai&quot;&gt;Cyberiadic AI&lt;&#x2F;h2&gt;
&lt;p&gt;It reminds me a lot of the various machines Trurl builds in &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;The_Cyberiad&quot;&gt;The Cyberiads&lt;&#x2F;a&gt;, as
soon as it is finished, it replies to “what four and four does?” with “seven”
and persists into defending that point so much so that it starts uprooting itself
and chasing its creator.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, the most memorable machine of Trurl’s is the Electronic Bard. A
machine so good at poetry that it causes every artist to give up on life.&lt;&#x2F;p&gt;
&lt;p&gt;Note that I’m now kinda in the same boat as the poets in the Cyberiads. What’s
the point of writing any code or text if ChatGPT can generate in a second a
tome ten times more efficient or elegant? ChatGPT is definitively not capable
of that, but this is a question I ask myself every time I write something now,
it’s a bit terrifying.&lt;&#x2F;p&gt;
&lt;p&gt;I couldn’t resist reproducing the prompt Klapaucius uses to test the machine and
results in the most amazing bit of sci-fi poetry ever written (The English
translation is remarkable)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s have a love poem, lyrical, pastoral, and expressed in the language of
pure mathematics. Tensor algebra mainly, with a little topology and higher
calculus, if need be. But with feeling, you understand, and in the cybernetic
spirit.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ChatGPT:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a world of ones and zeros,&lt;br&gt;
Our love is a complex vector,&lt;br&gt;
A tensor of boundless grace,&lt;br&gt;
Defined by a single equation.&lt;&#x2F;p&gt;
&lt;p&gt;Our passion is a topological knot,&lt;br&gt;
A Moebius strip of endless twists,&lt;br&gt;
Our bound a higher-dimensional space,&lt;br&gt;
Where hearts and minds merge and coexist.&lt;&#x2F;p&gt;
&lt;p&gt;And as we navigate this digital realm,&lt;br&gt;
Our love remains constant,&lt;br&gt;
A matrix of unbreakable trust,&lt;br&gt;
A formula for perfect harmony.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It picked up amazingly the vocabulary in the quoted domains of mathematics!
Also quotes a mathematician. The version from Trurl’s machine is of course
written by Stanisław Lem (and Michael Kandel for the English version). It
captures perfectly the naivety and horniness of love poems and makes fun of it
(in the cybernetic spirit, you understand) masterfully.&lt;&#x2F;p&gt;
&lt;p&gt;The three paragraphs ChatGPT generated are nothing compared to it (though make
sure you check the rhymes more carefully, there are more than at first glance!)
but it’s beyond anything a computer ever was capable of doing previously.&lt;&#x2F;p&gt;
&lt;p&gt;Comparing this to state of the art in 2018 (merely 5 years ago!) we are
about five orders of magnitude better.&lt;&#x2F;p&gt;
&lt;p&gt;Of all the sci-fi AIs we conceived in the 20th century, we end up with the AIs
from the Cyberaids. Amazing! Looking forward to countering superintelligent
entities with bureaucracy.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Optimizing the day 6 Advent of Code 2022 challenge a little too much</title>
        <published>2022-12-06T00:00:00+00:00</published>
        <updated>2022-12-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/day6-advent-2022/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/day6-advent-2022/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/day6-advent-2022/">&lt;p&gt;&lt;strong&gt;WARNING:&lt;&#x2F;strong&gt; Spoilers ahead for the thing mentioned in the title.&lt;&#x2F;p&gt;
&lt;p&gt;Today’s (2022-12-06) AOC (&lt;a href=&quot;https:&#x2F;&#x2F;adventofcode.com&quot;&gt;Advent of Code&lt;&#x2F;a&gt;) was easier than yesterday’s if
you have been doing it in rust.&lt;&#x2F;p&gt;
&lt;p&gt;You basically just have to implement code that finds the ending index of
the first sequence of N bytes in a given input where no two bytes are the same.&lt;&#x2F;p&gt;
&lt;p&gt;It is relatively trivial to do in rust. Here is my initial implementation.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all_distinct&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T: Clone &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span&gt;Ord&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[T]) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; slice_copy &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;to_vec&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    slice_copy.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;sort_unstable&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    slice_copy.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;windows&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;pair&lt;&#x2F;span&gt;&lt;span&gt;| pair[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;!=&lt;&#x2F;span&gt;&lt;span&gt; pair[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;first_unique&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T: Clone &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span&gt;Ord&amp;gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;datastream&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[T],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;required_distinct&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Option&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    datastream
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;windows&lt;&#x2F;span&gt;&lt;span&gt;(required_distinct)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;enumerate&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;find_map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;)| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all_distinct&lt;&#x2F;span&gt;&lt;span&gt;(slice).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;then_some&lt;&#x2F;span&gt;&lt;span&gt;(i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; required_distinct))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; input &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;std::io::stdin().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;lines&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;into_bytes&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; output &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;first_unique&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;input, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;{output}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ez-pz &lt;&#x2F;p&gt;
&lt;p&gt;Could have ended here, but as your scrollbar may hint, that wasn’t accounting
for &lt;code&gt;@Toby&lt;&#x2F;code&gt; on the bevy discord
implementing a benchmarking suite to compare the performance of each
solutions people posted in the &lt;code&gt;#off-topic&lt;&#x2F;code&gt; channel.&lt;&#x2F;p&gt;
&lt;p&gt;From now on I’ll refer to &lt;code&gt;required_distinct&lt;&#x2F;code&gt; by &lt;code&gt;W&lt;&#x2F;code&gt;. I’ll also refer to the
input length by &lt;code&gt;N&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;solution name&lt;&#x2F;th&gt;&lt;th&gt;runtime (ns)&lt;&#x2F;th&gt;&lt;th&gt;&lt;code&gt;W&lt;&#x2F;code&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;hashet&lt;&#x2F;td&gt;&lt;td&gt;244,760&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;manevillef&lt;&#x2F;td&gt;&lt;td&gt;242,403&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;nicopap&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;123,600&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;4&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;snaketwix&lt;&#x2F;td&gt;&lt;td&gt;50,000&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;vec&lt;&#x2F;td&gt;&lt;td&gt;153,107&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;–––––––&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;hashet&lt;&#x2F;td&gt;&lt;td&gt;1,792,000&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;manevillef&lt;&#x2F;td&gt;&lt;td&gt;1,239,000&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;nicopap&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;699,000&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;14&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;snaketwix&lt;&#x2F;td&gt;&lt;td&gt;106,000&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;vec&lt;&#x2F;td&gt;&lt;td&gt;1,764,677&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;I’m fairing pretty well for an &lt;em&gt;a priori&lt;&#x2F;em&gt; very naive implementation
optimized for readability.
But &lt;code&gt;snaketwix&lt;&#x2F;code&gt; clearly has the lead. The reason is that, unlike all the other
Solutions, they only iterates over the input once. They have a &lt;code&gt;VecDeque&lt;&#x2F;code&gt; to keep
track of already seen characters and dropping them when they go out of the
window. So their solution has a complexity of &lt;code&gt;O(N)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;My solution uses
&lt;code&gt;windows(required_distinct)&lt;&#x2F;code&gt; and does an operation per element of that window
(both a &lt;code&gt;sort_unstable&lt;&#x2F;code&gt; and a linear adjacent element comparison). It also
allocates a whole &lt;code&gt;Vec&lt;&#x2F;code&gt; per stream element, going to a complexity of
&lt;code&gt;O(N * (W + W * log(W))) = O(N * W * log(W))&lt;&#x2F;code&gt;. This is clearly visible when &lt;code&gt;W&lt;&#x2F;code&gt;
is increased in the benchmarks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;first-optimization&quot;&gt;First optimization&lt;&#x2F;h2&gt;
&lt;p&gt;Suddenly invaded by a Zachtronician sense of optimization, I decided to
go down the rabbit hole.&lt;&#x2F;p&gt;
&lt;p&gt;Allocation is a well known source of slowdown. Especially if recurrent. Each
new allocation can put the allocated data at widely different position in
memory. When reading that data, it might evict the CPU cache and result in a
few thousands cycles of slowdown.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to “hoist” (aka moving outside of a loop) the &lt;code&gt;Vec&lt;&#x2F;code&gt; allocated in
&lt;code&gt;all_distinct&lt;&#x2F;code&gt;. Since I call &lt;code&gt;all_distinct&lt;&#x2F;code&gt; in a loop, I must now accept the
&lt;code&gt;Vec&lt;&#x2F;code&gt; as a function parameter, I’ll just initialize the &lt;code&gt;Vec&lt;&#x2F;code&gt; in
&lt;code&gt;first_unique&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; Now we have a &amp;amp;mut Vec&amp;lt;T&amp;gt; as parameter    vvvvvvvvvvvvvvvvvvvvvvvv
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all_distinct&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T: Clone &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span&gt;Ord&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[T], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;collect_vec&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut &lt;&#x2F;span&gt;&lt;span&gt;Vec&amp;lt;T&amp;gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; `Vec::clear` removes all elements while keeping the pre-existing capacity.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; Perfect, since `slice` will always have the same length.
&lt;&#x2F;span&gt;&lt;span&gt;    collect_vec.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    slice.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;clone_into&lt;&#x2F;span&gt;&lt;span&gt;(collect_vec);
&lt;&#x2F;span&gt;&lt;span&gt;    collect_vec.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;sort_unstable&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    collect_vec.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;windows&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;pair&lt;&#x2F;span&gt;&lt;span&gt;| pair[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;!=&lt;&#x2F;span&gt;&lt;span&gt; pair[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;first_unique&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T: Clone &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span&gt;Ord&amp;gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;datastream&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[T],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;required_distinct&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Option&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; The Vec is initialized here, outside of the find_map, before we iterate.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; collect_vec &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Vec::with_capacity(required_distinct);
&lt;&#x2F;span&gt;&lt;span&gt;    datastream
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;windows&lt;&#x2F;span&gt;&lt;span&gt;(required_distinct)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;enumerate&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;find_map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;)| {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; must pass it as argument vvvvvvvv
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all_distinct&lt;&#x2F;span&gt;&lt;span&gt;(slice, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; collect_vec).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;then_some&lt;&#x2F;span&gt;&lt;span&gt;(i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; required_distinct)
&lt;&#x2F;span&gt;&lt;span&gt;        })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; input &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;std::io::stdin().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;lines&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;into_bytes&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; output &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;first_unique&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;input, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;{output}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;solution name&lt;&#x2F;th&gt;&lt;th&gt;runtime (ns)&lt;&#x2F;th&gt;&lt;th&gt;&lt;code&gt;W&lt;&#x2F;code&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;hashet&lt;&#x2F;td&gt;&lt;td&gt;344,420&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;manevillef&lt;&#x2F;td&gt;&lt;td&gt;338,375&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;nicopap&lt;&#x2F;td&gt;&lt;td&gt;166,605&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;nicopap_hoist&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;6,410&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;4&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;snaketwix&lt;&#x2F;td&gt;&lt;td&gt;59,685&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;vec&lt;&#x2F;td&gt;&lt;td&gt;212,330&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;–––––––&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;hashet&lt;&#x2F;td&gt;&lt;td&gt;2,126,025&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;manevillef&lt;&#x2F;td&gt;&lt;td&gt;1,654,485&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;nicopap&lt;&#x2F;td&gt;&lt;td&gt;931,946&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;nicopap_hoist&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;618,202&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;14&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;snaketwix&lt;&#x2F;td&gt;&lt;td&gt;130,358&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;vec&lt;&#x2F;td&gt;&lt;td&gt;2,406,825&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;(yep, that’s a 26× speedup on &lt;code&gt;W&lt;&#x2F;code&gt; = 4)&lt;&#x2F;p&gt;
&lt;p&gt;Notice that &lt;code&gt;nicopap_hoist&lt;&#x2F;code&gt; is two times faster than the &lt;code&gt;snaketwix&lt;&#x2F;code&gt; solution
on &lt;code&gt;W&lt;&#x2F;code&gt; = 4. This may be because their solution rely heavily on &lt;code&gt;HashMap&lt;&#x2F;code&gt; and
inserting&#x2F;popping from a &lt;code&gt;VecDeque&lt;&#x2F;code&gt;. For small &lt;code&gt;W&lt;&#x2F;code&gt;, the overhead of the
&lt;code&gt;HashMap&lt;&#x2F;code&gt; is greater than the additional operations of an  &lt;code&gt;O(N * W * log(W))&lt;&#x2F;code&gt;
impl with no overhead otherwise.&lt;&#x2F;p&gt;
&lt;p&gt;Now the question of why we got a &lt;strong&gt;27 times speedup&lt;&#x2F;strong&gt; for &lt;code&gt;W&lt;&#x2F;code&gt; = 4, while only
having a 1.5 speedup for &lt;code&gt;W&lt;&#x2F;code&gt; = 14. I actually have no idea.
It might be that allocating a &lt;code&gt;Vec&lt;&#x2F;code&gt; is as slow as &lt;code&gt;W&lt;&#x2F;code&gt; = 7.&lt;&#x2F;p&gt;
&lt;p&gt;Removing such overhead would indeed result in about 6 times speedup on very
small &lt;code&gt;W&lt;&#x2F;code&gt; and &lt;code&gt;&amp;lt;2&lt;&#x2F;code&gt; speedups on larger &lt;code&gt;W&lt;&#x2F;code&gt;. There might be other optimizations
kicking in, but I wouldn’t be able to name them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;second-optimization&quot;&gt;Second Optimization&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;snaketwix&lt;&#x2F;code&gt;’s solution has a &lt;code&gt;O(N)&lt;&#x2F;code&gt; complexity. Could we reach such complexity
level without what seems like overhead introduced by &lt;code&gt;HashMap&lt;&#x2F;code&gt;? Answer is: nay.
But yet we can do better.&lt;&#x2F;p&gt;
&lt;p&gt;We have one major issue with our implementation: Sorting each windows. This
represents a significant computing cost, repeated &lt;code&gt;N&lt;&#x2F;code&gt; times. Especially since
we have to copy the whole slice to our &lt;code&gt;Vec&lt;&#x2F;code&gt; (even if pre-allocated) each time
in addition to sorting it.&lt;&#x2F;p&gt;
&lt;p&gt;Why are we sorting? Simply put: we want to detect duplicates. There is of
course better ways to detect duplicates.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-set&quot;&gt;A set&lt;&#x2F;h3&gt;
&lt;p&gt;Most notably, we could – instead of copying each element to a new &lt;code&gt;Vec&lt;&#x2F;code&gt;,
sorting them, and then comparing them pair-wise – just, you know, add them one
after the others to a sort of set, and check each time if it is already in the
set. This already reduces the time complexity of our stuff from &lt;code&gt;O(N * W * log(W))&lt;&#x2F;code&gt;
to &lt;code&gt;O(N * W)&lt;&#x2F;code&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;But as you might have noticed, it’s a pretty bad idea. All those solutions that
are about twice slower than my implementation do exactly this.&lt;&#x2F;p&gt;
&lt;p&gt;Why are they
slower if they have a lower complexity? Simply put, &lt;code&gt;O&lt;&#x2F;code&gt; (big O notation, what I
have been referring to as “complexity”) is a &lt;em&gt;limit&lt;&#x2F;em&gt;, this means that for small
values of &lt;code&gt;N&lt;&#x2F;code&gt; and &lt;code&gt;W&lt;&#x2F;code&gt;, complexity is not a good indicator of runtime. Most of
the time other constant overhead are so great that the complexity start to
be useful to have an idea of runtime only after the variables in the expression
are greater than a hundred thousands. For &lt;a href=&quot;https:&#x2F;&#x2F;www.quantamagazine.org&#x2F;new-algorithm-breaks-speed-limit-for-solving-linear-equations-20210308&#x2F;&quot;&gt;some algorithms&lt;&#x2F;a&gt; constant overhead
can be so great that the big O notation is only good as a purely theoretical
construct.&lt;&#x2F;p&gt;
&lt;p&gt;In this particular case, the “better” solutions are slower because they use
&lt;code&gt;HashSet&lt;&#x2F;code&gt; (or &lt;code&gt;HashMap&lt;&#x2F;code&gt;). Hashing is indeed a constant time operation, but it’s
fairly costly. On top of that, they add a level of indirection that might kill
somewhat cache coherency again. This makes using the rust standard library
impractical.&lt;&#x2F;p&gt;
&lt;p&gt;So what alternative do we have? Well…&lt;&#x2F;p&gt;
&lt;p&gt;When doing some improvements to the bevy game engine, I came across &lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;fixedbitset&quot;&gt;bitsets&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;.
It’s a &lt;em&gt;cool&lt;&#x2F;em&gt; data structure where an individual element can be represented as a
single bit. We can then check the bit for set ownership.&lt;&#x2F;p&gt;
&lt;p&gt;Our input is explicitly only single letters from the alphabet. So to encode a
set of input elements, we only need a total of 26 bits! Hell, this means we
could simply encode a bitset as a &lt;code&gt;u32&lt;&#x2F;code&gt;! (Has 32 &amp;gt; 26 bits)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;AlphabetSet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;AlphabetSet {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F;&#x2F; Add letter to set, return `true` if it is already part of it.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F;&#x2F; `symbol` must be an ascii latin alphabet letter.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;add_letter_or_contains&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; to_set &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span&gt;(symbol.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;wrapping_sub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;#39;a&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;as u32&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; already_set &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; to_set &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span&gt; to_set;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;|=&lt;&#x2F;span&gt;&lt;span&gt; to_set;
&lt;&#x2F;span&gt;&lt;span&gt;        already_set
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s not rocket science, and it’s very efficient. I’ve even used bitsets for
&lt;a href=&quot;https:&#x2F;&#x2F;devildahu.ch&#x2F;devlog&#x2F;gba-c-to-rust&#x2F;&quot;&gt;my GBA game&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In that snippet, I subtract from &lt;code&gt;symbol&lt;&#x2F;code&gt; (the alphabet character from the
input) the &lt;code&gt;u8&lt;&#x2F;code&gt; value of &lt;code&gt;a&lt;&#x2F;code&gt; (so that the value of alphabet letters are in
[0..26]), and then I “add it to
the set” by setting the bit in the “set” (our &lt;code&gt;u32&lt;&#x2F;code&gt;) that corresponds to our
letter to &lt;code&gt;1&lt;&#x2F;code&gt; (&lt;code&gt;self.0 |= 1 &amp;lt;&amp;lt; [alphabet_index]&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all_distinct&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;]) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; set &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;AlphabetSet::new();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;slice
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;any&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;letter&lt;&#x2F;span&gt;&lt;span&gt;| set.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;add_letter_or_contains&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;letter))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; sop stands for &amp;quot;start of packet&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;first_sop&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; W: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;datastream&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;]) -&amp;gt; Option&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    datastream
&lt;&#x2F;span&gt;&lt;span&gt;        .array_windows::&amp;lt;W&amp;gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;enumerate&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;find_map&lt;&#x2F;span&gt;&lt;span&gt;(|(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span&gt;)| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;all_distinct&lt;&#x2F;span&gt;&lt;span&gt;(slice).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;then_some&lt;&#x2F;span&gt;&lt;span&gt;(i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; W))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; input &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;stdin&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;lines&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;into_bytes&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; output &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;first_sop::&amp;lt;14&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;input).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;{output}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(I also swapped to use &lt;code&gt;array_windows&lt;&#x2F;code&gt; over &lt;code&gt;windows&lt;&#x2F;code&gt;, for exoticism, since
&lt;code&gt;windows&lt;&#x2F;code&gt; will definitively generate the same final assembly)&lt;&#x2F;p&gt;
&lt;p&gt;Then we just need to replace the &lt;code&gt;all_distinct&lt;&#x2F;code&gt; function to use the
&lt;code&gt;AlphabetSet&lt;&#x2F;code&gt;. Specifically, we return from &lt;code&gt;add_letter_or_contains&lt;&#x2F;code&gt; a bool
telling if the letter was already encountered.&lt;&#x2F;p&gt;
&lt;p&gt;That’s it. It’s still &lt;code&gt;O(N * W)&lt;&#x2F;code&gt;, but &lt;code&gt;W&lt;&#x2F;code&gt; here grow by about 5 CPU cycle per
&lt;code&gt;W&lt;&#x2F;code&gt;, so unlike the hoist solution (which still was relatively light on CPU cycle growth per &lt;code&gt;W&lt;&#x2F;code&gt;,
I’d say 100 or so) there shouldn’t be a drastic difference between relatively
close values of &lt;code&gt;W&lt;&#x2F;code&gt;. To rephrase: This means the runtime of the solution should
grow still linearly but much slower than with hoist. Maybe so little that we’ll
beat more theoretically efficient solutions
(since we are talking about close to 0 overhead here).&lt;&#x2F;p&gt;
&lt;p&gt;Now let’s see our benchmarks…&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;solution name&lt;&#x2F;th&gt;&lt;th&gt;runtime (ns)&lt;&#x2F;th&gt;&lt;th&gt;&lt;code&gt;W&lt;&#x2F;code&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;hashet&lt;&#x2F;td&gt;&lt;td&gt;344,360&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;manevillef_2&lt;&#x2F;td&gt;&lt;td&gt;169,767&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;nicopap&lt;&#x2F;td&gt;&lt;td&gt;158,936&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;nicopap_hoist&lt;&#x2F;td&gt;&lt;td&gt;6,527&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;nicopap_bitset&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;5,197&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;4&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;snaketwix&lt;&#x2F;td&gt;&lt;td&gt;58,178&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;vec&lt;&#x2F;td&gt;&lt;td&gt;113,473&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;–––––––&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;hashet&lt;&#x2F;td&gt;&lt;td&gt;2,144,092&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;manevillef_2&lt;&#x2F;td&gt;&lt;td&gt;1,085,112&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;nicopap&lt;&#x2F;td&gt;&lt;td&gt;919,232&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;nicopap_hoist&lt;&#x2F;td&gt;&lt;td&gt;623,370&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;nicopap_bitset&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;24,871&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;14&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;snaketwix&lt;&#x2F;td&gt;&lt;td&gt;118,899&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;vec&lt;&#x2F;td&gt;&lt;td&gt;2,141,100&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Outrageously fast!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;going-further&quot;&gt;Going further&lt;&#x2F;h2&gt;
&lt;p&gt;I didn’t explore faster possibilities, but &lt;code&gt;@Verte&lt;&#x2F;code&gt; proposed an interesting
solution, very similar to mine. Instead of using
&lt;code&gt;!windows.any([add_or_contains])&lt;&#x2F;code&gt;, they simply Add &lt;strong&gt;all&lt;&#x2F;strong&gt; the letters from the
window to the bitset and count how many bits are set (this can be done in a single
instruction with &lt;code&gt;u32::count_ones&lt;&#x2F;code&gt;) If the number of bits is equal to the
number of elements, it means all the elements are unique!&lt;&#x2F;p&gt;
&lt;p&gt;This is pretty good, and possibly more efficient than my solution. In my case,
I early exit as soon as a duplicate is found. This translates in the generated
assembly by a single jump instruction after each comparison. Due to branch
prediction and pipeline invalidation, Verte’s solution might really be better.&lt;&#x2F;p&gt;
&lt;p&gt;The CPU has an instruction pipeline, it preloads the next few instructions it
will execute. Problem is that when encountering a conditional jump instruction,
the next few instructions become unknown since it’s impossible to know the
value of the predicate before evaluating it. So if it didn’t load the correct
instructions, it will need to clear the pipeline and reload the next
instructions, causing a &lt;em&gt;stall&lt;&#x2F;em&gt; of a few cycles to a few hundred cycles
depending on the context.&lt;&#x2F;p&gt;
&lt;p&gt;Just unconditionally adding up all the letters to the bit set, then acting on
it fixes that problem, and enables the potential for vectorization (aka
automatic SIMD instructions)&lt;&#x2F;p&gt;
&lt;p&gt;I didn’t test it yet, but I could expect a 4× speedup.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Warlock&#x27;s Gambit trace analysis</title>
        <published>2022-09-01T00:00:00+00:00</published>
        <updated>2022-09-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/warlocks-bevy-trace-analysis/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/warlocks-bevy-trace-analysis/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/warlocks-bevy-trace-analysis/">&lt;p&gt;I did some analysis on the traces of warlock’s gambit.&lt;&#x2F;p&gt;
&lt;p&gt;I captured traces both using Chromium’s dev tools and bevy’s &lt;code&gt;trace_chrome&lt;&#x2F;code&gt;
features. I usually use the &lt;code&gt;trace_tracy&lt;&#x2F;code&gt; feature, and run &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wolfpld&#x2F;tracy&quot;&gt;tracy&lt;&#x2F;a&gt;, but
this time, for the benefit of a potential employer (and my curiosity),
I decided to try out the chrome version.&lt;&#x2F;p&gt;
&lt;p&gt;Sadly, the trace as captured by chrome in the WASM stack do not help much.&lt;&#x2F;p&gt;
&lt;p&gt;The rust symbols show up, but bevy relies heavily on type erasure both for
performance and ergonomics.&lt;&#x2F;p&gt;
&lt;p&gt;Specifically the game systems are added to a scheduler as an erased function,
and ran each frame. Using the argument types of the function, the scheduler
knows which systems touches which components, and only runs in parallel
systems that do not touch mutably the same components. This allows automatic
concurrency, but at the cost of decoupling the running of game systems from
their declaration, thus losing a lot of “free” debugging tools.&lt;&#x2F;p&gt;
&lt;p&gt;However, bevy smartly sets up custom tracing events, actually associating
the system ran with the name of the function of the system. Bevy uses the
&lt;code&gt;tracing-wasm&lt;&#x2F;code&gt; crate for tracing on wasm, sadly, I didn’t manage to get
it working. It seems chrome has difficulties properly understanding the
trace event hierarchy.&lt;&#x2F;p&gt;
&lt;p&gt;Follows the tracing files for native and chrome telemetry:&lt;&#x2F;p&gt;
&lt;p&gt;Both traces are in the chrome tracing format, so they work in the same tools.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been recommended to use &lt;a href=&quot;https:&#x2F;&#x2F;ui.perfetto.dev&#x2F;&quot;&gt;https:&#x2F;&#x2F;ui.perfetto.dev&#x2F;&lt;&#x2F;a&gt; to inspect chrome traces,
but I fond in the chromium dev website  &lt;a href=&quot;https:&#x2F;&#x2F;speedscope.app&quot;&gt;https:&#x2F;&#x2F;speedscope.app&lt;&#x2F;a&gt; and I find it
much better. The sandwich view makes understanding what takes most time a piece
of cake (or sandwich as the name would have it).&lt;&#x2F;p&gt;
&lt;p&gt;speedscope has three views accessible through the top left bar:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Time order (the classical trace view)&lt;&#x2F;li&gt;
&lt;li&gt;Left heavy (shows to the left the longest spans)&lt;&#x2F;li&gt;
&lt;li&gt;Sandwich (show as list, allowing you to order by “self” time or total run time)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;“self” time is the time a span ran minus inner span runtime. &lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;center&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-center &quot;&gt;&lt;code class=&quot;language-center&quot; data-lang=&quot;center&quot;&gt;&lt;span&gt;fn fun1() {
&lt;&#x2F;span&gt;&lt;span&gt;    takes_a_lot_of_time();
&lt;&#x2F;span&gt;&lt;span&gt;    span2();
&lt;&#x2F;span&gt;&lt;span&gt;    span3();
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;fn fun2() {
&lt;&#x2F;span&gt;&lt;span&gt;    span2();
&lt;&#x2F;span&gt;&lt;span&gt;    span3();
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, &lt;code&gt;fun2&lt;&#x2F;code&gt; does no work beside calling other functions with spans, meaning its
self time is very low. While &lt;code&gt;fun1&lt;&#x2F;code&gt; will have a long self time. Self time tells
you which function to optimize.&lt;&#x2F;p&gt;
&lt;p&gt;I recommend you get familiar with the sandwich view, because it is the fastest
way to figure out what is slowing down your app.&lt;&#x2F;p&gt;
&lt;p&gt;Following is the “left heavy” view in speedscope.app for warlock’s traces.
Click on the heading to download the file.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;native-traces&quot;&gt;&lt;a href=&quot;&#x2F;blog-assets&#x2F;warlocks-bevy-trace-analysis&#x2F;trace_native.json&quot; download&gt;native traces&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;div class=&quot;spill&quot;&gt;
&lt;img style=&quot;max-width:100%&quot;
    src=&quot;&#x2F;blog-assets&#x2F;warlocks-bevy-trace-analysis&#x2F;warlocks-native-trace.png&quot;
    alt=&quot;native trace generated with speedscope.app&quot;
&gt;
&lt;&#x2F;div&gt;
&lt;h4 id=&quot;chrome-traces&quot;&gt;&lt;a href=&quot;&#x2F;blog-assets&#x2F;warlocks-bevy-trace-analysis&#x2F;trace_chrome.json&quot; download&gt;chrome traces&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;div class=&quot;spill&quot;&gt;
&lt;img style=&quot;max-width:100%&quot;
    src=&quot;&#x2F;blog-assets&#x2F;warlocks-bevy-trace-analysis&#x2F;warlocks-chrome-trace.png&quot;
    alt=&quot;chrome trace generated with speedscope.app&quot;
&gt;
&lt;&#x2F;div&gt;
&lt;h4 id=&quot;analysis&quot;&gt;Analysis&lt;&#x2F;h4&gt;
&lt;p&gt;The native trace will take about 5 minutes to open on &lt;a href=&quot;https:&#x2F;&#x2F;speedscope.app&quot;&gt;https:&#x2F;&#x2F;speedscope.app&lt;&#x2F;a&gt;,
but here is what I can get out of it:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Notice that 30% of runtime is &lt;code&gt;prepare_systems&lt;&#x2F;code&gt; self time! It’s the method
responsible for reading systems access types and scheduling them according
to their declared dependency and mutual exclusivity (exclusive writes etc.)
That time is completely unreasonable, and planned for removal with the
new scheduler rewrite.&lt;&#x2F;p&gt;
&lt;p&gt;But this doesn’t concern wasm at all! Since wasm is single-threaded,
&lt;code&gt;prepare_systems&lt;&#x2F;code&gt; is simply skipped, since everything is sequential anyway.
This implies that the WASM version is potentially faster than the native version&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore, I’m personally offended how bevy handles scheduling. The system
list is static since the first frame, yet, the dependency calculation is ran
every frame. In addition, the graph building code is very inelegant, and
naturally O(n²), &lt;code&gt;n&lt;&#x2F;code&gt; being the system count. This is especially damning
in the render extract stage where about a hundred systems are scheduled.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The second most expensive code seems to be rendering. Inspecting the chrome
trace, it seems most time is spent queuing GPU commands. It is probably that
bevy could minimize that, given that we have at most 30 sprites on screen here. &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The third most expensive function finally seems to be the lighting extraction
method. There is no lights and all materials are unlit, I’m really not sure
what bevy is doing there.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The systems warlock’s gambit has control over are difficult to catch,
especially since the names are mangled, even using bevy’s tracing feature,
due to usage of states, which are also due to be replaced. You can find some
in the &lt;code&gt;CoreStage::Update&lt;&#x2F;code&gt; span.&lt;&#x2F;p&gt;
&lt;p&gt;One of our dependencies, used to select cards with ray casting, is visible
in &lt;code&gt;CoreStage::First&lt;&#x2F;code&gt;, but you can see that compared to bevy’s overhead, its
impact is minimal&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;With this insight, I’ll probably be able to help optimize bevy a little bit.
I won’t touch the scheduling, since it is currently being rewritten. But it
seems some low hanging fruits are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;check_visibility&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;prepare_lights&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;prepare_windows&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Can&#x27;t we do better than the current dev workflow?</title>
        <published>2022-07-24T00:00:00+00:00</published>
        <updated>2022-07-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/rock-age-ci/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/rock-age-ci/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/rock-age-ci/">&lt;p&gt;CI sucks.
Tests take forever,
fail spuriously or magically starts to fail in new and amusing ways,
it requires constant attention, even more than an baby breastfed with prunes.&lt;&#x2F;p&gt;
&lt;p&gt;Git sucks. No need to lament about complexity, just get used to it,
my issue is how it barely helps with asynchronous development.
Merge conflicts are hard to fix,
conflict resolution doesn’t provide enough context, and
need a config flag to avoid having to repeat the same conflict resolution a billion
times.
If merge requests are not handled fast enough,
invariably you have to rebase over and over, even for trivial changes.
You &lt;em&gt;always&lt;&#x2F;em&gt; get merge conflicts if you touch the imports of your file.
I swear, I feel sometimes git invents new commits just out of spite
and forces you to solve conflicts.&lt;&#x2F;p&gt;
&lt;p&gt;Why all of this?&lt;&#x2F;p&gt;
&lt;p&gt;You develop on a dev machine, usually running the same OS as the CI machine.
You don’t delete your whole OS and reinstall everything from scratch
every time you compile your code.
You take advantage of your language’s compiler ability to cache intermediate
results and reuse them.
Why is it that we remake everything from scratch on our CI machines?&lt;&#x2F;p&gt;
&lt;p&gt;The artifacts locally generated by your compiler are no different
from the ones your CI machine generates.
So why not re-use them?&lt;&#x2F;p&gt;
&lt;p&gt;You ran the tests locally, why is it that the CI machine must re-check them?&lt;&#x2F;p&gt;
&lt;p&gt;Why is it that git can’t take into consideration your language’s syntax
when generating diffs?
Even Vim automatically detects your file’s language and understands
enough of it to color it accordingly.&lt;&#x2F;p&gt;
&lt;p&gt;Can’t we do better? It seems we got stuck at one point on Jenkins + git,
and froze in time before we got actually good development tools.&lt;&#x2F;p&gt;
&lt;p&gt;Can’t we get better review tools?
Github, Bitbucket and Gitlab are worse than bad.
Insanely slow, barely any context in the review comments,
with little traceability.&lt;&#x2F;p&gt;
&lt;p&gt;It seems those issues that affect all developers all the time are left
completely unattended.&lt;&#x2F;p&gt;
&lt;p&gt;Why is that?&lt;&#x2F;p&gt;
&lt;p&gt;Are we so bereft of creativity we can’t imagine a better world for ourselves?&lt;&#x2F;p&gt;
&lt;p&gt;I see &lt;em&gt;some&lt;&#x2F;em&gt; interest, but so so little of it. In no particular order:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There is &lt;a href=&quot;https:&#x2F;&#x2F;darklang.com&#x2F;&quot;&gt;dark&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;There is &lt;a href=&quot;https:&#x2F;&#x2F;www.unison-lang.org&#x2F;blog&#x2F;&quot;&gt;unison&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;There is &lt;a href=&quot;https:&#x2F;&#x2F;pijul.org&#x2F;&quot;&gt;pijul&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Both pijul and unison do not directly solve any of my questions,
they only explore related problems.&lt;&#x2F;p&gt;
&lt;p&gt;Anything else? Anything more? How have we not yet solved
(or even slightly improved) those issues?
Yet, those must be the largest source of expense in the modern development workflow.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Helix magic</title>
        <published>2022-07-18T00:00:00+00:00</published>
        <updated>2022-07-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/helix-html/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/helix-html/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/helix-html/">&lt;p&gt;I’ve been using as daily driver the &lt;a href=&quot;https:&#x2F;&#x2F;helix-editor.com&#x2F;&quot;&gt;Helix&lt;&#x2F;a&gt; text editor for 3 months now.
Coming from 5 consistent years of Neovim usage, I switched fairly quickly.
The kakoune-based modal editing intrigued me, and I wanted to give it a try.
But what swayed me is the great out-of-the-box user experience.
Going from 200 lines of fennel config and 20 dependencies to 0 config and 0
dependency is a big plus.&lt;&#x2F;p&gt;
&lt;p&gt;I’m still more comfortable with neovim than helix, but Helix has capabilities
that I’ve yet to take advantage of.&lt;&#x2F;p&gt;
&lt;p&gt;Here is an example of what I mean.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;&#x2F;h2&gt;
&lt;p&gt;I was asked to create a &lt;a href=&quot;https:&#x2F;&#x2F;bheisler.github.io&#x2F;criterion.rs&#x2F;book&#x2F;criterion_rs.html&quot;&gt;criterion&lt;&#x2F;a&gt; report for changes I made to the bevy
implementation of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;5214&quot;&gt;query iterator size hints&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;After familiarizing myself with criterion and running the benchmarks,
criterion generated a report in the form of a HTML file tree.
Each benchmark has its own html file with a variety of plots,
the reports also contain a bunch of json and csv files I’ve no idea how to use.&lt;&#x2F;p&gt;
&lt;p&gt;Criterion also generates automatically difference plots if you run it twice in
a row. But again, does nothing else but embed them in the benchmark-specific
html page.&lt;&#x2F;p&gt;
&lt;p&gt;However, what I needed was a &lt;em&gt;summary&lt;&#x2F;em&gt; of all the changes. It was impossible to
tell what the changes I made entailed at a glance, since I would need to open
each html benchmark report individually and look at the “Changes” section at
the very end of the file.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-did-helix-help-me-solve-it&quot;&gt;How did Helix help me solve it&lt;&#x2F;h2&gt;
&lt;p&gt;What I wanted was a unique page that displays a single plot per benchmark and a
summary of the changes for it.&lt;&#x2F;p&gt;
&lt;p&gt;Looking at the file tree generated by criterion, I found that each report had a
subdirectory called &lt;code&gt;both&lt;&#x2F;code&gt; with a few plots in them. The one I chose was
&lt;code&gt;pdf.svg&lt;&#x2F;code&gt; (the probability density function), because it does both a good job
of expressing the accuracy of the benchmark and the effects of the change.&lt;&#x2F;p&gt;
&lt;p&gt;I also needed the table of comparison from each html report files (as follow):&lt;&#x2F;p&gt;
&lt;table style=&quot;background-color:white&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;&lt;&#x2F;th&gt;
      &lt;th title=&quot;0.95 confidence level&quot; class=&quot;ci-bound&quot;&gt;Lower bound&lt;&#x2F;th&gt;
      &lt;th&gt;Estimate&lt;&#x2F;th&gt;
      &lt;th title=&quot;0.95 confidence level&quot; class=&quot;ci-bound&quot;&gt;Upper bound&lt;&#x2F;th&gt;
      &lt;th&gt;&lt;&#x2F;th&gt;
    &lt;&#x2F;tr&gt;
  &lt;&#x2F;thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Change in time&lt;&#x2F;td&gt;
      &lt;td class=&quot;ci-bound&quot;&gt;-0.0149%&lt;&#x2F;td&gt;
      &lt;td&gt;+0.0193%&lt;&#x2F;td&gt;
      &lt;td class=&quot;ci-bound&quot;&gt;+0.0543%&lt;&#x2F;td&gt;
      &lt;td&gt;(p = 0.33 &amp;gt;
      0.05)&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
  &lt;&#x2F;tbody&gt;
&lt;&#x2F;table&gt;
&lt;p&gt;Ideally, I’d also make it clear which benchmark was an improvement and which
one was a regression by having a different color for each comparison result.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-i-did-it&quot;&gt;How I did it&lt;&#x2F;h3&gt;
&lt;p&gt;I first used the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sharkdp&#x2F;fd&quot;&gt;&lt;code&gt;fd&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; tool to list all &lt;code&gt;pdf.svg&lt;&#x2F;code&gt; files within a &lt;code&gt;both&lt;&#x2F;code&gt;
directory.
I then put the result in a file.&lt;&#x2F;p&gt;
&lt;p&gt;(btw I strongly recommend you use &lt;code&gt;fd&lt;&#x2F;code&gt;, it’s a better version of &lt;code&gt;find&lt;&#x2F;code&gt;, which
paleolithic UI I absolutely never once remembered how to use, even at five
minutes interval)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;fd --full-path&lt;&#x2F;span&gt;&lt;span&gt; both&#x2F;pdf.svg target&#x2F;criterion &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; all_changes.html
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I then opened &lt;code&gt;all_changes.html&lt;&#x2F;code&gt; with helix.
The content of the &lt;code&gt;all_changes.html&lt;&#x2F;code&gt; file was as follow:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#fafafa;color:#383a42;&quot;&gt;&lt;code&gt;&lt;span&gt;target&#x2F;criterion&#x2F;for_each_iter&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;target&#x2F;criterion&#x2F;for_each_par_iter&#x2F;threads&#x2F;1&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;target&#x2F;criterion&#x2F;for_each_par_iter&#x2F;threads&#x2F;16&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;target&#x2F;criterion&#x2F;for_each_par_iter&#x2F;threads&#x2F;2&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;target&#x2F;criterion&#x2F;for_each_par_iter&#x2F;threads&#x2F;32&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;target&#x2F;criterion&#x2F;for_each_par_iter&#x2F;threads&#x2F;4&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that &lt;code&gt;&amp;lt;ESC&amp;gt;&lt;&#x2F;code&gt; means that I press the escape key.&lt;&#x2F;p&gt;
&lt;p&gt;I created a &lt;code&gt;h2&lt;&#x2F;code&gt; html element by copying the head of the file name and copying
it into a &lt;code&gt;h2&lt;&#x2F;code&gt; tag. The command sequence would be:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;111C&lt;&#x2F;code&gt; (create a cursor per line in the file)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gs2f&#x2F;d&lt;&#x2F;code&gt; (go to start of line, select all characters between it and the 2nd
next slash and delete them)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gl&lt;&#x2F;code&gt; (go to line ending)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;3F&#x2F;h&lt;&#x2F;code&gt; (go back 3 slashes in the line + one more character back)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;v&lt;&#x2F;code&gt; (enter selection extension mode)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;gs&lt;&#x2F;code&gt; (go to start of the line)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;iy&lt;&#x2F;code&gt; (yank selection into register &lt;code&gt;i&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;O&amp;lt;ESC&amp;gt;&lt;&#x2F;code&gt; (create a new line before this one, exit edit mode)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;_iP&lt;&#x2F;code&gt; (insert in before the cursor the content of register &lt;code&gt;i&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;I&amp;lt;h2&amp;gt;&amp;lt;ESC&amp;gt;&lt;&#x2F;code&gt; (insert the string “&amp;lt;h2&amp;gt;” at the beginning of the line)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;A&amp;lt;&#x2F;h2&amp;gt;&lt;&#x2F;code&gt; (finally, insert “&amp;lt;&#x2F;h2&amp;gt;” at the end of the line)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;center&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-center &quot;&gt;&lt;code class=&quot;language-center&quot; data-lang=&quot;center&quot;&gt;&lt;span&gt;&amp;lt;h2&amp;gt;for_each_iter&amp;lt;&#x2F;h2&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;for_each_iter&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;h2&amp;gt;for_each_par_iter&#x2F;threads&#x2F;1&amp;lt;&#x2F;h2&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;for_each_par_iter&#x2F;threads&#x2F;1&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;h2&amp;gt;for_each_par_iter&#x2F;threads&#x2F;16&amp;lt;&#x2F;h2&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;for_each_par_iter&#x2F;threads&#x2F;16&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I then embedded the image in the file by translating each line into a &lt;code&gt;img&lt;&#x2F;code&gt;
element.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;o&amp;lt;img src=&amp;quot;&amp;lt;ESC&amp;gt;&lt;&#x2F;code&gt; (start new line with img tag beginning)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;_iP&lt;&#x2F;code&gt; (past content of register &lt;code&gt;i&lt;&#x2F;code&gt; before the cursor)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;i&#x2F;report&#x2F;both&#x2F;pdf.svg&amp;quot;&amp;gt;&amp;lt;ESC&amp;gt;&lt;&#x2F;code&gt; (insert the end of the img tag)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;center&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-center &quot;&gt;&lt;code class=&quot;language-center&quot; data-lang=&quot;center&quot;&gt;&lt;span&gt;&amp;lt;h2&amp;gt;for_each_iter&amp;lt;&#x2F;h2&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;img src=&amp;quot;for_each_iter&#x2F;report&#x2F;both&#x2F;pdf.svg&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;for_each_iter&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;h2&amp;gt;for_each_par_iter&#x2F;threads&#x2F;1&amp;lt;&#x2F;h2&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;img src=&amp;quot;for_each_par_iter&#x2F;threads&#x2F;1&#x2F;report&#x2F;both&#x2F;pdf.svg&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;for_each_par_iter&#x2F;threads&#x2F;1&#x2F;report&#x2F;both&#x2F;pdf.svg
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now the difficult thing was embedding the html change report table  from the
benchmark page.
For this, I used &lt;a href=&quot;http:&#x2F;&#x2F;videlibri.sourceforge.net&#x2F;xidel.html&quot;&gt;xidel&lt;&#x2F;a&gt;, a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;XPath&quot;&gt;xpath&lt;&#x2F;a&gt; tool to read xml and html.
It’s very similar to &lt;code&gt;jq&lt;&#x2F;code&gt;, but for &lt;code&gt;xml&lt;&#x2F;code&gt; rather than &lt;code&gt;json&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;FYI &lt;code&gt;xidel&lt;&#x2F;code&gt; is a single pascal file of 2000 lines.&lt;&#x2F;p&gt;
&lt;p&gt;I first tested in my shell how I would do it in pure bash. I came up with the
following function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;function &lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;get-report-table &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;file&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;%%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;both&#x2F;pdf.svg}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;xidel&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;target&#x2F;criterion&#x2F;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;file&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;index.html \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;        --xpath3 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;#39;&#x2F;&#x2F;*[@class=&amp;quot;additional_stats&amp;quot;]&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;        --printed-node-format&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;html
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This returned (almost) the HTML I wanted in my final file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-html &quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;div &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;additional_stats&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&amp;lt;!-- The report data for the last benchmark, which
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;       we don&amp;#39;t care about for the summary --&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&amp;lt;!-- What we want: the comparison table between the last benchmark and
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;     the current one (with a diagnostic such as &amp;quot;Performance has improved.&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;     --&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;div &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;additional_stats&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;h4&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Additional Statistics:&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;h4&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;table&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;thead&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tr&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;0.95 confidence level&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;ci-bound&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Lower bound&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Estimate&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;0.95 confidence level&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;ci-bound&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Upper bound&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tr&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;thead&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tbody&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tr&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Change in time&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;ci-bound&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;-17.097%&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;-14.185%&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;ci-bound&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;-11.391%&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(p = 0.00 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;&amp;amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; 0.05)&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;td&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tr&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;tbody&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;table&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  Performance has improved.
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Helix has the “&lt;code&gt;|&lt;&#x2F;code&gt;” command to pass the currently selected lines to a shell
command and replace them in place with the output of the command.&lt;&#x2F;p&gt;
&lt;p&gt;I had difficulties with this one, because &lt;code&gt;xidel&lt;&#x2F;code&gt; only accepts files as
argument, also &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;bash&#x2F;manual&#x2F;bash.html#Shell-Parameter-Expansion&quot;&gt;parameter expansion&lt;&#x2F;a&gt; (such as &lt;code&gt;${1%%both&#x2F;pdf.svg}&lt;&#x2F;code&gt; used to
remove the trailing &lt;code&gt;both&#x2F;pdf.svg&lt;&#x2F;code&gt; from the input) does only work with
variables, not standard input.&lt;&#x2F;p&gt;
&lt;p&gt;The trick was to:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Replace the &lt;code&gt;$file&lt;&#x2F;code&gt; in the command by &lt;code&gt;$(cat &#x2F;dev&#x2F;stdin)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Remove in helix the trailing &lt;code&gt;both&#x2F;pdf.svg&lt;&#x2F;code&gt; (&lt;code&gt;gl2F&#x2F;d&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Now I can just press &lt;code&gt;|&lt;&#x2F;code&gt; and copy the command.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;And BANG! I had now the table in my html file for each benchmark.&lt;&#x2F;p&gt;
&lt;p&gt;I then selected the extraneous report div by using helix’s awesome
tree-sitter based motions (I bound them to &lt;code&gt;(&lt;&#x2F;code&gt; and &lt;code&gt;)&lt;&#x2F;code&gt; on my keyboard), and
pressed &lt;code&gt;d&lt;&#x2F;code&gt; to remove it.&lt;&#x2F;p&gt;
&lt;p&gt;Now for clarity, I just needed to wrap the “Performance has improved” bit into
a &lt;code&gt;&amp;lt;a style=&amp;quot;color:red&#x2F;green&amp;quot;&amp;gt;&lt;&#x2F;code&gt; based on the message.&lt;&#x2F;p&gt;
&lt;p&gt;This is a classic usage of the helix editor.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Select the whole document with &lt;code&gt;%&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;with &lt;code&gt;s&lt;&#x2F;code&gt; enter “select mode”&lt;&#x2F;li&gt;
&lt;li&gt;type &lt;code&gt;improved&lt;&#x2F;code&gt;, then enter. You now have all the occurrences of &lt;code&gt;improved&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;expand selection to parent syntax node (I set this to &lt;code&gt;]&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Add in front the anchor node opening with &lt;code&gt;i&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Add at the back the node closing delimiter with &lt;code&gt;a&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repeat with &lt;code&gt;regressed&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Done.&lt;&#x2F;p&gt;
&lt;p&gt;I now had the full report, I &lt;a href=&quot;https:&#x2F;&#x2F;nicopap.ch&#x2F;p&#x2F;bevy_exact_size_iter_criterion_results&#x2F;all_changes.html&quot;&gt;uploaded it on my site&lt;&#x2F;a&gt; and linked it in
the PR.&lt;&#x2F;p&gt;
&lt;p&gt;EZ&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The mut keyword in Rust</title>
        <published>2022-07-18T00:00:00+00:00</published>
        <updated>2022-07-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/rust-mut/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/rust-mut/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/rust-mut/">&lt;p&gt;Rust implements explicit mutability declaration. However, rust has a very
unique and precise definition of what “mutating” a variable means, and this
might trip up new users.&lt;&#x2F;p&gt;
&lt;p&gt;Also, rust’s borrow rules makes declaring variables as “constant” or
“mutable” much more meaningful than in other programming languages.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll explain here what &lt;code&gt;mut&lt;&#x2F;code&gt; &lt;em&gt;really&lt;&#x2F;em&gt; means in rust.&lt;&#x2F;p&gt;
&lt;p&gt;The tl;dr is: declaring a variable as &lt;code&gt;mut&lt;&#x2F;code&gt; just allows you to create a mutable
reference to it, and assign new values to it nothing more, nothing less.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s start with some code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::collections::HashMap;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_map: HashMap&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, String&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;HashMap::new();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, we create a new hash map, call it &lt;code&gt;my_map&lt;&#x2F;code&gt;.
We &lt;em&gt;own&lt;&#x2F;em&gt; &lt;code&gt;my_map&lt;&#x2F;code&gt;, because what &lt;code&gt;my_map&lt;&#x2F;code&gt; is,
is not a reference (&lt;code&gt;&amp;amp;Foo&lt;&#x2F;code&gt;) or mutable reference (&lt;code&gt;&amp;amp;mut Foo&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;But, when you do:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; item &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; my_map.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;103434&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You are creating a reference to &lt;code&gt;my_map&lt;&#x2F;code&gt;.
The &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;collections&#x2F;struct.HashMap.html#method.get&quot;&gt;&lt;code&gt;get&lt;&#x2F;code&gt; method&lt;&#x2F;a&gt; on &lt;code&gt;HashMap&lt;&#x2F;code&gt; accepts a &lt;code&gt;&amp;amp;self&lt;&#x2F;code&gt;, a reference.
But &lt;code&gt;my_map&lt;&#x2F;code&gt; is not a reference, this should be a compilation error!
Mismatching types.
What is actually happening is that the compiler inserts a reference here.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; item &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;my_map).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;103434&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The same is true for the &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;collections&#x2F;struct.HashMap.html#method.insert&quot;&gt;&lt;code&gt;insert&lt;&#x2F;code&gt; method&lt;&#x2F;a&gt;.
&lt;code&gt;insert&lt;&#x2F;code&gt; accepts a &lt;code&gt;&amp;amp;mut self&lt;&#x2F;code&gt;, a mutable reference.
So, behind the scenes, rust creates a mutable reference to &lt;code&gt;my_map&lt;&#x2F;code&gt; when you
do:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_map: HashMap&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, String&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;HashMap::new();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; !!!!! ERROR, does not compile !!!!
&lt;&#x2F;span&gt;&lt;span&gt;my_map.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;insert&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;340101&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;My String&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;to_owned&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; (&amp;amp;mut my_map).insert(...)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In fact, the above snippet of code doesn’t compile.
This is because rust requires all variables for which you create mutable
references to be declared with the &lt;code&gt;mut&lt;&#x2F;code&gt; keyword.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; my_map: HashMap&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, String&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;HashMap::new();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F;  ^^^
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; 👌 💯
&lt;&#x2F;span&gt;&lt;span&gt;my_map.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;insert&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;340101&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;My String&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;to_owned&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In rust, function parameters act like variable declarations,
so they follow the same rule.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-can-i-mutate-a-mutable-reference-without-mut&quot;&gt;Why can I mutate a mutable reference without &lt;code&gt;mut&lt;&#x2F;code&gt;?&lt;&#x2F;h2&gt;
&lt;p&gt;Ok, but why can I do this?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; my_map: HashMap&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, String&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;HashMap::new();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_other_map &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; my_map;
&lt;&#x2F;span&gt;&lt;span&gt;my_other_map.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;insert&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;340101&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50a14f;&quot;&gt;&amp;quot;My String&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;to_owned&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;See? No &lt;code&gt;mut my_other_map&lt;&#x2F;code&gt;, only &lt;code&gt;let&lt;&#x2F;code&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;Indeed, the only things you need to declare with &lt;code&gt;mut&lt;&#x2F;code&gt; are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Things you &lt;em&gt;create a mutable reference of&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Things you assign to, as in &lt;code&gt;foo = new_foo;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;code&gt;my_other_map&lt;&#x2F;code&gt; is already a mutable reference, and you are not assigning to it.
So it doesn’t need to be declared &lt;code&gt;mut&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Besides, the &lt;code&gt;&amp;amp;mut&lt;&#x2F;code&gt; here in the declaration is a dead giveaway that you are
going to mutate &lt;code&gt;my_other_map&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;By all means, you still can create a mutable reference to your mutable
reference if you really want to.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; my_map: HashMap&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, String&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;HashMap::new();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_other_map &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; my_map;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; !!!!! ERROR, does not compile !!!!!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; need to declare mut my_other_map
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_sneaky_map: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;&amp;amp;mut &amp;amp;mut &lt;&#x2F;span&gt;&lt;span&gt;HashMap&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; my_other_map;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;in-comparison-to-other-languages&quot;&gt;In comparison to other languages&lt;&#x2F;h2&gt;
&lt;p&gt;Rust follows a recent trend in languages design, which is to make the
declaration of mutable variable distinct from immutable variables.&lt;&#x2F;p&gt;
&lt;p&gt;However, in other programming languages, &lt;em&gt;everything has interior mutability&lt;&#x2F;em&gt;.
Interior mutability is when you modify the &lt;em&gt;inside&lt;&#x2F;em&gt; of a class without
modifying the outside.
In any project of meaningful size, you more often change the inside of classes
than their complete value
(in fact, it’s very rare to change the value of something without going through
a method).
All implementations of explicit mutability declaration I have seen, do not, in
any way, prevent interior mutability. &lt;strong&gt;Even rust&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As a result, the only way to ensure immutability in those languages, is by only
exposing non-mutating methods to your class and marking all fields private.&lt;&#x2F;p&gt;
&lt;p&gt;In scala, you &lt;em&gt;can&lt;&#x2F;em&gt; use &lt;code&gt;val&lt;&#x2F;code&gt; and &lt;code&gt;var&lt;&#x2F;code&gt; to declare a variable as “immutable” vs
“mutable”, but this is definitively misleading. You can very much declare a
&lt;strong&gt;java&lt;&#x2F;strong&gt; hash map as &lt;code&gt;val&lt;&#x2F;code&gt; and then insert new items in it.
However, since the scala standard library is immutable, there is no point in
worrying about mutability or interior mutability.
(unless of course, you are using java classes or your scala classes themselves
contain java classes)
The compiler doesn’t in anyway guarantee that your &lt;code&gt;val&lt;&#x2F;code&gt; won’t be mutated or
won’t have a mutable method.
So what is &lt;code&gt;var&lt;&#x2F;code&gt; for?
It’s a sort of inline documentation (with all the pitfalls that this entails).
And honestly, I’m not too hot on it.&lt;&#x2F;p&gt;
&lt;p&gt;This is also true of javascript’s &lt;code&gt;var&lt;&#x2F;code&gt; vs &lt;code&gt;const&lt;&#x2F;code&gt;, and C’s &lt;code&gt;const&lt;&#x2F;code&gt; (beyond the
complete nonsense related to declaration priority and what &lt;code&gt;const&lt;&#x2F;code&gt; is
actually &lt;code&gt;const&lt;&#x2F;code&gt;-ing between the type, the reference or god knows what)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;we_have_consts &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{ a: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;10 &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; Wait, this doesn&amp;#39;t even cause a runtime error???
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;we_have_consts&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a626a4;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;34
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c18401;&quot;&gt;console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#0184bc;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;we_have_consts&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e45649;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0a1a7;&quot;&gt;&#x2F;&#x2F; 34
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rust also has interior mutability, and indeed, it can trip up users to see a
method taking a &lt;code&gt;&amp;amp;self&lt;&#x2F;code&gt; and modifying the value of &lt;code&gt;self&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;However, this is far from usual, and it’s mostly constrained to specialized
concurrent libraries such as &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;dashmap&#x2F;latest&#x2F;dashmap&#x2F;struct.DashMap.html#method.insert&quot;&gt;dashmap&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;(also, &lt;code&gt;&amp;amp;mut T&lt;&#x2F;code&gt; itself has interior mutability, by definition, you are mutating
something “pointed to” by the reference, aka “inside” of it)&lt;&#x2F;p&gt;
&lt;p&gt;In general, the borrowing rules prevent all spooky action at a distance,
at least, as long as the &lt;code&gt;unsafe&lt;&#x2F;code&gt; code you are using is sound.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The little coordinate system reference</title>
        <published>2022-07-16T00:00:00+00:00</published>
        <updated>2022-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nicopap.ch/blogs/snaps-of-bafflement/coordinate-systems/"/>
        <id>https://nicopap.ch/blogs/snaps-of-bafflement/coordinate-systems/</id>
        
        <content type="html" xml:base="https://nicopap.ch/blogs/snaps-of-bafflement/coordinate-systems/">&lt;p&gt;I’ve been implementing an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;HeavyRain266&#x2F;bevy_fbx&quot;&gt;FBX&lt;&#x2F;a&gt; 3d file format loader for &lt;a href=&quot;https:&#x2F;&#x2F;bevyengine.org&#x2F;&quot;&gt;bevy&lt;&#x2F;a&gt;, and currently the
most challenging part of it has been figuring out coordinate system
transitions.&lt;&#x2F;p&gt;
&lt;p&gt;I’m having a lot of trouble using search engines to find references online, so
I’m creating my own. Here it is: the most exhaustive reference (with pictures!)
on how to convert between coordinate systems.&lt;&#x2F;p&gt;
&lt;p&gt;If you finish reading this without an answer to those 3 questions, I’m a twat.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;What’s “left-handed” vs “right-handed” coordinate systems?&lt;&#x2F;li&gt;
&lt;li&gt;What is forward?&lt;&#x2F;li&gt;
&lt;li&gt;How to convert between coordinate systems?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-s-a-coordinate-system&quot;&gt;What’s a coordinate system?&lt;&#x2F;h2&gt;
&lt;p&gt;A game engine, a modelling software, or any 3D game work in 3D space.
To locate something in 3D space, you need some sort of information or data.
The position data is called a “coordinate”, and in 3 dimension,
it is divided in 3 different scalar&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; values, also called components.
Software most often use the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Standard_basis&quot;&gt;standard basis&lt;&#x2F;a&gt; as coordinates.
Each component answer the question:
“how many step in this basis direction do you have to make
to reach the coordinate position?”
The basis of 3D space are X, Y and Z. We all agree on that.
However, it turns out, beyond that, no one agrees on anything.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-are-the-differences-between-coordinate-systems-in-different-software&quot;&gt;What are the differences between coordinate systems in different software?&lt;&#x2F;h2&gt;
&lt;p&gt;You might be interested in &lt;a href=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;KDahir247&#x2F;Fabled-Engine&#x2F;main&#x2F;references&#x2F;Coord_Reference.jpg&quot;&gt;this link&lt;&#x2F;a&gt; as a reference of which
software uses which coordinate system.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond X Y and Z, you need to find what they represent.
On a whiteboard, you generally draw the X axis from left to right and the Y
axis bottom up.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img style=&quot;width:100%&quot; src=&quot;&#x2F;blog-assets&#x2F;coordinate-systems&#x2F;whiteboard-axis.jpg&quot;
  alt=&quot;A 2d axis drawn on a whiteboard&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;While, when drawing on a piece of paper on your desk, the X axis goes to the
right and the &lt;strong&gt;Y axis forward&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Each software is free to chose what axis is up.
Usually, Y is up, like on the whiteboard. But after choosing what “up” is,
there is the question of choosing what is “forward” (goes out of the whiteboard
perpendicularly) and what goes in the other direction of the whiteboard.
(on the whiteboard, it was X)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-left-right-handed-coordinate-system&quot;&gt;The left&#x2F;right-handed coordinate system&lt;&#x2F;h2&gt;
&lt;p&gt;(If you are reading this in a public place, you may look silly while reading
this section.)&lt;&#x2F;p&gt;
&lt;p&gt;To answer this question, some people use the “left&#x2F;right-handed” description.
Take your hands, and point your thumb, your index and middle fingers outward.
In the left&#x2F;right-handed system, the thumb is X, the index is Y and middle
finger Z.
You’ll notice that regardless of how you spin your hands,
the outward fingers of both hands won’t ever go in the same direction.
They may at one point end up on the same axises, but they won’t point in the
same direction.&lt;&#x2F;p&gt;
&lt;p&gt;I embedded an interactive demo, which source code is
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;gizmo-manip&quot;&gt;available here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The left gizmo is left-handed, while the right gizmo is right-handed.
The red ball is &lt;strong&gt;+X&lt;&#x2F;strong&gt;, the green ball is &lt;strong&gt;+Y&lt;&#x2F;strong&gt; and the blue ball &lt;strong&gt;+Z&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;(may be slightly broken on mobile)&lt;&#x2F;p&gt;
&lt;script&gt;
  function create_iframe(target) {
    var iframe = document.createElement(&#x27;iframe&#x27;);
    iframe.src = &quot;&#x2F;blog-assets&#x2F;coordinate-systems&#x2F;index.html&quot;;
    iframe.style=&quot;border:0&quot;
    iframe.height=&quot;270&quot;
    iframe.width=&quot;480&quot;
    iframe.scrolling=&quot;no&quot;
    target.replaceWith(iframe);   
  }
&lt;&#x2F;script&gt;
&lt;p&gt;&lt;button onclick=&quot;create_iframe(this)&quot;&gt;Press here to start demo&lt;&#x2F;button&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And here is a table showing all 6 possible coordinate systems:&lt;&#x2F;p&gt;
&lt;div class=&quot;spill&quot; style=&quot;display:flex;flex-wrap:wrap;justify-content:center&quot;&gt;
  &lt;img width=&quot;330&quot; src=&quot;&#x2F;blog-assets&#x2F;coordinate-systems&#x2F;table.svg&quot;&gt;
  &lt;img width=&quot;330&quot; src=&quot;&#x2F;blog-assets&#x2F;coordinate-systems&#x2F;both-identical.svg&quot;&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;how-to-convert-between-coordinate-systems&quot;&gt;How to convert between coordinate systems?&lt;&#x2F;h2&gt;
&lt;p&gt;Now, if you ever imported or exported a 3D model from one program to another,
you probably got the opportunity to see first-hand that indeed not all software
use the same coordinate system.&lt;&#x2F;p&gt;
&lt;p&gt;If you don’t want to manually rotate all the models you are importing, you
gotta use some math.&lt;&#x2F;p&gt;
&lt;p&gt;It’s actually quite simple. Find in the previous table the cell with the
&lt;strong&gt;expected&lt;&#x2F;strong&gt; coordinate, and the cell with the &lt;strong&gt;actual&lt;&#x2F;strong&gt; coordinates.
Then write down the “up”, “forward” and “right” axis of the &lt;strong&gt;actual&lt;&#x2F;strong&gt;
coordinates in a column on paper.
Then write down the &lt;strong&gt;expected&lt;&#x2F;strong&gt; coordinates in a column to the right.
If you expected left-handed Y up, and got right-handed Z up,
it should look like this now:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;center&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-center &quot;&gt;&lt;code class=&quot;language-center&quot; data-lang=&quot;center&quot;&gt;&lt;span&gt;  top     Z  →  Y
&lt;&#x2F;span&gt;&lt;span&gt;  forward Y  →  Z
&lt;&#x2F;span&gt;&lt;span&gt;  right   X  →  X
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This means you need to go from (x,y,z) to (x,z,y),
which means that your need to swap your Z and Y axis.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;with-matrices&quot;&gt;With matrices&lt;&#x2F;h3&gt;
&lt;p&gt;You can do it with vector swizzles, but you may also want a transform.
I’m not going to give rotation keys here, because I’m as clueless as you. 
But your software’s API let you probably create a transform based on a matrix.&lt;&#x2F;p&gt;
&lt;p&gt;A matrix is an operation on vectors, to go from one 3D vector to another 3D
vector, you need a 3x3 matrix.&lt;&#x2F;p&gt;
&lt;p&gt;The kind of matrix we need is a &lt;em&gt;rotation&lt;&#x2F;em&gt; matrix, that rotates at exactly 90
degree angles.&lt;&#x2F;p&gt;
&lt;p&gt;You can think of a matrix as a table,
where the columns are the “from position” and the rows the “to position”.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;center&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-center &quot;&gt;&lt;code class=&quot;language-center&quot; data-lang=&quot;center&quot;&gt;&lt;span&gt;   fx fy fz
&lt;&#x2F;span&gt;&lt;span&gt;tx  1, 0, 0
&lt;&#x2F;span&gt;&lt;span&gt;ty  0, 1, 0
&lt;&#x2F;span&gt;&lt;span&gt;tz  0, 0, 1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So for our right-handed Z up to left-handed Y up, conversion from earlier, we
would need the following matrix:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;center&quot; style=&quot;background-color:#fafafa;color:#383a42;&quot; class=&quot;language-center &quot;&gt;&lt;code class=&quot;language-center&quot; data-lang=&quot;center&quot;&gt;&lt;span&gt;    1  0  0
&lt;&#x2F;span&gt;&lt;span&gt;    0  0  1
&lt;&#x2F;span&gt;&lt;span&gt;    0  1  0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; scalar just means “a single number”, here we often use rational numbers, &lt;br &#x2F;&gt;
or “float” in computer jargon.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; A 3x3 matrix has 9 components, 3 columns and 3 rows.&lt;&#x2F;p&gt;
&lt;p&gt;Whiteboard image courtesy of geralt on &lt;a href=&quot;https:&#x2F;&#x2F;pixabay.com&#x2F;&quot;&gt;pixabay&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
