<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Alex DeLorenzo</title>
    <description>Articles, blog and software by Alex DeLorenzo. Check out Alex&apos;s software, articles and open source contributions here. </description>
    <link>https://alexdelorenzo.dev/</link>
    <atom:link href="https://alexdelorenzo.dev/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 28 Mar 2026 20:57:41 +0000</pubDate>
    <lastBuildDate>Sat, 28 Mar 2026 20:57:41 +0000</lastBuildDate>
    <generator>Jekyll v4.3.2</generator>
    
    
      <item>
        <title>Encrypted Root with LUKS and Opal</title>
        <description>&lt;h2 id=&quot;using-cryptsetups-native-opal-support-to-decrypt-self-encrypting-drive-partitions-at-boot-with-luks-and-systemd&quot;&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt;’s native Opal support to decrypt self-encrypting drive partitions at boot with LUKS and systemd&lt;/h2&gt;

&lt;p&gt;Prior to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; 2.7.0, using &lt;a href=&quot;https://en.wikipedia.org/wiki/Hardware-based_full_disk_encryption#Hard_disk_drive_FDE&quot;&gt;self-encrypting drives (SEDs)&lt;/a&gt; on Linux required the use of tools like &lt;a href=&quot;https://github.com/Drive-Trust-Alliance/sedutil&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sedutil&lt;/code&gt;&lt;/a&gt; to boot in order to use hardware encryption, otherwise the drives were limited to using &lt;a href=&quot;https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup&quot;&gt;LUKS software encryption&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to encrypt your root or boot partitions via &lt;a href=&quot;https://en.wikipedia.org/wiki/Opal_Storage_Specification&quot;&gt;the Opal specification for hardware encryption&lt;/a&gt;, you either needed a motherboard with UEFI/BIOS that supports Opal, or you need to flash a &lt;a href=&quot;https://en.wikipedia.org/wiki/Pre-boot_authentication&quot;&gt;pre-boot authorization (PBA)&lt;/a&gt; image to your Opal drive and boot from that.&lt;/p&gt;

&lt;p&gt;On systems without Opal support, SEDs will trick firmware into booting an unencrypted PBA image that then handles the mounting and booting of the encrypted disk itself.&lt;/p&gt;

&lt;p&gt;With the new release of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt;, you can use self-encrypting drives’ hardware encryption directly with LUKS via Opal interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;#how-to-use-hardware-encryption-with-cryptsetup&quot;&gt;
    &lt;sparkly-text number-of-sparkles=&quot;2&quot; style=&quot;--sparkly-text-color: gold; --sparkly-text-size: 2em&quot;&gt;&lt;b class=&quot;shadow&quot;&gt;Click here&lt;/b&gt;&lt;/sparkly-text&gt; to skip directly to the tutorial
&lt;/a&gt; 👇&lt;/p&gt;

&lt;h2 id=&quot;hardware-encryption-versus-software-encryption&quot;&gt;Hardware encryption versus software encryption&lt;/h2&gt;

&lt;p&gt;This comes down to choice. Modern NVMe drives with self-encryption support automatically encrypt your data even if you don’t set up encryption yourself. The drives ship with a manufacturer-set key that encrypts your data, but with the password disabled. Even if you personally aren’t using a password to unlock your drive, your data is still being encrypted anyway.&lt;/p&gt;

&lt;p&gt;By shipping drives with encryption turned on without a password, it allows you to later set a password for your drive without having to erase all of your data just so that it can be encrypted using your password. Explicitly setting a password just encrypts the drive’s underlying encryption key, and requires that password to decrypt the drive.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;tl;dr&lt;/em&gt;: Your self-encrypting drives are already using encryption even if it is “off”. You’re already paying for the cost of hardware self-encryption whether you set a password or not.&lt;/p&gt;

&lt;p&gt;Software encryption, on the other hand, needs to be explicitly set up. Using software encryption has a cost: it takes time and energy to encrypt and decrypt data. All of your data must flow through your CPU in order to read or write anything to disk, which takes time and a considerable amount of power, even if your processors implement &lt;a href=&quot;https://en.wikipedia.org/wiki/AES_instruction_set&quot;&gt;AES-NI acceleration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re on a laptop, for example, software encryption can impact your battery life. It can also impact the speed at which you’re able to access data on your machine. Comparing the two, you don’t have to pay any additional cost in terms of speed or battery life if you choose to enable hardware encryption, since it’s always on anyway.&lt;/p&gt;

&lt;p&gt;That said, by using hardware encryption alone, you are placing full trust in your hardware manufacturer’s encryption implementation. &lt;a href=&quot;https://www.zdnet.com/article/flaws-in-self-encrypting-ssds-let-attackers-bypass-disk-encryption/&quot;&gt;That trust can be misplaced, as self-encrypted drives’ firmware implementations are frequently broken&lt;/a&gt;. Even if you’re using strong underlying encryption, if the surrounding implementation can be hacked, that encryption doesn’t mean much if an attacker can easily exfiltrate your keys or data.&lt;/p&gt;

&lt;p&gt;When it comes to encryption, mobile users are presented with the choice to use software encryption, and pay the price in terms of time and energy, or use hardware encryption, which can improve speed and battery life at the expense of potentially using poor encryption implementations.&lt;/p&gt;

&lt;p&gt;If your machine is stolen, hardware encryption might keep your data safe from unsophisticated criminals, but it might not keep you out of prison if you’re a whistleblower that a government wants to silence. For 99.999% of people, keeping data safe from petty criminals is sufficient enough. Just keep in mind that it’s not perfect and don’t hinge your life or freedom on some random drive’s encryption implementation.&lt;/p&gt;

&lt;h2 id=&quot;booting-self-encrypted-drives-on-machines-without-opal-support&quot;&gt;Booting self-encrypted drives on machines without Opal support&lt;/h2&gt;

&lt;p&gt;My hardware doesn’t support self-encrypting drives natively, so if I want to encrypt my root and/or boot partitions, I need to jump through some hoops. Those hoops include finding or building PBA images, enabling pre-boot authorization on my self-encrypting drives, ensuring my PBA is set up to boot correctly and configuring the system to use my authentication methods of choice.&lt;/p&gt;

&lt;p&gt;Luckily, it turns out that the &lt;a href=&quot;https://www.drivetrust.com/&quot;&gt;Drive Trust Alliance (DTA)&lt;/a&gt; published pre-compiled PBA images for use with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sedutil&lt;/code&gt;. That sounds convenient, until you learn that those images were compiled 4+ years ago using kernels that may or may not support your hardware. Similarly, if you want to unlock your Opal drives using multiple factors, like &lt;a href=&quot;https://en.wikipedia.org/wiki/FIDO_Alliance#Specifications&quot;&gt;FIDO authenticators&lt;/a&gt;, you need to modify your PBA image to do so. The PBA from the DTA doesn’t support hardware authenticators like Yubikeys natively.&lt;/p&gt;

&lt;p&gt;On normal drives that do not have encryption support, you can use software encryption via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup&quot;&gt;LUKS&lt;/a&gt; and systemd. It’s easy to set up and boot your encrypted drives, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; natively supports enrolling FIDO authenticators to unlock encrypted partitions. Set it up right, and you can easily use a Yubikey at boot to unlock your root partitions. It’s relatively uncomplicated.&lt;/p&gt;

&lt;p&gt;In contrast, using self-encrypting drives is much more cumbersome, and potentially involves rolling your own bootable PBA image just to unlock your drive.&lt;/p&gt;

&lt;p&gt;That was the state of things if you wanted to use Opal with motherboard firmware that doesn’t support self-encrypting drives.&lt;/p&gt;

&lt;h2 id=&quot;new-cryptsetup-has-native-opal-support&quot;&gt;New &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; has native Opal support&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://lore.kernel.org/all/cd409f6c-5d51-482c-8a26-340822754ff1@gmail.com/T/&quot;&gt;Now, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; 2.7.0, there is native support for hardware encryption for drives that support Opal encryption&lt;/a&gt;, even if your firmware doesn’t implement support for Opal drives.&lt;/p&gt;

&lt;p&gt;Set up correctly, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt;, LUKS and systemd with hardware encryption as easily as it is to use software encryption. There is no need to trick your BIOS into booting a PBA, and there is no need to build your own PBA image if you want to use a Yubikey. In fact, there is no need for a PBA at all.&lt;/p&gt;

&lt;h2 id=&quot;typical-encrypted-file-system-scheme-with-cryptsetup&quot;&gt;Typical encrypted file-system scheme with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;When using software encryption, it’s typical to turn on &lt;a href=&quot;https://en.wikipedia.org/wiki/UEFI#Secure_Boot&quot;&gt;Secure Boot&lt;/a&gt; and leave your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot&lt;/code&gt; unencrypted so you can bootstrap your kernel and initramfs to automatically unlock your encrypted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; for you. This can be automated so that all you need to do is supply your password, and/or Yubikey + PIN, at boot to unlock your root partition.&lt;/p&gt;

&lt;p&gt;Depending on how much of the Opal specification your self-encrypting drive accurately implements, Opal drives can use hardware encryption for specific regions of the drive while leaving others unencrypted.&lt;/p&gt;

&lt;p&gt;That means you can use a similar setup to your software encryption scheme where you turn on Secure Boot and leave your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot&lt;/code&gt; unencrypted so you can easily unlock your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;. All you have to do is create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot&lt;/code&gt; EFI partition and a separate partition for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;. You can then tell your Opal drive to encrypt your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; region.&lt;/p&gt;

&lt;p&gt;From that point on, you can use hardware encryption with the same exact tools you would software encryption, allowing you to easily boot, enter your credentials and unlock your drive without a hacky pre-boot authorization process complicating your boot process.&lt;/p&gt;

&lt;h2 id=&quot;how-to-use-hardware-encryption-with-cryptsetup&quot;&gt;How to use hardware encryption with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;This guide assumes you’re using &lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemd-boot.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd-boot&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://wiki.archlinux.org/title/Dm-crypt/System_configuration#Using_systemd-cryptsetup-generator&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd-cryptsetup-generator&lt;/code&gt;&lt;/a&gt; to unlock your LUKS partitions at boot. I add additional information and links for those who are not using this setup, but be aware that this guide has only been tested using systemd for boot and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; support.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; only works with self-encrypting drives over PCIe, not USB.&lt;/p&gt;

&lt;p&gt;Find your NVMe device in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev&lt;/code&gt;. Mine is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/nvme1n1&lt;/code&gt;. Yours might be different.&lt;/p&gt;

&lt;h3 id=&quot;detect-opal-support&quot;&gt;Detect Opal support&lt;/h3&gt;

&lt;p&gt;Not all drives support the Opal specification. You can see if your drive supports it by running the following:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sedutil-cli &lt;span class=&quot;nt&quot;&gt;--scan&lt;/span&gt;

Scanning &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;Opal compliant disks
/dev/nvme1  2  YOUR_DRIVE_MODEL		YOUR_DRIVE_ID
No more disks present ending scan
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you see a number in the second column, like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; above, your drive supports Opal.&lt;/p&gt;

&lt;p&gt;If you see the word &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;No&lt;/code&gt;, your drive does not support Opal:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sedutil-cli &lt;span class=&quot;nt&quot;&gt;--scan&lt;/span&gt;

Scanning &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;Opal compliant disks
/dev/nvme0 No  YOUR_DRIVE_MODEL		YOUR_DRIVE_ID
No more disks present ending scan
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;reset-your-opal-drive&quot;&gt;Reset your Opal drive&lt;/h3&gt;

&lt;p&gt;This will erase your drive and reset it.&lt;/p&gt;

&lt;p&gt;You will need to locate the &lt;a href=&quot;https://trustedcomputinggroup.org/resource/tcg-storage-opal-feature-set-psid/&quot;&gt;PSID of your drive&lt;/a&gt; to prove you have physical access to it. On my drives, it is printed in small text on a sticker attached to the drives themselves. If the PSID has dashes, ignore them. The PSID should be one long string of letters and numbers without any special symbols.&lt;/p&gt;

&lt;p&gt;When you find it, save it somewhere you won’t lose it and then use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sedutil-cli&lt;/code&gt; with your drive:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sedutil-cli &lt;span class=&quot;nt&quot;&gt;--PSIDrevert&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;YOUR_PSID_HERE&quot;&lt;/span&gt; /dev/nvme1n1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; instead:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cryptsetup luksErase &lt;span class=&quot;nt&quot;&gt;--hw-opal-factory-reset&lt;/span&gt; /dev/nvme1n1
Enter OPAL PSID: YOUR_PSID_HERE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YOUR_PSID_HERE&lt;/code&gt; with your drive’s PSID.&lt;/p&gt;

&lt;p&gt;Alternatively, if you’ve already set up encryption on your drive’s specific locking range, and know the passwords you set yourself, you can skip the stage above. Keep in mind that setting up LUKS on an Opal locking range will reset and erase that locking range, anyway.&lt;/p&gt;

&lt;h3 id=&quot;create-boot-and-root-partitions&quot;&gt;Create boot and root partitions&lt;/h3&gt;

&lt;p&gt;This will overwrite your partition table and you will lose the data on the drive.&lt;/p&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot&lt;/code&gt; EFI partition and a root partition using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parted&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;parted /dev/nvme1n1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parted&lt;/code&gt;, run:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create a GPT partition table&lt;/span&gt;
mklabel gpt

&lt;span class=&quot;c&quot;&gt;# Create an EFI partition&lt;/span&gt;
mkpart ESP fat32 1MiB 513MiB
&lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;1 boot on

&lt;span class=&quot;c&quot;&gt;# Create a root partition that we&apos;ll encrypt&lt;/span&gt;
mkpart primary btrfs 513MiB 100%

quit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Format your EFI partition:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mkfs.fat &lt;span class=&quot;nt&quot;&gt;-F32&lt;/span&gt; /dev/nvme1n1p1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;set-up-luks-with-opal-support&quot;&gt;Set up LUKS with Opal support&lt;/h3&gt;

&lt;p&gt;Running  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;luksFormat&lt;/code&gt; will erase and format your specified partition, you will lose the data on it. Encrypting data in-place is not supported.&lt;/p&gt;

&lt;p&gt;Ensure that you have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; 2.70 or newer. Older versions of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; will not work.&lt;/p&gt;

&lt;p&gt;Determine your root partition’s location in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev&lt;/code&gt;. My EFI partition is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/nvme1n1p1&lt;/code&gt; and my root partition to be encrypted is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/nvme1n1p2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then run the following to set up LUKS:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;cryptsetup luksFormat /dev/nvme1n1p2 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; luks2 &lt;span class=&quot;nt&quot;&gt;--hw-opal-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--hw-opal-only&lt;/code&gt; flag tells &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptsetup&lt;/code&gt; to use hardware encryption only. If you want to use software encryption on top of hardware encryption, pass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--hw-opal&lt;/code&gt; flag instead.&lt;/p&gt;

&lt;p&gt;You might be asked to set user and administrator password, do so and don’t forget them.&lt;/p&gt;

&lt;p&gt;Let’s open and decrypt the partition so we can format a file-system on it. You can replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DISK_NAME_GOES_HERE&lt;/code&gt; with any name, the value will determine what Device Mapper will call your unlocked drive under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/mapper&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;cryptsetup open /dev/nvme1n1p2 DISK_NAME_GOES_HERE
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mkfs.btrfs &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; EncryptedRoot /dev/mapper/DISK_NAME_GOES_HERE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’m using btrfs, but feel free to use EXT4, F2FS or whatever you want for your root partition. Note that the rest of this guide will assume you’re using btrfs, too.&lt;/p&gt;

&lt;h3 id=&quot;enroll-your-authentication-methods&quot;&gt;Enroll your authentication methods&lt;/h3&gt;

&lt;p&gt;LUKS partitions can be unlocked via a variety of methods, like passwords, key-files and hardware authenticators. Enroll the methods you’d like to use to decrypt your drive at boot.&lt;/p&gt;

&lt;p&gt;If you want to use a FIDO authentication device, you can use &lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemd-cryptenroll.html#&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd-cryptenroll&lt;/code&gt;&lt;/a&gt; to enroll one yourself:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;systemd-cryptenroll &lt;span class=&quot;nt&quot;&gt;--fido2-device&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;auto /dev/nvme1n1p2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For plaintext passwords, you can run:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;systemd-cryptenroll /dev/nvme1n1p2 &lt;span class=&quot;nt&quot;&gt;--password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html&quot;&gt;Here is a good resource for using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd-cryptenroll&lt;/code&gt; to enroll various authentication methods with LUKS.&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;confirm-configuration&quot;&gt;Confirm configuration&lt;/h3&gt;

&lt;p&gt;Before going any further, let’s ensure that the encrypted partition is set up properly.&lt;/p&gt;

&lt;p&gt;Close your open LUKS partition:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;cryptsetup close DISK_NAME_GOES_HERE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then try to open it again:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;cryptsetup open /dev/nvme1n1p2 DISK_NAME_GOES_HERE &lt;span class=&quot;nt&quot;&gt;--token-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Omit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--token-only&lt;/code&gt; flag if you aren’t unlocking your partition with something like a Yubikey.&lt;/p&gt;

&lt;p&gt;You should now see your device in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/mapper&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /dev/mapper
/dev/mapper/DISK_NAME_GOES_HERE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ensure your LUKS partition is set up to your expectations:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;cryptsetup luksDump /dev/nvme1n1p2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;set-your-machine-to-unlock-luks&quot;&gt;Set your machine to unlock LUKS&lt;/h2&gt;

&lt;p&gt;We’re going to need to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/crypttab&lt;/code&gt; file and edit the kernel command-line options to point the kernel to our encrypted root file-system.&lt;/p&gt;

&lt;h3 id=&quot;create-a-crypttab-file&quot;&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crypttab&lt;/code&gt; file&lt;/h3&gt;

&lt;p&gt;Determine your partition’s UUID by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blkid&lt;/code&gt; and noting its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PARTUUID&lt;/code&gt; label:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;blkid
/dev/nvme1n1p2: &lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;87425985-0ed3-486f-8d66-b07bbf27f8ea&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;crypto_LUKS&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PARTLABEL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;EncryptedRoot&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PARTUUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fec2fe57-8a1b-43af-96b4-05cf1b944e03&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With root permissions, create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/crypttab&lt;/code&gt; file like so, replacing the UUID value with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PARTUUID&lt;/code&gt; value of your partition:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# &amp;lt;name&amp;gt;               &amp;lt;device&amp;gt;                         &amp;lt;password&amp;gt; &amp;lt;options&amp;gt;&lt;/span&gt;
DISK_NAME_GOES_HERE      &lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;PARTUUID_GOES_HERE     -     luks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A common naming scheme is just prepending your UUID with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;luks-&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s an example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crypttab&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# &amp;lt;name&amp;gt;               &amp;lt;device&amp;gt;                         &amp;lt;password&amp;gt; &amp;lt;options&amp;gt;&lt;/span&gt;
luks-fec2fe57-8a1b-43af-96b4-05cf1b944e03      &lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;fec2fe57-8a1b-43af-96b4-05cf1b944e03     -    luks,discard,fido2-device&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;auto,token-timeout&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Your options should reflect your unlocking method you used with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd-cryptenroll&lt;/code&gt;. If you used a FIDO authenticator, add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fido2-device=auto&lt;/code&gt; to your options. Similarly, you can set a token timeout. If you’re using a password, skip the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fido2&lt;/code&gt; and token timeout options.&lt;/p&gt;

&lt;p&gt;If you want to enable TRIM on the partition, add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;discard&lt;/code&gt; option to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crypttab&lt;/code&gt;. Keep in mind that &lt;a href=&quot;https://wiki.archlinux.org/title/dm-crypt/Specialties#Discard/TRIM_support_for_solid_state_drives_(SSD)&quot;&gt;using TRIM has security implications&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;install-your-root-file-system&quot;&gt;Install your root file-system&lt;/h2&gt;

&lt;p&gt;You can copy over an existing file-system using something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsync&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cp&lt;/code&gt;. If you’re using btrfs, you can use &lt;a href=&quot;https://btrfs.readthedocs.io/en/latest/Send-receive.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs send&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;btrfs receive&lt;/code&gt;&lt;/a&gt; to copy your root subvolume(s) over.&lt;/p&gt;

&lt;p&gt;You can also use &lt;a href=&quot;https://wiki.debian.org/Debootstrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;debootstrap&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://wiki.archlinux.org/title/Pacstrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacstrap&lt;/code&gt;&lt;/a&gt; to bootstrap a new Debian or Arch rootfs.&lt;/p&gt;

&lt;p&gt;You might want to create a root subvolume:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /tmp/disk
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount /dev/mapper/DISK_NAME_GOES_HERE /tmp/disk
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;btrfs subvolume create disk/@
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;umount /tmp/disk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configure-etcfstab&quot;&gt;Configure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;You need to set your root file-system entry correctly.&lt;/p&gt;

&lt;p&gt;Instead of pointing directly to your disk, you need to point &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; to the value of the custom name you set in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/crypttab&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Edit your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt; file to point to your unlocked LUKS device in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/mapper&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/dev/mapper/DISK_NAME_GOES_HERE      /       btrfs   &lt;span class=&quot;nv&quot;&gt;subvol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/@,defaults 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above assumes your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/@&lt;/code&gt; subvolume used as the root subvolume.&lt;/p&gt;

&lt;p&gt;You can also use other btrfs features like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noatime&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compress=zstd&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssd&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;discard=async&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autodefrag&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/dev/mapper/luks-fec2fe57-8a1b-43af-96b4-05cf1b944e03       /     btrfs     &lt;span class=&quot;nv&quot;&gt;subvol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;@,defaults,noatime,compress&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;zstd,ssd,discard&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;async,autodefrag 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Alternatively, &lt;a href=&quot;#get-your-luks-partition-uuid&quot;&gt;you can use the unlocked LUKS volume’s UUID&lt;/a&gt; instead of pointing to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/mapper/DISK_NAME_GOES_HERE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Make sure you have an entry for your EFI partition in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt;. You might not be able to boot without it.&lt;/p&gt;

&lt;h2 id=&quot;unlock-at-boot&quot;&gt;Unlock at boot&lt;/h2&gt;

&lt;h3 id=&quot;edit-kernel-command-line-options&quot;&gt;Edit kernel command-line options&lt;/h3&gt;

&lt;p&gt;On my system, I can edit my kernel command-line options by changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/kernel/cmdline&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;We need to append the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rd.luks.uuid&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; parameters:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rd.luks.uuid&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;PARTUUID_GOES_HERE &lt;span class=&quot;nv&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/mapper/DISK_NAME_GOES_HERE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is how it would look using the example values from above:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rd.luks.uuid&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;fec2fe57-8a1b-43af-96b4-05cf1b944e03 &lt;span class=&quot;nv&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/mapper/luks-fec2fe57-8a1b-43af-96b4-05cf1b944e03
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After adding those parameters, make sure they’re propagated to your bootloader like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd-boot&lt;/code&gt; or GRUB.&lt;/p&gt;

&lt;p&gt;On EndeavourOS, for example, simply running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo reinstall-kernels&lt;/code&gt; will ensure that the new kernel command-line parameters will be supplied at boot.&lt;/p&gt;

&lt;h3 id=&quot;configure-your-early-boot-environment&quot;&gt;Configure your early boot environment&lt;/h3&gt;
&lt;p&gt;You might have to configure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkinitcpio&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dracut&lt;/code&gt; so that you can unlock your drive at boot.&lt;/p&gt;

&lt;p&gt;You might have to add the following modules to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/mkinitcpio&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keyboard&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sd-vconsole&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sd-encrypt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dracut&lt;/code&gt;, you might need to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crypttab&lt;/code&gt; to a configuration file in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/dracut.conf.d&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;install_items+&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; /etc/crypttab &quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You might also have to add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resume&lt;/code&gt; modules to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dracut&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;add_dracutmodules+&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; systemd resume &quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Again, do whatever you need to do on your distribution to update your initramfs. For example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reinstall-kernels&lt;/code&gt; will do that automatically.&lt;/p&gt;

&lt;h3 id=&quot;reboot&quot;&gt;Reboot&lt;/h3&gt;

&lt;p&gt;Cross your fingers and reboot. If everything went well, your system will boot to a prompt asking for you to authenticate and unlock your root partition.&lt;/p&gt;

&lt;h2 id=&quot;encrypted-swap-and-hibernation&quot;&gt;Encrypted swap and hibernation&lt;/h2&gt;
&lt;p&gt;Once your encrypted root partition is set up and you’ve booted into it, you might want to set up encrypted swap, too.&lt;/p&gt;

&lt;h3 id=&quot;create-a-swap-file&quot;&gt;Create a swap file&lt;/h3&gt;
&lt;p&gt;Btrfs gives us some tools that make setting up an encrypted swap with hibernation support easy.&lt;/p&gt;

&lt;p&gt;Mount your LUKS partition to create a swap subvolume:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /tmp/root
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;subvol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/@ /dev/mapper/DISK_NAME_GOES_HERE /tmp/root
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;btrfs create subvolume /tmp/root/swap
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You’ll want to put it in its own subvolume because you cannot take snapshots of subvolumes that contain swapfiles.&lt;/p&gt;

&lt;p&gt;Choose the size of your swap file, if you want to enable hibernation, it needs to be the same size, or larger, than the amount of memory you have.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;btrfs filesystem mkswapfile &lt;span class=&quot;nt&quot;&gt;--size&lt;/span&gt; 64G &lt;span class=&quot;nt&quot;&gt;--uuid&lt;/span&gt; clear /tmp/root/swap/swapfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configure-fstab&quot;&gt;Configure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstab&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Add your swap file to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/swap/swapfile      swap        swap        defaults    0   0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Reload systemd and test out the swap:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;swapon &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;get-the-swap-file-offset&quot;&gt;Get the swap file offset&lt;/h3&gt;

&lt;p&gt;Get the resume offset:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;btrfs inspect-internal map-swapfile &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; /tmp/root/swap/swapfile
198273664  &lt;span class=&quot;c&quot;&gt;# YOUR_RESUME_OFFSET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;get-your-luks-partition-uuid&quot;&gt;Get your LUKS partition UUID&lt;/h3&gt;
&lt;p&gt;Get your unlocked LUKS disk’s UUID:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;blkid
/dev/mapper/DISK_NAME_GOES_HERE: &lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;YOUR_LUKS_UUID&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;UUID_SUB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;IGNORE_THIS&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;BLOCK_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;4096&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;btrfs&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s an example output:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;blkid
/dev/mapper/luks-fec2fe57-8a1b-43af-96b4-05cf1b944e03: &lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ae72c069-9729-43dc-adab-ea0054ef70ee&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;UUID_SUB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;511b5768-dd75-453e-9ecf-a194e9167f2b&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;BLOCK_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;4096&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;btrfs&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case, you’d want to keep the UUID value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ae72c069-9729-43dc-adab-ea0054ef70ee&lt;/code&gt; and ignore the rest.&lt;/p&gt;

&lt;h3 id=&quot;adjust-your-kernel-parameters&quot;&gt;Adjust your kernel parameters&lt;/h3&gt;
&lt;p&gt;Edit your kernel’s command line options. On my system, that means editing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/kernel/cmdline&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;resume&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;YOUR_LUKS_UUID &lt;span class=&quot;nv&quot;&gt;resume_offset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;YOUR_RESUME_OFFSET
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using the example parameters:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;resume&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ae72c069-9729-43dc-adab-ea0054ef70ee &lt;span class=&quot;nv&quot;&gt;resume_offset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;198273664
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then make sure those changes propagate to your kernel’s command-line at boot. This is where running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reinstall-kernels&lt;/code&gt; might help.&lt;/p&gt;

&lt;h3 id=&quot;reboot-and-test-it-out&quot;&gt;Reboot and test it out&lt;/h3&gt;

&lt;p&gt;Restart your machine and then run the following to see if hibernation is configured correctly:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl hibernate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Tue, 21 May 2024 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/articles/cryptsetup-luks-self-encrypting-drives</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/articles/cryptsetup-luks-self-encrypting-drives</guid>
        
        
        <category>code</category>
        
      </item>
    
      <item>
        <title>Toll-free Bridging in Kotlin Native</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/Toll-FreeBridgin/Toll-FreeBridgin.html&quot;&gt;Toll-free bridging&lt;/a&gt; is a concept in macOS and iOS development that allows developers to use &lt;a href=&quot;https://en.wikipedia.org/wiki/Data_type&quot;&gt;data types&lt;/a&gt; interchangeably between the &lt;a href=&quot;https://developer.apple.com/documentation/corefoundation&quot;&gt;Core Foundation&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/foundation&quot;&gt;Foundation Kit&lt;/a&gt; frameworks.&lt;/p&gt;

&lt;h2 id=&quot;about-core-foundation--foundation&quot;&gt;About Core Foundation &amp;amp; Foundation&lt;/h2&gt;

&lt;p&gt;Core Foundation belongs to the &lt;a href=&quot;https://github.com/opensource-apple/CF/tree/master&quot;&gt;open-source framework&lt;/a&gt; created by Apple as a foundation to build libraries and applications for Mac OS. It is C-based and inspired by Foundation.&lt;/p&gt;

&lt;p&gt;Foundation, on the other hand, was created by NeXT for &lt;a href=&quot;https://en.wikipedia.org/wiki/NeXTSTEP&quot;&gt;NeXTSTEP&lt;/a&gt; for similar purposes, and it uses the &lt;a href=&quot;https://en.wikipedia.org/wiki/Objective-C&quot;&gt;Objective-C&lt;/a&gt; programming language. &lt;a href=&quot;https://news.ycombinator.com/item?id=34348838&quot;&gt;Allegedly, it was created for their EOF product&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Tools from the former kit typically start with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CF&lt;/code&gt; for &lt;strong&gt;C&lt;/strong&gt;ore &lt;strong&gt;F&lt;/strong&gt;oundation in their names, while tools from Foundation start with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; for &lt;strong&gt;N&lt;/strong&gt;eXT&lt;strong&gt;S&lt;/strong&gt;TEP.&lt;/p&gt;

&lt;h2 id=&quot;toll-free-bridging&quot;&gt;Toll-free Bridging&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Classic_Mac_OS&quot;&gt;Mac OS&lt;/a&gt; merged with &lt;a href=&quot;https://en.wikipedia.org/wiki/NeXTSTEP#History&quot;&gt;NeXTSTEP to create Mac OS X&lt;/a&gt; and the need to merge the &lt;a href=&quot;https://en.wikipedia.org/wiki/Macintosh_Toolbox&quot;&gt;Mac Toolbox&lt;/a&gt; with &lt;a href=&quot;https://en.wikipedia.org/wiki/OpenStep&quot;&gt;OpenStep&lt;/a&gt; gave forth &lt;em&gt;toll-free &lt;a href=&quot;https://en.wikipedia.org/wiki/Bridging_(programming)&quot;&gt;bridging&lt;/a&gt;&lt;/em&gt; of types between Core Foundation and Foundation. That is, conversion of equivalent types between both frameworks without the need for &lt;a href=&quot;https://en.wikipedia.org/wiki/Type_system#Type_checking&quot;&gt;checking types&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Type_conversion&quot;&gt;converting&lt;/a&gt; between them. There is no cost to cross the Core Foundation to Foundation and Foundation to Core Foundation bridge.&lt;/p&gt;

&lt;p&gt;Toll-free bridging is used by &lt;a href=&quot;https://en.wikipedia.org/wiki/Cocoa_(API)&quot;&gt;Cocoa&lt;/a&gt; to interact with macOS APIs.&lt;/p&gt;

&lt;p&gt;When using tools from Foundation, you are able to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CF&lt;/code&gt; types in places where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; types are expected. Similarly, when using Core Foundation, you’re able to pass in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Object_(computer_science)&quot;&gt;objects&lt;/a&gt; to &lt;a href=&quot;https://en.wikipedia.org/wiki/API&quot;&gt;APIs&lt;/a&gt; that expect &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CF&lt;/code&gt; types.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;sparkly-text number-of-sparkles=&quot;2&quot; style=&quot;--sparkly-text-color: gold; --sparkly-text-size: 2em&quot;&gt;&lt;b class=&quot;shadow&quot;&gt;Click here&lt;/b&gt;&lt;/sparkly-text&gt; to see how Core Foundation types map to Foundation classes below &lt;span class=&quot;shadow&quot;&gt;👇&lt;/span&gt;&lt;/summary&gt;
  &lt;center&gt;
    &lt;div&gt;
      &lt;p&gt;&lt;/p&gt;

      &lt;table&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;th style=&quot;text-align: left&quot;&gt;Core Foundation type&lt;/th&gt;
            &lt;th style=&quot;text-align: left&quot;&gt;Foundation class&lt;/th&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFArrayRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSArray&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFAttributedStringRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSAttributedString&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFBooleanRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSNumber&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFCalendarRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSCalendar&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFCharacterSetRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSCharacterSet&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFDataRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSData&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFDateRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSDate&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFDictionaryRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSDictionary&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFErrorRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSError&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFLocaleRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLocale&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFMutableArrayRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableArray&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFMutableAttributedStringRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableAttributedString&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFMutableCharacterSetRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableCharacterSet&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFMutableDataRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableData&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFMutableDictionaryRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableDictionary&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFMutableSetRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableSet&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFMutableStringRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableString&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFNullRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSNull&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFNumberRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSNumber&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFReadStreamRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSInputStream&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFRunLoopTimerRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTimer&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFSetRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSSet&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFStringRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSString&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFTimeZoneRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTimeZone&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFURLRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSURL&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFWriteStreamRef&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSOutputStream&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;

    &lt;/div&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;/center&gt;
&lt;/details&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ridiculousfish.com/blog/posts/bridge.html&quot;&gt;Here is a good summary circa 2006 of the history and inner workings of toll-free bridging from someone who was involved with its design and implementation&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;kotlin-native&quot;&gt;Kotlin Native&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://kotlinlang.org/docs/native-overview.html&quot;&gt;Kotlin Native&lt;/a&gt; uses the &lt;a href=&quot;https://kotlinlang.org/&quot;&gt;Kotlin programming language&lt;/a&gt; as a &lt;a href=&quot;https://en.wikipedia.org/wiki/LLVM#Frontends&quot;&gt;frontend&lt;/a&gt; and the &lt;a href=&quot;https://llvm.org/&quot;&gt;LLVM compiler&lt;/a&gt; as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Compiler#Back_end&quot;&gt;backend&lt;/a&gt; instead of targeting the &lt;a href=&quot;https://en.wikipedia.org/wiki/Java_virtual_machine&quot;&gt;JVM&lt;/a&gt; for &lt;a href=&quot;https://en.wikipedia.org/wiki/Compiler#Compiled_versus_interpreted_languages&quot;&gt;compilation&lt;/a&gt;. Kotlin Native compiles down to &lt;a href=&quot;https://en.wikipedia.org/wiki/Machine_code&quot;&gt;native code&lt;/a&gt; for multiple platforms including Windows, Linux, macOS, iOS and Android.&lt;/p&gt;

&lt;h2 id=&quot;interoperability&quot;&gt;Interoperability&lt;/h2&gt;

&lt;p&gt;Kotlin Native provides &lt;a href=&quot;https://kotlinlang.org/docs/native-c-interop.html&quot;&gt;built-in C&lt;/a&gt; and &lt;a href=&quot;https://kotlinlang.org/docs/native-objc-interop.html&quot;&gt;Objective-C interoperability&lt;/a&gt;. Kotlin Native makes it easy to import and &lt;a href=&quot;https://kotlinlang.org/docs/native-dynamic-libraries.html#create-a-kotlin-library&quot;&gt;export C&lt;/a&gt; and &lt;a href=&quot;https://kotlinlang.org/docs/apple-framework.html&quot;&gt;Objective-C compatible&lt;/a&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Application_binary_interface&quot;&gt;ABIs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a result, Kotlin Native can be used for macOS and iOS development using both platforms’ native libraries.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;sparkly-text number-of-sparkles=&quot;2&quot; style=&quot;--sparkly-text-color: gold; --sparkly-text-size: 2em&quot;&gt;&lt;b class=&quot;shadow&quot;&gt;Click here&lt;/b&gt;&lt;/sparkly-text&gt; to see how Kotlin Native types map to Swift and Objective-C types below &lt;span class=&quot;shadow&quot;&gt;👇&lt;/span&gt;&lt;/summary&gt;
  &lt;center&gt;
    &lt;div&gt;
      &lt;p&gt;&lt;/p&gt;

      &lt;table&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;th style=&quot;text-align: left&quot;&gt;Kotlin&lt;/th&gt;
            &lt;th style=&quot;text-align: left&quot;&gt;Swift&lt;/th&gt;
            &lt;th style=&quot;text-align: left&quot;&gt;Objective-C&lt;/th&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@interface&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interface&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protocol&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@protocol&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constructor&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Initializer&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Initializer&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Property&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Property&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Property&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Method&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Method&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Method&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enum class&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@interface&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;suspend-&amp;gt;&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;completionHandler:&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;completionHandler:&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Throws fun&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throws&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error:(NSError**)error&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Extension&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Extension&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Category member&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;companion&lt;/code&gt; member &amp;lt;-&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Class method or property&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Class method or property&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nan&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Singleton&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shared&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;companion property&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shared&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;companion property&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Primitive type&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Primitive type / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSNumber&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nan&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unit&lt;/code&gt; return type&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Void&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSString&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableString&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableString&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSArray&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MutableList&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableArray&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableArray&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSSet&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MutableSet&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableSet&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableSet&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Map&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dictionary&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSDictionary&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MutableMap&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableDictionary&lt;/code&gt;&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableDictionary&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Function type&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Function type&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Block pointer type&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Inline classes&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Unsupported&lt;/td&gt;
            &lt;td style=&quot;text-align: left&quot;&gt;Unsupported&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;

    &lt;/div&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;/center&gt;
&lt;/details&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;However, the language doesn’t abstract away the need to understand the underlying systems and APIs for the platforms you’re targeting. Kotlin Native does nothing to change the need to manually invoke toll-free bridging when working with Core Foundation and Foundation libraries. You still need to cross the bridge from C to Objective-C/Kotlin and the other way around.&lt;/p&gt;

&lt;p&gt;Kotlin Native also doesn’t &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstraction_(computer_science)&quot;&gt;abstract away&lt;/a&gt; the need for manual &lt;a href=&quot;https://en.wikipedia.org/wiki/Memory_management&quot;&gt;memory management&lt;/a&gt;. It’s up to you to to know who owns your types and when they should be freed from memory.&lt;/p&gt;

&lt;h2 id=&quot;how-to-use-it&quot;&gt;How to use it&lt;/h2&gt;
&lt;h3 id=&quot;from-objective-c-and-c&quot;&gt;From Objective-C and C&lt;/h3&gt;

&lt;p&gt;You can use toll-free bridging just by casting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; types as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CF&lt;/code&gt; types and vice versa. If you do that, however, you have to remember to release memory manually.&lt;/p&gt;

&lt;p&gt;Here’s an example from Apple’s &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/Toll-FreeBridgin/Toll-FreeBridgin.html&quot;&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;NSLocale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gbNSLocale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSLocale&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;alloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initWithLocaleIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;en_GB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CFLocaleRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gbCFLocale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CFLocaleRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gbNSLocale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, we create a Foundation object, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLocale&lt;/code&gt;, and then cast it to its Core Foundation equivalent type.&lt;/p&gt;

&lt;p&gt;Below, we then use that Core Foundation type to call a Core Foundation function, then we cast that object as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSString&lt;/code&gt; pointer to use it with a Foundation function, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLog()&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;CFStringRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cfIdentifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFLocaleGetIdentifier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gbCFLocale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;cfIdentifier: %@&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cfIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, we have to release the memory used by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CF&lt;/code&gt; type:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CFRelease((CFLocaleRef) gbNSLocale);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;toll-free-bridging-and-arc&quot;&gt;Toll-free bridging and ARC&lt;/h4&gt;

&lt;p&gt;What if you want to hand off ownership of a Core Foundation type to &lt;a href=&quot;https://en.wikipedia.org/wiki/Objective-C#Garbage_collection&quot;&gt;Objective-C’s ARC&lt;/a&gt;? And what if you want to hand ownership of an Objective-C object to C?&lt;/p&gt;

&lt;p&gt;Core Foundation provides functions like &lt;a href=&quot;https://developer.apple.com/documentation/foundation/1587932-cfbridgingrelease&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFBridgingRelease()&lt;/code&gt;&lt;/a&gt; to move ownership of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CF&lt;/code&gt; types to Objective-C and &lt;a href=&quot;https://developer.apple.com/documentation/foundation/1416649-cfbridgingretain&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFBridgingRetain()&lt;/code&gt;&lt;/a&gt; to give ownership of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; type to C.&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Bridge to Core Foundation&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;NSArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foundationArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;Objective&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;Example&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CFArrayRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coreFoundationArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFBridgingRetain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foundationArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The last line in the example above moves ownership of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSArray&lt;/code&gt; to C from ARC, re-casted as an equivalent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFArrayRef&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here we take a Core Foundation object and move its ownership to ARC:&lt;/p&gt;
&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;CFMutableArrayRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mutableCoreFoundationArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFArrayCreateMutableCopy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kCFAllocatorDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coreFoundationArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CFArrayAppendValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mutableCoreFoundationArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFSTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Bridge to Foundation&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;NSArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;updatedFoundationArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFBridgingRelease&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mutableCoreFoundationArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;from-kotlin-native&quot;&gt;From Kotlin Native&lt;/h3&gt;
&lt;h4 id=&quot;why-toll-free-bridging-is-necessary-in-kotlin-native&quot;&gt;Why toll-free bridging is necessary in Kotlin Native&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://kotlinlang.org/docs/native-objc-interop.html#usage&quot;&gt;Kotlin Native supports bidirectional compatibility with Objective-C&lt;/a&gt;. That means that Kotlin Native can import and export Objective-C libraries natively.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://kotlinlang.org/docs/native-memory-manager.html&quot;&gt;Kotlin Native also has its own memory management model&lt;/a&gt; that is unlike C and Objective-C’s ARC. The language uses &lt;a href=&quot;https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)&quot;&gt;garbage collection&lt;/a&gt; to manage memory instead of &lt;a href=&quot;https://en.wikipedia.org/wiki/Reference_counting&quot;&gt;reference counting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;According to KN’s developers, integration between Kotlin’s garbage collector is seamless with Objective-C’s ARC. That means once an object crosses into Objective-C land, and ARC would be aware of it, Kotlin is, too.&lt;/p&gt;

&lt;p&gt;In contrast, when working with C code and Kotlin Native, manual memory management is still needed for C objects.&lt;/p&gt;

&lt;p&gt;With that in mind, we can let Kotlin’s garbage collector handle our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; types and be vigilant about memory management when using Core Foundation types.&lt;/p&gt;

&lt;p&gt;When we need to cross the Core Foundation to Foundation bridge, we don’t have to release memory manually. That’s because once crossed to the Objective-C side of things, ARC owns the object. Kotlin Native integrates with ARC and handles the memory for us.&lt;/p&gt;

&lt;p&gt;When we need to cross the Foundation to Core Foundation bridge, neither ARC nor Kotlin Native’s garbage collector are managing our objects’ memory.&lt;/p&gt;

&lt;h4 id=&quot;toll-free-bridging-in-kotlin-native&quot;&gt;Toll-free bridging in Kotlin Native&lt;/h4&gt;

&lt;p&gt;While Kotlin Native supports Objective-C interoperability, it does not support simply casting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CF&lt;/code&gt; types as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; types, and vice versa, in order to use them.&lt;/p&gt;

&lt;p&gt;If you want to use a Foundation type with Core Foundation, or the other way around, you will need to manually cross that bridge.&lt;/p&gt;

&lt;h4 id=&quot;working-with-core-foundation-types&quot;&gt;Working with Core Foundation types&lt;/h4&gt;

&lt;p&gt;Core Foundation types derive from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFTypeRef&lt;/code&gt;, in both C and Kotlin, and in Kotlin, &lt;a href=&quot;https://developer.apple.com/documentation/corefoundation/cftyperef&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFTypeRef&lt;/code&gt;&lt;/a&gt; is a type alias of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COpaquePointer&lt;/code&gt;, the supertype for other pointer types, which maps to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void*&lt;/code&gt; and is a type alias of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CPointer&amp;lt;T&amp;gt;&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typealias&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;COpaquePointer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CPointed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typealias&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFTypeRef&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kotlinx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cinterop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;COpaquePointer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s what a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CPointer&amp;lt;T&amp;gt;&lt;/code&gt; looks like:&lt;/p&gt;
&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CPointed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rawPtr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NativePtr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NativePointed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rawPtr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toNonNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CPointed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@PublishedApi&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NonNullNativePtr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CValuesRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://kotlinlang.org/docs/native-c-interop.html#pointer-types&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CPointer&lt;/code&gt; is a feature of Kotlin Native’s C interop&lt;/a&gt;, it isn’t unique to the platform, Core Framework, or Objective-C. Kotlin uses it for pointers and arrays in C.&lt;/p&gt;

&lt;p&gt;If we want to use Core Foundation types in Kotlin, &lt;a href=&quot;https://kotlinlang.org/docs/native-objc-interop.html#mappings&quot;&gt;especially to cast them to types that Kotlin integrates like Foundation types&lt;/a&gt;, we’ll need to manually bridge it into Kotlin with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFBridgingRelease()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a naive example:&lt;/p&gt;
&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;platform.CoreFoundation.*&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;platform.CoreGraphics.*&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;platform.Foundation.*&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFArrayRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;CGWindowListCopyWindowInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kCGWindowListOptionAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kCGNullWindowID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;cf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cf&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NSObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// -&amp;gt; CPointer(raw=0x7f7e5ec04080)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// -&amp;gt; CPointer(raw=0x7f7e5ec04080)&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;released&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFBridgingRelease&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;released&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;released&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!::&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qualifiedName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// -&amp;gt; [{kCGWindowLayer=0, kCGWindowMemoryUsage=186720, ...}]&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// -&amp;gt; kotlin.native.internal.NSMutableArrayAsKMutableList&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;asNsObject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;released&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NSObject&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asNsObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!::&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qualifiedName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// -&amp;gt; kotlin.native.internal.NSMutableArrayAsKMutableList&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;asNative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;released&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MutableList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asNative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!::&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qualifiedName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// -&amp;gt; kotlin.native.internal.NSMutableArrayAsKMutableList&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Above, we call the Core Foundation function &lt;a href=&quot;https://developer.apple.com/documentation/coregraphics/1455137-cgwindowlistcopywindowinfo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CGWindowListCopyWindowInfo()&lt;/code&gt;&lt;/a&gt; that returns a &lt;a href=&quot;https://developer.apple.com/documentation/corefoundation/cfarrayref&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFArrayRef?&lt;/code&gt;&lt;/a&gt;, which would map to a &lt;a href=&quot;https://developer.apple.com/documentation/foundation/nsarray&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSArray&lt;/code&gt;&lt;/a&gt; when using toll-free bridging from Objective-C. Using Objective-C, a simple cast is all we would need, unless we want to transfer ownership, but in Kotlin, we will need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFBridgingRelease()&lt;/code&gt; to do our casting and ownership transfer. Then, &lt;a href=&quot;https://kotlinlang.org/docs/typecasts.html&quot;&gt;casting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;as&lt;/code&gt;&lt;/a&gt; tells the compiler to treat the underlying data as a new type without changing the data itself. Casting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;released&lt;/code&gt; to collections successfully compiles and runs at runtime.&lt;/p&gt;

&lt;p&gt;To use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;released&lt;/code&gt; value in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main()&lt;/code&gt; from Kotlin or Foundation APIs, we don’t have to do anything. Looking at its class name, we see that it is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kotlin.native.internal.NSMutableArrayAsKMutableList&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what that looks like in Kotlin:&lt;/p&gt;
&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actual&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractMutableList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actual&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractMutableCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(),&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MutableList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NSMutableArrayAsKMutableList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractMutableList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&amp;gt;(),&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RandomAccess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ObjCObjectWrapper&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableArrayAsKMutableList&lt;/code&gt; is an &lt;a href=&quot;https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-abstract-mutable-list/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AbstractMutableList&lt;/code&gt;&lt;/a&gt; from &lt;a href=&quot;https://kotlinlang.org/api/latest/jvm/stdlib/&quot;&gt;Kotlin’s standard library&lt;/a&gt;. That is the base class for Kotlin Native’s &lt;a href=&quot;https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MutableList&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As it stands, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSMutableArrayAsKMutableList&lt;/code&gt; is equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MutableList&lt;/code&gt; and casts to it both compile and succeed at runtime.&lt;/p&gt;

&lt;p&gt;With that said, there is no reason you need to manually cast any Foundation type to a Kotlin type, as Kotlin will handle the interop for you. That means you can use Kotlin types in place of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NS&lt;/code&gt; types without explicit casts:&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;released&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MutableList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFBridgingRelease&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can now treat &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;released&lt;/code&gt; like any type from Kotlin’s standard library thanks to the language’s built-in Objective-C support.&lt;/p&gt;

&lt;h4 id=&quot;memory-management&quot;&gt;Memory management&lt;/h4&gt;

&lt;p&gt;Creating C objects uses native memory and not the Kotlin application’s &lt;a href=&quot;https://opendsax.cs.vt.edu/ODSA/Books/CS2/html/HeapMem.html&quot;&gt;heap memory&lt;/a&gt;. To automatically handle native memory, you can use &lt;a href=&quot;https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/mem-scoped.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memScoped&lt;/code&gt; blocks&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;kotlinx.cinterop.memScoped&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;memScoped&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;cf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memScoped&lt;/code&gt; blocks allocate memory via &lt;a href=&quot;https://en.wikipedia.org/wiki/Region-based_memory_management&quot;&gt;an arena&lt;/a&gt; and automatically free it when done.&lt;/p&gt;

&lt;h4 id=&quot;writing-idiomatic-extension-functions&quot;&gt;Writing idiomatic extension functions&lt;/h4&gt;

&lt;p&gt;Let’s clean up our example into some extension functions that have better ergonomics.&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFRefType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFBridgingRelease&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFRefType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;memScoped&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we can do things like:&lt;/p&gt;
&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;typealias&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Window&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;typealias&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Windows&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;memScoped&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;CGWindowListCopyWindowInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kCGWindowListOptionAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kCGNullWindowID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filterKeys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cast&amp;lt;T&amp;gt;()&lt;/code&gt; &lt;a href=&quot;https://kotlinlang.org/docs/extensions.html#extension-functions&quot;&gt;extension function&lt;/a&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFRefType&lt;/code&gt; to easily cast them to Kotlin types.&lt;/p&gt;

&lt;p&gt;If we want to go in the other direction and cast a Kotlin type to a Core Foundation type, we can do this:&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;retain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFTypeRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFBridgingRetain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFTypeRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;memScoped&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;retain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;asCoreFoundation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CFRefType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Similarly, we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cast&amp;lt;T&amp;gt;()&lt;/code&gt; extension function on Kotlin objects to easily cast and bridge them to Core Foundation types.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While Kotlin Native, and its related platforms like &lt;a href=&quot;https://www.jetbrains.com/kotlin-multiplatform/&quot;&gt;Kotlin Multiplatform&lt;/a&gt;, abstract away a lot of underlying system details, if you want to target multiple platforms with Kotlin, you still need to understand what Kotlin abstracts over.&lt;/p&gt;

&lt;p&gt;For macOS development, that means understanding how Kotlin Native interops with Objective-C and C, how Objective-C and C interact with each other, and how Core Foundation and Foundation kit interact with one another.&lt;/p&gt;

&lt;p&gt;Sometimes it also means being aware of memory management outside of Kotlin’s garbage collector, and how you can allocate and free memory from C without leaking memory.&lt;/p&gt;

&lt;p&gt;With that said, Kotlin Native makes it easy to also abstract over those implementation details with using features like extension functions, generics and manual memory management.&lt;/p&gt;
</description>
        <pubDate>Fri, 22 Mar 2024 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/articles/toll-free-bridging-kotlin</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/articles/toll-free-bridging-kotlin</guid>
        
        
        <category>code</category>
        
      </item>
    
      <item>
        <title>How to find Ubuntu repository mirrors</title>
        <description>&lt;p&gt;You can use &lt;a href=&quot;https://github.com/alexdelorenzo/find-ubuntu-mirrors&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find-ubuntu-mirrors&lt;/code&gt;&lt;/a&gt; to find alternative repository mirrors for Ubuntu. It will check mirror lists and test the mirrors to see if they’re working or not.&lt;/p&gt;

&lt;p&gt;When it finds mirrors that are compatible with your preferences, &lt;a href=&quot;#output&quot;&gt;it will output the mirrors in Apt’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sources.list&lt;/code&gt; format&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The script also allows you to find Ubuntu mirrors for different architectures like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;ARM (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;armhf&lt;/code&gt; &amp;amp; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aarch64&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;RISC-V (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;riscv64&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;PPC (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppc64el&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;IBM Z (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s390x&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;#script&quot;&gt;Click here to view the source code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find-mirrors.sh&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;usage&quot;&gt;Usage&lt;/h1&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://raw.githubusercontent.com/alexdelorenzo/find-ubuntu-mirrors/master/find-mirrors.sh&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-Ls&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;passing-options&quot;&gt;Passing options&lt;/h2&gt;
&lt;p&gt;The script takes the following positional arguments or environment variables:&lt;/p&gt;

&lt;center&gt;
  &lt;div&gt;

    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Position&lt;/th&gt;
          &lt;th&gt;Variable name&lt;/th&gt;
          &lt;th&gt;Description&lt;/th&gt;
          &lt;th&gt;Default value&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;1&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ARCH&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Architecture that the mirrors support&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amd64&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;2&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$DISTRO&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Version of Ubuntu the mirrors support&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;focal&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;3&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$REPOSITORY&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; repository&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;4&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PROTOCOL&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; repository protocol&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;5&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$JOBS&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Number of concurrent network connections&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;

  &lt;/div&gt;
  &lt;p&gt;&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Here’s the syntax:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-Ls&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bash &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ARCH&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DISTRO&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$REPOSITORY&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PROTOCOL&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$JOBS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you want to find alternatives for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aarch64&lt;/code&gt; architectures while checking 6 repositories concurrently, you can do this:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-Ls&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bash &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; aarch64 focal main http 6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can also use environment variables instead:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;aarch64 &lt;span class=&quot;nv&quot;&gt;DISTRO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;focal &lt;span class=&quot;nv&quot;&gt;JOBS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-Ls&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;output&quot;&gt;Output&lt;/h3&gt;
&lt;p&gt;The script will output the mirrors it finds in Apt’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sources.list&lt;/code&gt; format:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-Ls&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bash
deb http://mirror.kumi.systems/ubuntu-ports/ focal main
deb-src http://mirror.kumi.systems/ubuntu-ports/ focal main

deb http://mirrors.portafixe.com/ubuntu/archive/ focal main
deb-src http://mirrors.portafixe.com/ubuntu/archive/ focal main
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;requirements&quot;&gt;Requirements&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;Bash&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/parallel/&quot;&gt;GNU &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parallel&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mgdm/htmlq&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;htmlq&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/httpie/httpie&quot;&gt;HTTPie&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;script&quot;&gt;Script&lt;/h1&gt;
&lt;p&gt;You can check out &lt;a href=&quot;https://github.com/alexdelorenzo/find-ubuntu-mirrors&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find-ubuntu-mirrors&lt;/code&gt;&lt;/a&gt; on GitHub &lt;a href=&quot;https://github.com/alexdelorenzo/find-ubuntu-mirrors&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;
    &lt;b&gt;Click here&lt;/b&gt; to see the source for &lt;code&gt;find-ubuntu-mirrors&lt;/code&gt; below
  &lt;/summary&gt;

  &lt;p&gt;&lt;p /&gt;

  &lt;div&gt;
    &lt;script src=&quot;https://emgithub.com/embed.js?target=https%3A%2F%2Fgithub.com%2Falexdelorenzo%2Ffind-ubuntu-mirrors%2Fblob%2Fmaster%2Ffind-mirrors.sh&amp;amp;style=github&amp;amp;showBorder=on&amp;amp;showLineNumbers=on&amp;amp;showFileMeta=on&amp;amp;showCopy=on&quot;&gt;&lt;/script&gt;
  &lt;/div&gt;

&lt;/p&gt;&lt;/details&gt;
</description>
        <pubDate>Wed, 23 Mar 2022 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/ubuntu-mirrors.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/ubuntu-mirrors.html</guid>
        
        
        <category>notes</category>
        
      </item>
    
      <item>
        <title>How to install npm packages as a non-root user</title>
        <description>&lt;p&gt;After running this script, you will be able run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install -g&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt;, because&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; will install packages as your non-root user. The script will set up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; user directories for you, and then add them to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Packages can then be installed without root privileges:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; yarn
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;yarn
yarn is /home/user/.npm-packages/bin/yarn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Run the following:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://raw.githubusercontent.com/alexdelorenzo/npm-user/main/npm-user.sh&quot;&lt;/span&gt; | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can check out &lt;a href=&quot;#requirements&quot;&gt;the script’s requirements here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;options&quot;&gt;Options&lt;/h3&gt;
&lt;p&gt;The script takes 6 optional positional arguments, or you can set &lt;a href=&quot;https://en.wikipedia.org/wiki/Environment_variable&quot;&gt;environment variables&lt;/a&gt;:&lt;/p&gt;

&lt;center&gt;
  &lt;div&gt;

    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Position&lt;/th&gt;
          &lt;th&gt;Variable name&lt;/th&gt;
          &lt;th&gt;Description&lt;/th&gt;
          &lt;th&gt;Default value&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;1&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ROOT&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;The root directory for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$HOME&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;2&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$SHELL_NAME&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Name of the shell to configure&lt;/td&gt;
          &lt;td&gt;Current shell&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;3&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$SHELL_RC&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Shell configuration file, automatically detected&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$HOME/.profile&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;4&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$BIN&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;’s executable directory&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ROOT/.npm-packages/bin&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;5&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$MAN&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Man_page&quot;&gt;Manpage&lt;/a&gt; directory for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ROOT/.npm-packages/share/man&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;6&lt;/td&gt;
          &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$REINSTALL&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Set to any non-null value to reinstall old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; packages in your new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ROOT&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Unset&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;

  &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;/center&gt;

&lt;h3 id=&quot;passing-options&quot;&gt;Passing options&lt;/h3&gt;
&lt;p&gt;If you want to set your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; path to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.local/.npm-packages&lt;/code&gt;, instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.npm-packages&lt;/code&gt;, and configure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zsh&lt;/code&gt; to work with it, you can run:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://raw.githubusercontent.com/alexdelorenzo/npm-user/main/npm-user.sh&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bash &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~/.local&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;zsh&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can also use environment variables:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ROOT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~/.local&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;SHELL_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;zsh&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;confirming-it-works&quot;&gt;Confirming it works&lt;/h3&gt;
&lt;p&gt;Install a package with the global flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt; and then see where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; puts the files:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; yarn
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;yarn
yarn is /home/user/.npm-packages/bin/yarn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;details&gt;
	&lt;summary&gt;
	  &lt;b&gt;Click here&lt;/b&gt; to see the dependencies and supported systems for this script
	&lt;/summary&gt;

	&lt;p /&gt;

  &lt;div&gt;
    &lt;h3 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h3&gt;
    &lt;ul&gt;
      &lt;li&gt;Bash, GNU Coreutils and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;NPM&lt;/li&gt;
    &lt;/ul&gt;

    &lt;h3 id=&quot;supported-systems&quot;&gt;Supported systems&lt;/h3&gt;
    &lt;h4 id=&quot;shells&quot;&gt;Shells&lt;/h4&gt;
    &lt;p&gt;This script works with configuration files for the following shells:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bash&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zsh&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fish&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sh&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;The script will default to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$HOME/.profile&lt;/code&gt; if it doesn’t recognize any of the shells from above. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksh&lt;/code&gt; uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$HOME/.profile&lt;/code&gt;, but the script wasn’t tested on it.&lt;/p&gt;

    &lt;h4 id=&quot;operating-systems&quot;&gt;Operating systems&lt;/h4&gt;
    &lt;p&gt;This script will work on any POSIX compatible system or compatibility layer.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Linux&lt;/li&gt;
      &lt;li&gt;*BSD&lt;/li&gt;
      &lt;li&gt;macOS&lt;/li&gt;
      &lt;li&gt;WSL 1 &amp;amp; 2 on Windows&lt;/li&gt;
      &lt;li&gt;Cygwin or MSYS2 on Windows&lt;/li&gt;
    &lt;/ul&gt;

  &lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&quot;script&quot;&gt;Script&lt;/h2&gt;
&lt;p&gt;You can check out the script &lt;a href=&quot;https://github.com/alexdelorenzo/npm-user/&quot;&gt;on GitHub&lt;/a&gt; via the &lt;a href=&quot;https://github.com/alexdelorenzo/npm-user/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;🏠 npm-user&lt;/code&gt;&lt;/a&gt; project.&lt;/p&gt;
&lt;details&gt;
	&lt;summary&gt;
		&lt;b&gt;Click here&lt;/b&gt; to show
		&lt;a href=&quot;https://github.com/alexdelorenzo/npm-user/&quot;&gt;
			&lt;code&gt;🏠 npm-user&lt;/code&gt;
		&lt;/a&gt;
		source code below
	&lt;/summary&gt;
	&lt;p&gt;&lt;/p&gt;
	&lt;script src=&quot;https://emgithub.com/embed.js?target=https%3A%2F%2Fgithub.com%2Falexdelorenzo%2Fnpm-user%2Fblob%2Fmain%2Fnpm-user.sh&amp;amp;style=github&amp;amp;showBorder=on&amp;amp;showLineNumbers=on&amp;amp;showFileMeta=on&amp;amp;showCopy=on&amp;amp;fetchFromJsDelivr=on&quot;&gt;&lt;/script&gt;
&lt;/details&gt;
</description>
        <pubDate>Sat, 26 Feb 2022 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/npm-user.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/npm-user.html</guid>
        
        
        <category>javascript</category>
        
      </item>
    
      <item>
        <title>How to get the first item of a Python iterable</title>
        <description>&lt;p&gt;Here’s a succinct definition of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first()&lt;/code&gt; function for Python:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# © 2025 Alex DeLorenzo. Licensed under the LGPLv3.
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TypeVar&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TypeVar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;U&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TypeVar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;U&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Scroll to the bottom or &lt;a href=&quot;#an-async-first-function&quot;&gt;click here to see an async implementation&lt;/a&gt; of this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first()&lt;/code&gt; function.&lt;/p&gt;

&lt;h2 id=&quot;using-the-function&quot;&gt;Using the function&lt;/h2&gt;
&lt;p&gt;Here’s a look at how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first()&lt;/code&gt; with various data structures that are common in Python.&lt;/p&gt;

&lt;h3 id=&quot;iterables&quot;&gt;Iterables&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 0
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ordered-sequences&quot;&gt;Ordered sequences&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;empty-sequences&quot;&gt;Empty sequences&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tuple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;default-value&quot;&gt;Default value&lt;/h3&gt;
&lt;p&gt;The default value can be any object, not just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Missing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;generator-expressions&quot;&gt;Generator expressions&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;strings-and-bytes&quot;&gt;Strings and bytes&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;arrays&quot;&gt;Arrays&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;files&quot;&gt;Files&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pathlib&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;example.txt&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;custom-iterators&quot;&gt;Custom iterators&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterator&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataclasses&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataclass&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@dataclass&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]):&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__next__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;unordered-collections&quot;&gt;Unordered collections&lt;/h3&gt;
&lt;p&gt;Doesn’t make much sense with unordered collections, but it works. It could be used as a way to get a member of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt; without raising a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KeyError&lt;/code&gt; if it’s empty, or to supply a default value.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;an-async-first-function&quot;&gt;An async first function&lt;/h1&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AsyncIterable&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AsyncIterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;aiterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;aiter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;anext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aiterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;
&lt;p&gt;To run these examples with top-level &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; expressions, you can use an async REPL by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python -m asyncio&lt;/code&gt;, or by using IPython.&lt;/p&gt;

&lt;h3 id=&quot;files-1&quot;&gt;Files&lt;/h3&gt;
&lt;p&gt;Here’s an example using &lt;a href=&quot;https://github.com/alexdelorenzo/aiopath&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;📁 aiopath&lt;/code&gt;&lt;/a&gt;, an async &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pathlib&lt;/code&gt; replacement for Python.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aiopath&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AsyncPath&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AsyncPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;example.txt&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;async-iterables&quot;&gt;Async iterables&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;agen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AsyncIterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;agen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;async-generator-expressions&quot;&gt;Async generator expressions&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AsyncIterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;agen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;custom-async-iterators&quot;&gt;Custom async iterators&lt;/h3&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AsyncIterator&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataclasses&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataclass&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@dataclass&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AsyncIterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]):&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__anext__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AsyncIterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_num&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Thu, 13 Jan 2022 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/first.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/first.html</guid>
        
        
        <category>python</category>
        
      </item>
    
      <item>
        <title>How to clean up Python build, caching and packaging artifacts</title>
        <description>&lt;h1 id=&quot;about&quot;&gt;About&lt;/h1&gt;
&lt;p&gt;Python leaves compiled bytecode in project directories under subdirectories named  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pycache__&lt;/code&gt;. Building packages also creates artifacts in project directories.&lt;/p&gt;

&lt;p&gt;This simple script will delete those build, caching and packaging artifacts for you.&lt;/p&gt;

&lt;h1 id=&quot;script&quot;&gt;Script&lt;/h1&gt;
&lt;p&gt;The following depends on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aiopath&lt;/code&gt;, &lt;a href=&quot;https://github.com/alexdelorenzo/aiopath&quot;&gt;which can be found here&lt;/a&gt; or installed via PyPI.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;b&gt;Click here&lt;/b&gt; to see the source code below&lt;/summary&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;script src=&quot;https://gist.github.com/alexdelorenzo/2180dc69a587d79647309767d99489be/f20d094da140cc921ddc1b027e03d1212effaeb8.js&quot;&gt;&lt;/script&gt;
&lt;/details&gt;
</description>
        <pubDate>Sat, 03 Jul 2021 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/pyclean.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/pyclean.html</guid>
        
        
        <category>python</category>
        
      </item>
    
      <item>
        <title>How to list Click CLI commands in the order they&apos;re defined</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://click.palletsprojects.com/en/8.0.x/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;click&lt;/code&gt; is a Python module&lt;/a&gt; used to create &lt;a href=&quot;https://en.wikipedia.org/wiki/Command-line_interface&quot;&gt;command-line interfaces (CLI)&lt;/a&gt; for scripts and applications.&lt;/p&gt;

&lt;p&gt;In the sections below, we’ll look at a method for making sure that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;click&lt;/code&gt; CLI commands are listed in the order they were defined when we invoke the CLI or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--help&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;You can skip ahead to the &lt;a href=&quot;#how-it-works&quot;&gt;explanation for how our solution works here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;building-a-cli-with-click&quot;&gt;Building a CLI with Click&lt;/h2&gt;
&lt;p&gt;Let’s look at a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;click&lt;/code&gt; CLI with a couple of commands:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;


&lt;span class=&quot;nd&quot;&gt;@click.group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


&lt;span class=&quot;nd&quot;&gt;@cli.command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;This should be first.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;xyz_first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


&lt;span class=&quot;nd&quot;&gt;@cli.command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;This should be second.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abc_second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


&lt;span class=&quot;nf&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we run this script, we’ll see that the commands &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xyz-first&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;abc-second&lt;/code&gt; aren’t displayed in the order that they were declared:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./cli.py
Usage: cli.py &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;OPTIONS] COMMAND &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ARGS]...

Options:
  &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;  Show this message and exit.

Commands:
  abc-second  This should be second.
  xyz-first   This should be first.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ordering-commands&quot;&gt;Ordering commands&lt;/h2&gt;
&lt;p&gt;If we want to order those commands in the order that we define their functions, we can subclass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;click.Group&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderCommands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list_commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, when declaring our commands, we pass our new class as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cls&lt;/code&gt; parameter to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;click.group()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@click.group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderCommands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


&lt;span class=&quot;nd&quot;&gt;@cli.command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;This should be first.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;xyz_first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


&lt;span class=&quot;nd&quot;&gt;@cli.command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;This should be second.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abc_second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, we’ll see that our commands are listed in the order they were defined:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./cli.py
Usage: cli.py &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;OPTIONS] COMMAND &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ARGS]...

Options:
  &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;  Show this message and exit.

Commands:
  xyz-first   This should be first.
  abc-second  This should be second.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;
&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;click.Group&lt;/code&gt; object has an attribute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commands&lt;/code&gt; of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict[str, click.Command]&lt;/code&gt;. Normally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Group.list_commands()&lt;/code&gt; just returns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sorted()&lt;/code&gt; list of keys from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commands&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Here’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Group&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list_commands()&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list_commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As an implementation detail of &lt;a href=&quot;https://www.python.org/dev/peps/pep-0468/&quot;&gt;PEP 468&lt;/a&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt;’s keys are sorted in the order that they were created. The keys act similar to how a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list&lt;/code&gt; orders its items, instead of being unordered like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt;. This is the default behavior in Python 3.6 and up.&lt;/p&gt;

&lt;p&gt;That means we can make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Group.list_commands()&lt;/code&gt; just return the keys to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Group.commands&lt;/code&gt; attribute in order to preserve the order that our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;click&lt;/code&gt; commands were defined:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list_commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Thu, 27 May 2021 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/click.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/click.html</guid>
        
        
        <category>python</category>
        
      </item>
    
      <item>
        <title>How to use Intel GVT-g to create virtual graphics cards</title>
        <description>&lt;h1 id=&quot;about&quot;&gt;About&lt;/h1&gt;
&lt;p&gt;If you use KVM virtualization on Linux, you might be familiar with &lt;a href=&quot;https://developer.ibm.com/technologies/linux/tutorials/l-pci-passthrough/&quot;&gt;PCI passthrough&lt;/a&gt;.  Using an IOMMU, you can make your hardware available to guest operating systems for near native performance.&lt;/p&gt;

&lt;p&gt;Intel’s solution to make their integrated graphics cards available to virtualized guests is &lt;a href=&quot;https://wiki.archlinux.org/index.php/Intel_GVT-g&quot;&gt;Intel GVT-g&lt;/a&gt;. You can use it to virtualize GPUs to hand off to your virtual machines for enhanced performance compared to emulated graphics hardware.&lt;/p&gt;

&lt;p&gt;This script will let you discover the types of virtualized GPUs your hardware supports, and will let you add and remove the virtualized devices.&lt;/p&gt;

&lt;h2 id=&quot;script&quot;&gt;Script&lt;/h2&gt;
&lt;p&gt;You can check out the script &lt;a href=&quot;https://github.com/alexdelorenzo/intel-gvtg/&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;b&gt;Click here&lt;/b&gt; to see the source code below&lt;/summary&gt;
  &lt;p&gt;&lt;/p&gt;
	&lt;script src=&quot;https://emgithub.com/embed.js?target=https%3A%2F%2Fgithub.com%2Falexdelorenzo%2Fintel-gvtg%2Fblob%2Fmaster%2Fintel_gvtg.sh&amp;amp;style=github&amp;amp;showBorder=on&amp;amp;showLineNumbers=on&amp;amp;showFileMeta=on&amp;amp;showCopy=on&amp;amp;fetchFromJsDelivr=on&quot;&gt;&lt;/script&gt;
&lt;/details&gt;
</description>
        <pubDate>Tue, 19 Jan 2021 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/gvtg.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/gvtg.html</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>How to install Firefox with the GTK Global Menu patch on Ubuntu</title>
        <description>&lt;h1 id=&quot;about&quot;&gt;About&lt;/h1&gt;
&lt;p&gt;On Ubuntu 18.04 and earlier, Firefox is compiled with the GTK Global Menu patch.&lt;/p&gt;

&lt;p&gt;On newer Ubuntu releases, Firefox isn’t compiled with the patch. You need to hit the Alt key on your keyboard to show the application menu.&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&quot;https://kde.org/plasma-desktop/&quot;&gt;Plasma Desktop&lt;/a&gt; with the &lt;a href=&quot;https://github.com/psifidotos/applet-window-appmenu&quot;&gt;Window AppMenu Applet&lt;/a&gt; to simulate the global menu from macOS. It works with both Qt and GTK applications, but Firefox doesn’t take advantage of it.&lt;/p&gt;

&lt;p&gt;This script will download the latest version of Firefox from Ubuntu 18.04’s repositories, install it and hold its version to prevent it from being updated to a version from a newer Ubuntu release.&lt;/p&gt;

&lt;h1 id=&quot;installation-script&quot;&gt;Installation Script&lt;/h1&gt;
&lt;h2 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h2&gt;
&lt;p&gt;You need to have Bash, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wget&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;byobu&lt;/code&gt; and &lt;a href=&quot;https://github.com/ericchiang/pup&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pup&lt;/code&gt;&lt;/a&gt; installed.&lt;/p&gt;

&lt;p&gt;To install the first four, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;bash curl wget byobu
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ericchiang/pup&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pup&lt;/code&gt;&lt;/a&gt; is &lt;a href=&quot;https://packages.debian.org/sid/pup&quot;&gt;packaged for Debian Sid&lt;/a&gt;. You can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dpkg&lt;/code&gt; to install it.&lt;/p&gt;

&lt;h2 id=&quot;script&quot;&gt;Script&lt;/h2&gt;
&lt;p&gt;You can check out the script &lt;a href=&quot;https://gist.github.com/alexdelorenzo/041f1d28df63419527bd189390a0595a&quot;&gt;on GitHub&lt;/a&gt;.
&lt;script src=&quot;https://gist.github.com/alexdelorenzo/041f1d28df63419527bd189390a0595a.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 16 Jan 2021 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/firefox-global-menu.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/firefox-global-menu.html</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>How to get unique CFLAGS for your hardware</title>
        <description>&lt;h1 id=&quot;about&quot;&gt;About&lt;/h1&gt;
&lt;p&gt;This script will emit CFLAGS that enable features that are available on your hardware, but are absent when you set GCC’s architecture flag.&lt;/p&gt;

&lt;p&gt;For example, if you have a Skylake processor, your individual processor might have features enabled on it that are not shared across all Skylake processors. This script will list those differences.&lt;/p&gt;

&lt;h1 id=&quot;script&quot;&gt;Script&lt;/h1&gt;
&lt;p&gt;The script below requires the &lt;a href=&quot;https://github.com/alexdelorenzo/strs/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;🧵strs&lt;/code&gt; package&lt;/a&gt; in order to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; command. &lt;a href=&quot;https://github.com/alexdelorenzo/strs/#installation&quot;&gt;Click here for installation instructions&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/alexdelorenzo/866225bb5de796efc65a09371b4880e6.js&quot;&gt;&lt;/script&gt;

</description>
        <pubDate>Sat, 16 Jan 2021 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/cflags.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/cflags.html</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>How to export an OPML file from Airsonic</title>
        <description>&lt;h1 id=&quot;about&quot;&gt;About&lt;/h1&gt;
&lt;p&gt;If you want to export your podcast subscriptions out of Airsonic, you’ll probably want to do so using an &lt;a href=&quot;https://en.wikipedia.org/wiki/OPML&quot;&gt;OPML file&lt;/a&gt;. It’s simply an XML document listing your RSS feed subscriptions that you can import into any RSS feed reader, or podcast client.&lt;/p&gt;

&lt;p&gt;Unfortunately, &lt;a href=&quot;https://github.com/airsonic/airsonic/issues/1422&quot;&gt;Airsonic doesn’t have that feature&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, Airsonic keeps a log of database insertions in a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;airsonic.script&lt;/code&gt;. You can parse it to generate an OPML file.&lt;/p&gt;

&lt;h1 id=&quot;script&quot;&gt;Script&lt;/h1&gt;
&lt;p&gt;This script works on Linux.  If you’re on macOS or *BSD, use &lt;a href=&quot;https://www.gnu.org/software/coreutils/&quot;&gt;GNU &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coreutils&lt;/code&gt;&lt;/a&gt; along with &lt;a href=&quot;https://www.gnu.org/software/grep/&quot;&gt;GNU &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;b&gt;Click here&lt;/b&gt; to see the source code below&lt;/summary&gt;
	&lt;p&gt;&lt;/p&gt;
	&lt;script src=&quot;https://gist.github.com/alexdelorenzo/47267d8ba7cd50735517fe2c9da84414.js&quot;&gt;&lt;/script&gt;
&lt;/details&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h3 id=&quot;script-using-strs&quot;&gt;Script using &lt;a href=&quot;https://github.com/alexdelorenzo/strs/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;🧵strs&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The follow script uses the &lt;a href=&quot;https://github.com/alexdelorenzo/strs/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;🧵strs&lt;/code&gt; package&lt;/a&gt; for Python.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;b&gt;Click here&lt;/b&gt; to see the source code below&lt;/summary&gt;
	&lt;p&gt;&lt;/p&gt;
	&lt;script src=&quot;https://gist.github.com/alexdelorenzo/cc33c49ff704b4e0c461e6d0f70e422c.js&quot;&gt;&lt;/script&gt;
&lt;/details&gt;
</description>
        <pubDate>Sat, 16 Jan 2021 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/notes/airsonic-opml.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/notes/airsonic-opml.html</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Using Unix Pipes to Improve Chromecast Playback</title>
        <description>&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Looks like this &lt;a href=&quot;https://news.ycombinator.com/item?id=23673825&quot;&gt;made it to the top of Hacker News&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;the-issue&quot;&gt;The Issue&lt;/h1&gt;

&lt;p&gt;When casting from YouTube to a Chromecast, sometimes the audio playback will &lt;a href=&quot;https://support.google.com/chromecast/thread/13807879?hl=en&quot;&gt;skip&lt;/a&gt; and &lt;a href=&quot;https://support.google.com/youtube/thread/17251626?hl=en&quot;&gt;stutter&lt;/a&gt;. This issue is independent of the quality of the video, the FPS, or the internet connection. Trying to watch certain videos will reliably cause playback issues on the Chromecast.&lt;/p&gt;

&lt;p&gt;According to &lt;a href=&quot;https://support.google.com/chromecast/thread/13807879&quot;&gt;this thread&lt;/a&gt;, the playback issue only appeared in the latest and final firmware update for the first-gen Chromecast. Successful playback of the videos was possible in the past, and casting the downloaded YouTube videos eliminates the problem entirely. The problem exists solely when casting certain videos using the YouTube app.&lt;/p&gt;

&lt;h1 id=&quot;a-solution&quot;&gt;A Solution&lt;/h1&gt;
&lt;p&gt;Given that the problem only occurs with the YouTube app, you can download a video and cast it via &lt;a href=&quot;https://github.com/xat/castnow&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;castnow&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://github.com/skorokithakis/catt&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;catt&lt;/code&gt;&lt;/a&gt;, skipping the YouTube app entirely.&lt;/p&gt;

&lt;p&gt;You could do something like:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://youtu.be/Kas0tIxDvrg&quot;&lt;/span&gt;


cast&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;--get-filename&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# download&lt;/span&gt;
  youtube-dl &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# wait a bit to finish download&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# cast the video then delete it&lt;/span&gt;
  castnow &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;


cast &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But having to skip using the YouTube app to cast is already a clunky solution, and downloading every video before playing them is an even worse user experience. Instant playback and ephemeral streams are what make for a pleasant video streaming experience these days, and this solution implements neither of them.&lt;/p&gt;

&lt;h1 id=&quot;a-slightly-better-solution&quot;&gt;A Slightly Better Solution&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ytdl-org/youtube-dl/blob/master/README.md&quot;&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl&lt;/code&gt; allows us to output to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt;&lt;/a&gt;, if we can hook its &lt;a href=&quot;https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt;&lt;/a&gt; to a casting app, we could emulate the instant playback and ephemeral videos we expect because we don’t have to wait for an entire file to download.&lt;/p&gt;

&lt;p&gt;Unfortunately, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;castnow&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;catt&lt;/code&gt; won’t cast from &lt;a href=&quot;https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdin&lt;/code&gt;&lt;/a&gt;. You’re expected to pass it file locations to cast from.&lt;/p&gt;

&lt;p&gt;This is where one of my favorite shell features really shines: &lt;a href=&quot;https://tldp.org/LDP/abs/html/process-sub.html&quot;&gt;process substitution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With process substitution, Bash gives us a convenient way to make ephemeral &lt;a href=&quot;https://en.wikipedia.org/wiki/Anonymous_pipe&quot;&gt;anonymous pipes&lt;/a&gt;. This method is both efficient and concurrent, making this primitive an apt choice to build a solution to the problem at hand. A process reading the &lt;a href=&quot;https://en.wikipedia.org/wiki/Pipeline_(Unix)&quot;&gt;pipe&lt;/a&gt; blocks until the pipe is opened by another process for writing. A process writing to the pipe will suspend until the pipe’s buffer is read by another process. The anonymous pipe will automatically remove itself, and when it is manually removed, its dependent processes will be terminated.&lt;/p&gt;

&lt;p&gt;When using process substitution, a process’ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt; is hooked up to an anonymous pipe. That pipe can be accessed from a &lt;a href=&quot;https://en.wikipedia.org/wiki/File_descriptor&quot;&gt;file descriptor&lt;/a&gt;, and the location of the pipe is given to the calling process.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Piped data&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
/dev/fd/63

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Piped data&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Piped data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the example above, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;(command)&lt;/code&gt; syntax is how we invoke process substitution in Bash. The output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;command&lt;/code&gt; is written to an anonymous pipe, and the calling process is given the location of the file descriptor to access that pipe.&lt;/p&gt;

&lt;p&gt;Using that example, we can take advantage of process substitution:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vlc &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; - &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The command above will play the YouTube video locally with &lt;a href=&quot;https://www.videolan.org/vlc/index.html&quot;&gt;VLC&lt;/a&gt;, and illustrates that process substitution can work for our use case.&lt;/p&gt;

&lt;p&gt;However, when we try to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;castnow&lt;/code&gt;, we can’t cast from the pipe:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;castnow &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; - &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Error: Load failed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Nor can we cast with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;catt&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;catt cast &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; - &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Error: The chosen file does not exist.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We know we can use VLC locally, and VLC also lets you cast to a Chromecast using its IP address.&lt;/p&gt;

&lt;p&gt;Let’s try that again using VLC:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cast-vlc&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# get the ip address for chromecast.lan host&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;dig +short chromecast.lan | &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

  vlc &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; ncurses &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--sout&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;#chromecast&apos;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--sout-chromecast-ip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ip&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--demux-filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;demux_chromecast &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &amp;lt; /dev/tty
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;


cast-vlc &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; - &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That works.&lt;/p&gt;

&lt;p&gt;As an aside, we hook VLC’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdin&lt;/code&gt; to &lt;a href=&quot;https://tldp.org/HOWTO/Text-Terminal-HOWTO-7.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/tty&lt;/code&gt;&lt;/a&gt; so that we can use the ncurses interface even if we invoke the function from a script.&lt;/p&gt;

&lt;p&gt;Let’s look at the &lt;a href=&quot;https://wiki.videolan.org/Documentation:Modules/ncurses/&quot;&gt;ncurses interface&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
        &lt;img src=&quot;/assets/imgs/converted/vlc-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;It only displays the file descriptor, and very little about the video itself. I’m not a fan of that.&lt;/p&gt;

&lt;h1 id=&quot;a-better-solution&quot;&gt;A Better Solution&lt;/h1&gt;

&lt;p&gt;Instead of using anonymous pipes, we can use &lt;a href=&quot;https://en.wikipedia.org/wiki/Named_pipe&quot;&gt;named pipes&lt;/a&gt;. Named pipes are like anonymous pipes, except they are not anonymous (they have a name) nor are they ephemeral. Named pipes still give us the efficiency and concurrency benefits that anonymous pipes give us, but Bash lacks the syntactic sugar it has for process substitution when it comes to named pipes.&lt;/p&gt;

&lt;p&gt;This is how we create named pipes, write to them, read from them and remove them.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkfifo &lt;/span&gt;our-pipe
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Piped data&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; our-pipe &amp;amp;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;our-pipe
Piped data
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;our-pipe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Not as pretty as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;(command)&lt;/code&gt;, but it gets the job done.&lt;/p&gt;

&lt;p&gt;We can give a named pipe the same name as our YouTube video, and that way, the VLC interface will show the name of what we’re watching.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cast-ytdl&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# create a temporary named pipe&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# why? because vlc will show the file descriptor path if we just use process substitution&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;--get-filename&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/tmp/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;mkfifo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# download in background, push to named pipe&lt;/span&gt;
  youtube-dl &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; - &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &amp;amp;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$!&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;disown&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# cast from named pipe&lt;/span&gt;
  cast-vlc &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# cleanup process and named pipe&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;kill&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-9&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &amp;amp;&amp;gt; /dev/null
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;


cast-ytdl &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works, too.&lt;/p&gt;

&lt;p&gt;We need to manually create a named pipe with &lt;a href=&quot;https://linux.die.net/man/1/mkfifo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkfifo&lt;/code&gt;&lt;/a&gt;, redirect &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt; to the named pipe while running the process in the background, and then cleanup the process after casting from it via VLC, otherwise it might linger in the background. Each of those tasks would have been handled for us automatically using process substitution.&lt;/p&gt;

&lt;p&gt;But it does look a bit better:&lt;/p&gt;

&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
        &lt;img src=&quot;/assets/imgs/converted/vlc3-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;h1 id=&quot;caveats&quot;&gt;Caveats&lt;/h1&gt;

&lt;p&gt;Pipes, anonymous pipes and named pipes are also known by another name because of the way they behave: &lt;a href=&quot;https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)#Pipes&quot;&gt;FIFOs&lt;/a&gt;, or &lt;strong&gt;f&lt;/strong&gt;irst &lt;strong&gt;i&lt;/strong&gt;n, &lt;strong&gt;f&lt;/strong&gt;irst &lt;strong&gt;o&lt;/strong&gt;ut. What’s written to the pipe is read from the pipe in first in, first out order. This behavior maps well to video streaming.&lt;/p&gt;

&lt;p&gt;While you can interact with anonymous and named pipes like you would a file, the interface isn’t 1:1 with a &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_file_types#Regular_file&quot;&gt;standard file&lt;/a&gt;. You cannot &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seek()&lt;/code&gt; forward or backward in pipe, you can just read the next forward values. For our use case, that means we cannot skip forward or backward in our streaming videos. We can only play, pause or stop the video.&lt;/p&gt;

&lt;p&gt;That’s not a problem for me, however it’s something that can be mitigated if it’s a problem for you. The first solution I can think of would be to write to a temporary file via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl&lt;/code&gt; and read from it. Or &lt;a href=&quot;/programming/2019/04/14/buffer&quot;&gt;perhaps a temporary spooled file can act as a buffer for the pipe&lt;/a&gt;, such that you can &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seek()&lt;/code&gt; through the buffer, but the buffer itself is ephemeral unlike a normal file.&lt;/p&gt;
</description>
        <pubDate>Sat, 14 Mar 2020 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/linux/2020/03/14/pipes.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/linux/2020/03/14/pipes.html</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>NFS Authentication and Encryption via WireGuard</title>
        <description>&lt;h1 id=&quot;about-nfs-and-wireguard&quot;&gt;About NFS and WireGuard&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://linux-nfs.org/wiki/index.php/Main_Page&quot;&gt;NFS&lt;/a&gt; is a &lt;strong&gt;n&lt;/strong&gt;etwork &lt;strong&gt;f&lt;/strong&gt;ile-&lt;strong&gt;s&lt;/strong&gt;ystem that’s included in the mainline Linux kernel. It’s everywhere that a complete Linux kernel exists. There are Windows and macOS clients for the protocol, and it can be used with Kubernetes and Docker Swarm. Out of the box, the protocol is not encrypted nor does it provide authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.wireguard.com/&quot;&gt;WireGuard&lt;/a&gt; is a VPN protocol that’s in the process of being &lt;a href=&quot;https://www.wireguard.com/build-status/&quot;&gt;included in the mainline Linux kernel&lt;/a&gt;. Despite not being in the current mainline kernel, it’s easy to install on pretty much any Linux platform. It has &lt;a href=&quot;https://www.wireguard.com/xplatform/&quot;&gt;cross-platform implementations&lt;/a&gt;, and there are WireGuard clients for &lt;a href=&quot;https://www.wireguard.com/install/&quot;&gt;Android, OpenWRT, macOS and Windows&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: &lt;a href=&quot;https://lists.zx2c4.com/pipermail/wireguard/2020-January/004906.html&quot;&gt;within a few hours of writing this, WireGuard was slated for release in Linux 5.6&lt;/a&gt;. Pretty good timing.&lt;/p&gt;

&lt;h2 id=&quot;why-tunnel-nfs-over-a-vpn&quot;&gt;Why tunnel NFS over a VPN?&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, the NFS protocol is not encrypted. If you’re on an &lt;a href=&quot;https://usa.kaspersky.com/resource-center/preemptive-safety/public-wifi-risks&quot;&gt;untrusted network&lt;/a&gt;, an attacker can &lt;a href=&quot;https://www.vice.com/en_us/article/jpgmxp/how-to-go-from-0-to-sniffing-packets-in-10-minute&quot;&gt;easily sniff&lt;/a&gt; your NFS traffic. Even if you’re on a trusted network, an untrusted device on your network can &lt;a href=&quot;https://en.wikipedia.org/wiki/ARP_spoofing&quot;&gt;sniff your traffic&lt;/a&gt;. On WiFi, an attacker doesn’t even need to connect to your network, because &lt;a href=&quot;https://en.wikipedia.org/wiki/Wired_Equivalent_Privacy#Weak_security&quot;&gt;WEP&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access#Security_issues&quot;&gt;WPA, and WPA2&lt;/a&gt; can be cracked. Enterprise-grade wireless encryption and isolation fare better, but why risk it?&lt;/p&gt;

&lt;p&gt;The typical method of providing NFS authentication is &lt;a href=&quot;https://wiki.linux-nfs.org/wiki/index.php/NFSv4_Introduction#Security&quot;&gt;via Kerberos&lt;/a&gt;. If you don’t already use Kerberos in your network infrastructure, there is an operational and cognitive overhead for its provision and maintenance. In my opinion, the less moving parts, the better.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://web.mit.edu/rhel-doc/5/RHEL-5-manual/Deployment_Guide-en-US/s1-nfs-server-config-exports.html&quot;&gt;NFS allows us to restrict access of our network shares to specific IP addresses, subnets and hostnames&lt;/a&gt;, giving us &lt;em&gt;some&lt;/em&gt; privacy control. However, this is not entirely secure.&lt;/p&gt;

&lt;p&gt;If we set up a VPN, we can have our &lt;a href=&quot;https://wiki.debian.org/NFSServerSetup#Listening_only_on_particular_IPs&quot;&gt;NFS server only listen on that network&lt;/a&gt;, and not on the wider unencrypted network. Our VPN server can handle authentication and give our authenticated clients hardcoded IP addresses. In our NFS exports, we can restrict which IP addresses can access certain NFS resources, and have a fine-grained policy for both authenticated clients and our shared resources.&lt;/p&gt;

&lt;h2 id=&quot;why-wireguard&quot;&gt;Why WireGuard?&lt;/h2&gt;

&lt;p&gt;WireGuard is a &lt;a href=&quot;https://www.wireguard.com/protocol/&quot;&gt;simple protocol&lt;/a&gt; built upon &lt;a href=&quot;https://www.wireguard.com/papers/wireguard.pdf&quot;&gt;cryptographic primitives that are modern and secure&lt;/a&gt;. Its concise implementation gives it a smaller attack surface than other solutions. The protocol and implementation itself have been &lt;a href=&quot;https://www.wireguard.com/formal-verification/&quot;&gt;formally verified&lt;/a&gt;, and it has the approval of security experts throughout the industry.&lt;/p&gt;

&lt;p&gt;While OpenVPN is widely supported across platforms, &lt;a href=&quot;https://en.wikipedia.org/wiki/WireGuard#Features&quot;&gt;it is a behemoth in comparison&lt;/a&gt;, which means that it has a wider attack surface. It’s relatively complicated to provision and maintain. As opposed to the in-kernel WireGuard protocol, there is at least &lt;a href=&quot;https://lekensteyn.nl/files/pwu-wireguard-thesis-final.pdf&quot;&gt;one extra context switch&lt;/a&gt; between kernel networking and the userspace OpenVPN software. Not only that, but AES is resource intensive on platforms without &lt;a href=&quot;https://en.wikipedia.org/wiki/AES_instruction_set&quot;&gt;hardware accelerated AES&lt;/a&gt; support, whereas &lt;a href=&quot;https://blog.cloudflare.com/do-the-chacha-better-mobile-performance-with-cryptography/&quot;&gt;ChaCha20-Poly1305 is performant on low-powered devices&lt;/a&gt; without hardware acceleration. Since I use many low-powered Linux devices, that context switch and lack of hardware acceleration for AES on OpenVPN has a &lt;a href=&quot;https://www.wireguard.com/performance/&quot;&gt;measurable impact on the speed of my VPN traffic&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;authentication-model&quot;&gt;Authentication Model&lt;/h2&gt;

&lt;p&gt;Our authentication will be based on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Public-key_cryptography&quot;&gt;public key authentication&lt;/a&gt; WireGuard provides, and restricting clients to specific IP addresses on our WireGuard network. Authentication is based on our users’ knowledge of a secret, in this case the private key from the key pair our WireGuard server knows about. This is otherwise known as &lt;a href=&quot;https://www.wireguard.com/#cryptokey-routing&quot;&gt;cryptokey routing&lt;/a&gt;, and is one of the principles WireGuard is built upon.&lt;/p&gt;

&lt;p&gt;WireGuard clients will request a specific IP address from our WireGuard server. Our server will only provision a unique but unchanging IP to the client with the corresponding public key. That way, we can know that traffic from that address is definitely from our authenticated client. We can then use that IP address in our NFS exports to restrict our shares and privileges to only that user.&lt;/p&gt;

&lt;p&gt;We can think of those client IP addresses as being our users, and their private keys as passwords. From there, we can configure our NFS server using the basic IP address restrictions the kernel server provides.&lt;/p&gt;

&lt;h1 id=&quot;nfs-over-wireguard&quot;&gt;NFS over WireGuard&lt;/h1&gt;

&lt;p&gt;First, we need to choose a subnet for our VPN. I’m going to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.8.0.0/24&lt;/code&gt; for our subnet, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.8.0.1&lt;/code&gt; as the address for our WireGuard server.&lt;/p&gt;

&lt;p&gt;For this article, our NFS server and WireGuard host will have the hostname &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-nfs&quot;&gt;Setting up NFS&lt;/h2&gt;
&lt;h3 id=&quot;server-installation&quot;&gt;Server Installation&lt;/h3&gt;

&lt;p&gt;If you’re on a Debian-based Linux distribution, you can install an NFS server like so:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nfs-kernel-server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;server-configuration&quot;&gt;Server Configuration&lt;/h3&gt;

&lt;p&gt;We need to set up our NFS server to listen only on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.8.0.1&lt;/code&gt;. We’re also going to configure the server to use only &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_File_System#NFSv4&quot;&gt;NFSv4&lt;/a&gt;, versus older versions of the protocol.&lt;/p&gt;

&lt;p&gt;On a Debian-based distribution, our configuration file lives on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/default/nfs-kernel-server&lt;/code&gt;. We’re going to edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RPCNFSDOPTS&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RPCMOUNTDOPTS&lt;/code&gt; variables in that file.&lt;/p&gt;

&lt;p&gt;To force NFSv4, we need to disable NFSv2 and NFSv3. NFSv4 has less moving parts and operates &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_File_System#NFSv4&quot;&gt;only on a single port&lt;/a&gt;. Older versions of NFS use many ports and require ancillary services to run alongside the NFS server.&lt;/p&gt;

&lt;p&gt;Add the following to the configuration file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RPCNFSDOPTS=&quot;-N 2 -N 3&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we’re going to instruct the server to listen on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.8.0.1&lt;/code&gt; and to further disable older versions of the NFS protocol:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RPCMOUNTDOPTS=&quot;--manage-gids -N 2 -N 3 -H 10.8.0.1&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To restrict the NFS server to listen only on the specified host, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nfs.conf&lt;/code&gt; file must be created or modified with the following configuration section.&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[nfsd]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;10.8.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make sure you save the configuration files.&lt;/p&gt;

&lt;h3 id=&quot;adding-network-shares&quot;&gt;Adding Network Shares&lt;/h3&gt;

&lt;p&gt;Let’s create the directory structures and bind mounts needed for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exportfs&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /export/example
&lt;span class=&quot;nb&quot;&gt;sudo touch&lt;/span&gt; /export/example/it_worked
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we need to edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/exports&lt;/code&gt; to allow a client to mount our example share:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/export                  10.8.0.0/24&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fsid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0,no_subtree_check&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
/export/example          10.8.0.0/24&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;rw,sync,no_subtree_check,crossmnt,no_root_squash&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first line and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsid&lt;/code&gt; option sets the root for our shares. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsid&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crossmnt&lt;/code&gt;, we can exclude the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/export&lt;/code&gt; prefix on our client at mount time, and just mount &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/export/example&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/example&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second line will allow any client on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.8.0.0/24&lt;/code&gt; subnet to mount &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/export/example&lt;/code&gt; as readable and writable. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sync&lt;/code&gt; option makes writes synchronous, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; makes them asynchronous. I find that synchronous writes are easier to reason about.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no_root_squash&lt;/code&gt; will prevent files that belong to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; from being exported with ownership to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nobody&lt;/code&gt; user. I want my network shares to reflect their source ownership as accurately as possible, so I enable this option.&lt;/p&gt;

&lt;p&gt;Let’s export our shares:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo exportfs -a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;starting-the-server&quot;&gt;Starting the Server&lt;/h3&gt;

&lt;p&gt;First, let’s disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpcbind&lt;/code&gt; because it isn’t required for NFSv4:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl mask rpcbind.service
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl mask rpcbind.socket
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, start the server, or restart it if it’s already running:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl restart nfs-kernel-server.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Great, now let’s test it out on a client machine. Ironically, if everything works as configured, mounting the share should fail, but with specific errors.&lt;/p&gt;

&lt;h3 id=&quot;configuring-the-nfs-client&quot;&gt;Configuring the NFS Client&lt;/h3&gt;

&lt;p&gt;Connect a separate Linux machine to your network, such that it can reach your host via it’s hostname &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;client-installation&quot;&gt;Client Installation&lt;/h3&gt;

&lt;p&gt;Again, assuming you’re using a Debian-based platform, install the NFS client software like so:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nfs-common
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;testing-nfs-security&quot;&gt;Testing NFS Security&lt;/h3&gt;

&lt;p&gt;We’re going to try to mount our network share, and hopefully it will fail. Replace the hostname &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt; in the following commands with the hostname of the machine running your NFS server.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; /mnt/NFS
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; nfs &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;vers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4.2 host:/example /mnt/NFS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hopefully, you will be met with either of the following errors:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mount.nfs: access denied by server while mounting host:/example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or, this error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mount.nfs: Operation not permitted
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setting-up-wireguard&quot;&gt;Setting up WireGuard&lt;/h2&gt;

&lt;h3 id=&quot;installing-wireguard&quot;&gt;Installing WireGuard&lt;/h3&gt;

&lt;p&gt;Head over to the &lt;a href=&quot;https://www.wireguard.com/install/&quot;&gt;official WireGuard website&lt;/a&gt; and choose your installation option.&lt;/p&gt;

&lt;p&gt;On my platform, no configuration is needed and the following will install the needed packages:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;wireguard
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After the software is installed, insert the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wireguard&lt;/code&gt; module into the kernel:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;modprobe wireguard
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In recent kernels, WireGuard ships with Linux by default and will automatically load the kernel module when necessary.&lt;/p&gt;

&lt;h3 id=&quot;generating-key-pairs&quot;&gt;Generating Key Pairs&lt;/h3&gt;

&lt;p&gt;Our server will need to generate a key pair, and each of our clients will need to generate their own unique key pairs.&lt;/p&gt;

&lt;p&gt;On both our server and client issue the following:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;umask &lt;/span&gt;077 
wg genkey &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; privatekey
wg pubkey &amp;lt; privatekey &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; publickey
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Remember to treat your private keys like passwords, and to delete the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;privatekey&lt;/code&gt; files when you are done with them.&lt;/p&gt;

&lt;h3 id=&quot;generate-a-pre-shared-key-psk&quot;&gt;Generate a Pre-shared Key (PSK)&lt;/h3&gt;

&lt;p&gt;For added security, generate a PSK on the client:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wg genpsk &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; psk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will need to generate a new PSK for each of your clients and add them both on the client configuration and on your server. That means every client will have unique pre-shared keys, like they have unique key pairs.&lt;/p&gt;

&lt;p&gt;Treat &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;psk&lt;/code&gt; like a password, as well, and delete it when you’re done.&lt;/p&gt;

&lt;h3 id=&quot;configuring-the-wireguard-server&quot;&gt;Configuring the WireGuard Server&lt;/h3&gt;

&lt;p&gt;On the server, identify the network device you’re using to connect to your network. I am using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth0&lt;/code&gt;. Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth0&lt;/code&gt; with your network device, or use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%i&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You will need to choose a port to listen on. In this case, we’ll use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;51820&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Copy the contents of our server’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;privatekey&lt;/code&gt; to your clipboard. Then, create a file located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/wireguard/wgNFS.conf&lt;/code&gt;. Keep the contents of your first client’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publickey&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;psk&lt;/code&gt; nearby, as we will use it in that file.&lt;/p&gt;
&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[Interface]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;10.8.0.1/24&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ListenPort&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;51820&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;PrivateKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;HOST_PRIVATE_KEY_GOES_HERE&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# client1
&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;[Peer]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;PublicKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;CLIENT_PUBLIC_KEY_GOES_HERE&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;PresharedKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PRESHARED_KEY_GOES_HERE&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;AllowedIPs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;10.8.0.2/32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Remember to add your client’s pre-shared key under its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[Peer]&lt;/code&gt; column.&lt;/p&gt;

&lt;h3 id=&quot;configuring-the-wireguard-client&quot;&gt;Configuring the WireGuard Client&lt;/h3&gt;

&lt;p&gt;For your client, you will need your host’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publickey&lt;/code&gt; and your client’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;privatekey&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;psk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create a file located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/wireguard/wgNFS.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[Interface]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;10.8.0.2/24&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;PrivateKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;CLIENT_PRIVATE_KEY_GOES_HERE&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[Peer]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;PublicKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;HOST_PUBLIC_KEY_GOES_HERE&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;PresharedKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PRESHARED_KEY_GOES_HERE&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Endpoint&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;host:51820&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;AllowedIPs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;10.8.0.0/24&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The last line tells the WireGuard client to route traffic on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.8.0.0/24&lt;/code&gt; subnet through the WireGuard server endpoint.&lt;/p&gt;

&lt;h3 id=&quot;delete-privatekey-and-psk-files&quot;&gt;Delete &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;privatekey&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;psk&lt;/code&gt; Files&lt;/h3&gt;

&lt;p&gt;On your host and clients delete your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;privatekey&lt;/code&gt; files after configuring WireGuard, and delete your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;psk&lt;/code&gt; files, as well.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;privatekey psk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;starting-and-connecting-to-the-vpn&quot;&gt;Starting and Connecting to the VPN&lt;/h3&gt;

&lt;p&gt;On both the host and client, but starting with the host, issue:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;wg-quick up wgNFS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Test that the connection works by pinging the host from the client:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ping -c 1 10.8.0.1
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=0.89 ms

--- 10.8.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.893/0.893/0.893/0.000 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;mount-nfs-share-over-wireguard&quot;&gt;Mount NFS Share over WireGuard&lt;/h2&gt;

&lt;p&gt;On the client machine, run the following:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; nfs &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;vers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4.2 10.8.0.1:/example /mnt/NFS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Test to see if the share mounted.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /mnt/NFS
it_worked
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should be able to access the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;it_worked&lt;/code&gt; example file we created earlier.&lt;/p&gt;

&lt;h2 id=&quot;making-it-permanent&quot;&gt;Making it Permanent&lt;/h2&gt;
&lt;h3 id=&quot;wireguard-via-systemd&quot;&gt;WireGuard via systemd&lt;/h3&gt;
&lt;p&gt;On both the server and client, add a WireGuard service to &lt;a href=&quot;https://www.freedesktop.org/wiki/Software/systemd/&quot;&gt;systemd&lt;/a&gt;. This service will start at boot.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;wg-quick@wgNFS.service
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tear down the existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wgNFS&lt;/code&gt; connection on both machines and then create the VPN connection via the new systemd service.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# stop WireGuard&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;wg-quick down wgNFS

&lt;span class=&quot;c&quot;&gt;# start WireGuard via systemd&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl start wg-quick@wgNFS.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Unmount the example share on the client.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;umount &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /mnt/NFS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;mount-nfs-share-automatically-via-systemd&quot;&gt;Mount NFS Share Automatically via systemd&lt;/h3&gt;

&lt;p&gt;Add an entry to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt; on the client with the parameters for the shares.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;10.8.0.1:/example   /mnt/NFS    nfs vers=4.2,_netdev,noauto,x-systemd.automount,x-systemd.requires=wg-quick@wgNFS.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Reload systemd and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remote-fs.target&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl daemon-reload 
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl restart remote-fs.target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, whenever the mountpoint is accessed, systemd will automatically mount the NFS share to the mountpoint specified in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /mnt/NFS
it_worked
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Tue, 28 Jan 2020 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/linux/2020/01/28/nfs-over-wireguard.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/linux/2020/01/28/nfs-over-wireguard.html</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Migrate Your Google Music Collection with MusicFS</title>
        <description>&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
        &lt;a href=&quot;https://musicfs.firstbyte.dev&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/imgdrive_blue.png&quot; /&gt;
        &lt;/a&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Mount your Google Music collection as a drive with &lt;a href=&quot;https://musicfs.firstbyte.dev/&quot;&gt;MusicFS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As Google Music is being shutdown, this utility will allow those who uploaded their music library to Google Music to back up the songs they uploaded.&lt;/p&gt;

&lt;h1 id=&quot;features&quot;&gt;Features&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Browse your music collection via artists, albums and songs&lt;/li&gt;
  &lt;li&gt;Play and index your collection with your favorite media player&lt;/li&gt;
  &lt;li&gt;Download and backup your entire collection with ease&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;download&quot;&gt;Download&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://musicfs.firstbyte.dev/&quot;&gt;You can sign up for the open MusicFS open beta here&lt;/a&gt;!&lt;/p&gt;
</description>
        <pubDate>Sat, 05 Oct 2019 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/releases/2019/10/05/musicfs.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/releases/2019/10/05/musicfs.html</guid>
        
        
        <category>releases</category>
        
      </item>
    
      <item>
        <title>Listen to Music from Bandcamp with CampFS</title>
        <description>&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
        &lt;a href=&quot;https://campfs.firstbyte.dev&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/imgdrive.png&quot; /&gt;
        &lt;/a&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://campfs.firstbyte.dev/&quot;&gt;CampFS&lt;/a&gt; is an app that lets you stream music and browse Bandcamp as files on your computer.&lt;/p&gt;

&lt;h1 id=&quot;features&quot;&gt;Features&lt;/h1&gt;

&lt;p&gt;With &lt;a href=&quot;https://campfs.firstbyte.dev/&quot;&gt;CampFS&lt;/a&gt;, you can browse and discover music easily.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Search for artists, albums, labels and songs&lt;/li&gt;
  &lt;li&gt;Browse music via tags&lt;/li&gt;
  &lt;li&gt;Find similar artists and albums&lt;/li&gt;
  &lt;li&gt;Stream music with the music player of your choice&lt;/li&gt;
  &lt;li&gt;Access high quality albums&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;download&quot;&gt;Download&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://campfs.firstbyte.dev/&quot;&gt;You can sign up for the open CampFS open beta here&lt;/a&gt;!&lt;/p&gt;

&lt;h1 id=&quot;about-campfs&quot;&gt;About CampFS&lt;/h1&gt;

&lt;p&gt;Over the last decade, it became harder to find new music that I like. I grew up with Yahoo’s music recommendation system, Last.fm and Pandora. As a result, I developed esoteric (read: bad) tastes and I took music discovery as given. Spotify and streaming platforms don’t scratch the itch that Last.fm and Myspace did 15 years ago.&lt;/p&gt;

&lt;p&gt;Enter Soundcloud and Bandcamp, two platforms that let anyone easily distribute music and get paid for it. I love them. Acts in my favorite subgenres tend to adhere to a DIY ethic, and Bandcamp enables that through a generous compensation program for labels and artists. Where artists might only make a few cents with a thousand Spotify plays, &lt;a href=&quot;https://bandcamp.com/fair_trade_music_policy&quot;&gt;they can recoup 80-85% of purchase price of content they sell on Bandcamp&lt;/a&gt;. If we’re honest, that’s a better deal than the 30% cut Apple and Google take via their app stores.&lt;/p&gt;

&lt;p&gt;To ease and automate music discovery for myself, I built a utility that connects with various music streaming platforms like Google Music, Soundcloud and Bandcamp.&lt;/p&gt;

&lt;p&gt;In the interest of supporting artists, this app &lt;strong&gt;does not&lt;/strong&gt; enable piracy. Only content that labels and artists list as free to download are accessible. Links to buy content and support artists are plentiful throughout the browsing experience.&lt;/p&gt;

&lt;p&gt;After talking with other music lovers in my favorite scenes, it seems that Bandcamp became the Myspace &lt;em&gt;du jour&lt;/em&gt; for underground music in 2019. I chose to release this app so that other people can discover music and support artists with the same ease that I can.&lt;/p&gt;
</description>
        <pubDate>Tue, 01 Oct 2019 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/releases/2019/10/01/campfs.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/releases/2019/10/01/campfs.html</guid>
        
        
        <category>releases</category>
        
      </item>
    
      <item>
        <title>A Stream Buffer Library for Python and Rust</title>
        <description>&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;

&lt;p&gt;While building out a project, I found the need to process and save streaming resources locally. Users would stream media via an application, and they would need to seek backwards and forwards in the stream.&lt;/p&gt;

&lt;p&gt;Often, the streaming resource size would be 2-5MB in total. But there were outlier resources that sometimes totaled  several hundred megabytes.&lt;/p&gt;

&lt;p&gt;Sometimes, the user would want to save the entire resource to the disk, but most of the time they’ll just stream the resource without saving it.&lt;/p&gt;

&lt;h1 id=&quot;the-problem&quot;&gt;The Problem&lt;/h1&gt;

&lt;p&gt;I want a simple buffer-like library that will both suit the user’s needs and not distract from the larger problem. It needs to be &lt;a href=&quot;https://en.wikipedia.org/wiki/Thread_safety&quot;&gt;thread-safe&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;looking-for-a-solution&quot;&gt;Looking for a Solution&lt;/h1&gt;

&lt;p&gt;The app was written in Python, so let’s take advantage of its &lt;a href=&quot;https://docs.python.org/3/library/&quot;&gt;rich standard library&lt;/a&gt;. After we build the solution, &lt;a href=&quot;#writing-it-in-rust&quot;&gt;I will implement it in Rust&lt;/a&gt; to better test my assumptions about the code and problem-space itself.&lt;/p&gt;

&lt;h2 id=&quot;tempfile&quot;&gt;tempfile&lt;/h2&gt;

&lt;p&gt;Python has a library for platform-independent creation of temporary files and directories, called &lt;a href=&quot;https://docs.python.org/3/library/tempfile.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tempfile&lt;/code&gt;&lt;/a&gt;. It takes care of creating and deleting ephemeral files and folders so you don’t create a mess for yourself or your users.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryFile&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TemporaryFile&lt;/code&gt;&lt;/a&gt; conforms to &lt;a href=&quot;https://docs.python.org/3/glossary.html#term-file-object&quot;&gt;Python’s file-like interface&lt;/a&gt;, so that fits the bill for a buffer-like library.&lt;/p&gt;

&lt;p&gt;However, writing a relatively small buffer to disk upon streaming each resource doesn’t make sense to me.&lt;/p&gt;

&lt;h2 id=&quot;spooledtemporaryfile&quot;&gt;SpooledTemporaryFile&lt;/h2&gt;

&lt;p&gt;Where a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TemporaryFile&lt;/code&gt; initially writes to disk when its buffer is written to, a &lt;a href=&quot;https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt;&lt;/a&gt; will first write to memory. When it reaches &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_size&lt;/code&gt; bytes, it will then begin writing its buffer to the disk in &lt;a href=&quot;https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)&quot;&gt;FIFO order&lt;/a&gt;. You can also arbitrarily purge the memory buffer to disk by invoking a method.&lt;/p&gt;

&lt;p&gt;This fits the bill a bit better.&lt;/p&gt;

&lt;h1 id=&quot;building-a-solution&quot;&gt;Building a Solution&lt;/h1&gt;

&lt;p&gt;Let’s build a library that solves this problem. We start with a stream, we know its size in advance, and we know we want to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt; as our buffer.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tempfile&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itertools&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wrapt.decorators&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;synchronized&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;MAX_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1_024&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# bytes
&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAX_SIZE&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tempfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;SpooledTemporaryFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I chose to make our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MAX_SIZE&lt;/code&gt; 5MB because the streams, on average, do not exceed 5MB. We will use a combination of &lt;a href=&quot;https://en.wikipedia.org/wiki/Least_Recently_Used#Least_recently_used_(LRU)&quot;&gt;LRU&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Time_to_live&quot;&gt;TTL&lt;/a&gt; cache polices to limit and purge the stream buffers our application creates, but that is out of scope for the class we’re building.&lt;/p&gt;

&lt;p&gt;I want to be able to take chunks out of the buffer at arbitrary sizes and positions, so I decided to use the &lt;a href=&quot;https://docs.python.org/3/reference/datamodel.html#object.__getitem__&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__getitem__&lt;/code&gt; interface&lt;/a&gt; with &lt;a href=&quot;https://docs.python.org/3/c-api/slice.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slice&lt;/code&gt; objects&lt;/a&gt;, similar to that used in &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#lists&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#bytes-objects&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Why? Because the app talks to a server that asks for chunks of bytes at arbitrary lengths.&lt;/p&gt;

&lt;p&gt;We can implement that functionality like so:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__getitem__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isinstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotImplementedError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Not implemented for &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will let us do things like:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;stream_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# snip
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ll need to implement a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt; function to do that, though.&lt;/p&gt;

&lt;h2 id=&quot;reading&quot;&gt;Reading&lt;/h2&gt;

&lt;p&gt;We can’t seek in the stream itself, so it’s best to think of the stream as &lt;a href=&quot;https://en.wikipedia.org/wiki/Generator_(computer_programming)&quot;&gt;a generator&lt;/a&gt; that only produces the next forward value of the streaming resource.&lt;/p&gt;

&lt;p&gt;This is our function signature:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That interface conforms almost exactly to the server requests our application has to handle, which give an offset and size and requires a byte-encoded response.&lt;/p&gt;

&lt;p&gt;Before we implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt;, we need to break the cases the function will encounter.&lt;/p&gt;

&lt;h3 id=&quot;cases-as-a-state-machine&quot;&gt;Cases as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Finite-state_machine&quot;&gt;State Machine&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;We can create an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enum&lt;/code&gt; to enumerate the states our function will handle.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auto&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;BeforeIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Bisected&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;AtIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;AfterIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can also define interfaces that our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StreamBuffer&lt;/code&gt; will implement that can break down the problem we’re trying to solve into testable sub-problems.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;abc&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ABC&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ChunkLocation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ABC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ChunkRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ABC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_before_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_bisected_by_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_at_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_after_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we’ll dive into those four cases and some other details.&lt;/p&gt;

&lt;h3 id=&quot;1-the-chunk-our-client-requests-is-already-in-the-streambuffer&quot;&gt;1. The chunk our client requests is already in the StreamBuffer&lt;/h3&gt;

&lt;p&gt;We can read directly from our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt; buffer and return from it.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_before_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-the-chunk-starts-where-we-last-left-off&quot;&gt;2. The chunk starts where we last left off&lt;/h3&gt;

&lt;p&gt;Next, we’re going to use a &lt;a href=&quot;https://docs.python.org/3.1/library/functions.html#bytearray&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytearray&lt;/code&gt;&lt;/a&gt; to store our return buffer.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Like strings, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; objects are &lt;a href=&quot;https://en.wikipedia.org/wiki/Immutable_object&quot;&gt;immutable&lt;/a&gt;. If we used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; objects to build our return buffer, each time we’d want to extend the return buffer, we’d run into the problem of the interpreter having to concatenate two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; objects to create a third &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; object that contains the contents of the first two objects.&lt;/p&gt;

&lt;p&gt;If the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; objects are small and we do that once or twice, that’s no big deal. However, we have to return arbitrarily many bytes, and the size of the chunks returned by the stream are predetermined and small. In some instances, we could very well be creating tens of thousands of intermediate objects that are created just to be thrown away, which is both slow and inefficient.&lt;/p&gt;

&lt;p&gt;Instead, we can copy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; objects into a list-like data structure, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytearray&lt;/code&gt;. It conforms to most of the &lt;a href=&quot;https://docs.python.org/3/glossary.html#term-bytes-like-object&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt;-like interface&lt;/a&gt;, as well, so there isn’t a feature mismatch between it and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; objects we’re dealing with.&lt;/p&gt;

&lt;p&gt;Then, once our return buffer is filled, we can join the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytearray&lt;/code&gt; into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; object and return it. That’s the last thing we’ll do though.&lt;/p&gt;

&lt;p&gt;We can grab chunks from our stream, and push them to our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt; buffer and copy it to our return buffer. If the return buffer’s size is the length of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slice&lt;/code&gt; or greater, we return the return buffer truncated to the size of the requested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slice&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_at_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-part-of-the-requested-chunk-was-already-loaded-and-part-of-it-wasnt&quot;&gt;3. Part of the requested chunk was already loaded, and part of it wasn’t&lt;/h3&gt;

&lt;p&gt;In this case, we can just use our solutions for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_chunk_before_index()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_chunk_at_index()&lt;/code&gt; and return the concatenated result.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_bisected_by_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;existing_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk_before&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_before_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;existing_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;new_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk_before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk_after&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_at_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;chunks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk_before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunk_after&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;4-none-of-the-requested-chunk-was-loaded-at-all&quot;&gt;4. None of the requested chunk was loaded at all&lt;/h3&gt;

&lt;p&gt;In this case, we’ll need start recording the stream to our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt; exactly where we last left off, until we reach the beginning of our requested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slice&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_after_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we finally reach the location our &lt;a href=&quot;https://en.wikipedia.org/wiki/Subroutine#Main_concepts&quot;&gt;caller&lt;/a&gt; cares about, we extend our return buffer and return it if it reaches or exceeds our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slice&lt;/code&gt;’s size:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;thread-safety&quot;&gt;Thread-safety&lt;/h3&gt;

&lt;p&gt;This library needs to be thread-safe. At any point, another thread can call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt;. If two threads call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt; at once, we can hit a &lt;a href=&quot;https://en.wikipedia.org/wiki/Race_condition&quot;&gt;race condition&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since we’re seeking and writing to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt;, we can have a situation where thread #1 seeks to location X, then thread #2 seeks to location Y, and thread #1 reads/writes to location Y instead of location X. That would be bad.&lt;/p&gt;

&lt;p&gt;If you’ve used Java, &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html&quot;&gt;synchronized methods and blocks&lt;/a&gt; can solve the problem of handling race conditions by sticking a lock in front of our &lt;a href=&quot;https://en.wikipedia.org/wiki/Critical_section&quot;&gt;critical sections&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://wrapt.readthedocs.io/en/latest/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wrapt&lt;/code&gt; library&lt;/a&gt; contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;synchronized&lt;/code&gt; &lt;a href=&quot;https://wiki.python.org/moin/PythonDecorators#What_is_a_Decorator&quot;&gt;decorator&lt;/a&gt; and &lt;a href=&quot;https://docs.python.org/3/reference/datamodel.html#context-managers&quot;&gt;context manager&lt;/a&gt;. We’ll use it to wrap our critical section and make our library thread-safe.&lt;/p&gt;

&lt;p&gt;Let’s go back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt; and stick this &lt;a href=&quot;https://docs.python.org/3/reference/compound_stmts.html#with&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;with&lt;/code&gt; statement&lt;/a&gt; in it:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;synchronized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;finishing-read&quot;&gt;Finishing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Next, we can implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_chunk_location()&lt;/code&gt;, and branch on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enum&lt;/code&gt; it returns.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeforeIndex&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bisected&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AtIndex&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AfterIndex&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;synchronized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeforeIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_before_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AtIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_at_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bisected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_bisected_by_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AfterIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_after_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In Python 3.10, we can write our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt; method using &lt;a href=&quot;https://docs.python.org/3/whatsnew/3.10.html#pep-634-structural-pattern-matching&quot;&gt;pattern matching with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;match&lt;/code&gt; statement&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;synchronized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeforeIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_before_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AtIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_at_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bisected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_bisected_by_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AfterIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_chunk_after_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This method will translate well to the Rust version of this library that we’ll write in the next section.&lt;/p&gt;

&lt;h2 id=&quot;cleaning-up&quot;&gt;Cleaning up&lt;/h2&gt;

&lt;p&gt;I’ll keep a reference to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StreamBuffer&lt;/code&gt; around if I want it to stick around. Otherwise, I want it to clean-up the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt; when it’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)&quot;&gt;garbage collected&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__del__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Releasing &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ll give it a nice &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__repr()__&lt;/code&gt; for the logs:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__repr__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream_index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;writing-it-in-rust&quot;&gt;Writing it in Rust&lt;/h1&gt;

&lt;p&gt;While Python is great for prototyping, &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; makes it easy to catch errors at &lt;a href=&quot;https://en.wikipedia.org/wiki/Compile_time&quot;&gt;compile time&lt;/a&gt; and prevent some errors at runtime. Rust’s type system is expressive, and utilizing &lt;a href=&quot;https://en.wikipedia.org/wiki/Generic_programming&quot;&gt;generics&lt;/a&gt; with &lt;a href=&quot;https://doc.rust-lang.org/reference/trait-bounds.html&quot;&gt;trait bounds&lt;/a&gt; can allow you to write libraries that are both adaptable and &lt;a href=&quot;https://en.wikipedia.org/wiki/Correctness_(computer_science)&quot;&gt;correct&lt;/a&gt;. We can setup our build such that the library won’t compile unless its tests pass.&lt;/p&gt;

&lt;h2 id=&quot;starting-out&quot;&gt;Starting out&lt;/h2&gt;

&lt;p&gt;Rust doesn’t have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tempfile&lt;/code&gt; module in its standard library, but there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tempfile&lt;/code&gt; crate with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTempFile&lt;/code&gt; implementation, so I’ll use that below and declare some constant items.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;#![feature(extend_one)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SeekFrom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IoError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tempfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SpooledTempFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAX_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1_024&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1_024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, I’m going to declare a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileLike&lt;/code&gt; trait that implements traits from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::io&lt;/code&gt;. Then I implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileLike&lt;/code&gt; for all types &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; that have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seek&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Write&lt;/code&gt; traits implemented.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileLike&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Seek&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Seek&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileLike&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ll build some type aliases for the library that will make the rest of the code both clearer and less verbose.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Byte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteBuf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IoError&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteBufResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ByteBuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IoError&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteStreamBuf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ByteResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;dyn&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In both Python and Rust, type aliases exist for developer convenience.&lt;/p&gt;

&lt;p&gt;However, in Python, type annotations are just labels, and are not used for runtime type checking by CPython.&lt;/p&gt;

&lt;p&gt;Type annotations and type aliases have semantic meaning in Rust that is enforced by the compiler.&lt;/p&gt;

&lt;h2 id=&quot;translating-the-streambuffer-class-to-rust&quot;&gt;Translating the StreamBuffer class to Rust&lt;/h2&gt;

&lt;p&gt;Languages like Python are dynamically typed, and have little need for explicit generics.&lt;/p&gt;

&lt;p&gt;Rust allows developers to design APIs that can match their dynamically typed cousins, but with safety and restrictions enforced by the compiler.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StreamBuffer&lt;/code&gt; is generic over the type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; of streaming data we’re iterating over and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileLike&lt;/code&gt; type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F&lt;/code&gt; that was a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt; in Python.&lt;/p&gt;

&lt;p&gt;By making &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StreamBuffer&lt;/code&gt; generic over types &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F&lt;/code&gt;, our Rust implementation isn’t limited to using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SpooledTemporaryFile&lt;/code&gt; as its backing store, and we can safely iterate and handle errors for nearly limitless types of streams.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileLike&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpooledTempFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpooledTempFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;SpooledTempFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MAX_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;START_INDEX&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileLike&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BufferRead&lt;/code&gt; is generic over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt;’s output type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BufferRead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Below, I will define traits that will encode cases our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt; implementation will need to cover.&lt;/p&gt;

&lt;h2 id=&quot;implementing-read&quot;&gt;Implementing read()&lt;/h2&gt;

&lt;p&gt;We can encode the four states our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt; function will encounter in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enum&lt;/code&gt; named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt;, and divide into traits the tasks of reading into a buffer and writing to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tempfile&lt;/code&gt; based on the the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ChunkLocation&lt;/code&gt; provides a trait that identifies one of the four states, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ChunkRead&lt;/code&gt; will provide implementations to read from those locations.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;BeforeIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Bisected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AtIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AfterIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ChunkLocation&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ChunkRead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_before_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_bisected_by_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_at_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_after_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileLike&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ChunkLocation&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StreamBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_chunk_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeforeIndex&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bisected&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AtIndex&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AfterIndex&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileLike&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ChunkRead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ByteBufResult&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteStreamBuf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* snip */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileLike&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BufferRead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ByteBufResult&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteStreamBuf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteBufResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;._chunk_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BeforeIndex&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;._chunk_before_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bisected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;._chunk_bisected_by_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AtIndex&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;._chunk_at_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nn&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AfterIndex&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;._chunk_after_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By breaking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read()&lt;/code&gt; up like this, it allowed me to reason about the library easily, and most importantly, it was easier to test. I was able to find and correct logic errors in the code &lt;a href=&quot;https://gitlab.com/thismachinechills/buffers-rs/-/blob/master/src/lib.rs#L200&quot;&gt;via tests in this Rust module&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The general structure of the Rust code and the corrections that the tests helped elucidate then made their way back into the Python code written above.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;We just walked through building a relatively simple stream buffer. You can &lt;a href=&quot;https://gitlab.com/thismachinechills/buffer&quot;&gt;check out the Python code here&lt;/a&gt; and install it like so:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip3 &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;buffer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can &lt;a href=&quot;https://gitlab.com/thismachinechills/buffers-rs&quot;&gt;check out the Rust code here&lt;/a&gt;, too.&lt;/p&gt;
</description>
        <pubDate>Sun, 14 Apr 2019 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/programming/2019/04/14/buffer.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/programming/2019/04/14/buffer.html</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Optimization with NumPy and Rust</title>
        <description>&lt;p&gt;This is a quick post about optimizing algorithms written in Python with NumPy, and implementing the same code in Rust. We’re going to take a look at one of the &lt;a href=&quot;https://adventofcode.com&quot;&gt;Advent of Code&lt;/a&gt; challenges, solve it, optimize it with NumPy, and then &lt;a href=&quot;#writing-it-in-rust&quot;&gt;write both of our solutions in Rust&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re unfamiliar with Advent of Code, it’s an advent calendar of programming related puzzles which has run each December since 2015. Every day from December 1st until the 25th, a new challenge is posted and you’re encouraged to submit a solution.&lt;/p&gt;

&lt;h2 id=&quot;analyzing-the-challenge&quot;&gt;Analyzing the Challenge&lt;/h2&gt;
&lt;p&gt;Let’s take a look at &lt;a href=&quot;https://adventofcode.com/2018/day/3&quot;&gt;AoC’s Day 3 challenge&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This problem requires us to count the number of overlapping claims in a given area. That area, which is the fabric in the challenge, can be represented by a 2-dimensional array of zeros in a naive solution to this problem.&lt;/p&gt;

&lt;p&gt;Every item in the 2-dimensional array will keep a count of how many claims take ownership of that item.&lt;/p&gt;

&lt;p&gt;Each claim can be thought of as another smaller 2-dimensional array of ones that we add to the larger 2-dimensional array. When we are finished, we can count how many items in the larger 2-dimensional array are greater than 1. Those items will represent the square inches of fabric that belong to more than one claim.&lt;/p&gt;

&lt;h2 id=&quot;pure-python-solution&quot;&gt;Pure Python Solution&lt;/h2&gt;
&lt;p&gt;Here’s a naive solution written in Python. While in the above analysis I said that we can think of each claim as being a 2-dimensional array of ones that we’ll add to the greater 2-dimensional array, our implementation will differ.&lt;/p&gt;

&lt;p&gt;We’ll iterate over the Cartesian coordinates of each claim and add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; to the corresponding item in the greater 2-dimensional array.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__future__&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;annotations&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NamedTuple&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itertools&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;product&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;NO_CLAIM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;INCREMENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MIN_OVERLAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1050&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Claim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NamedTuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Claim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NO_CLAIM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INCREMENT&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count_overlapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;INCREMENT&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_OVERLAP&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# generate list of claims from challenge input file
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# let&apos;s profile our solution
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeit&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeit&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count_overlapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s our output on an Intel processor:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;287 ms ± 14 ms per loop &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mean ± std. dev. of 7 runs, 1 loop each&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
125 ms ± 1.62 ms per loop &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mean ± std. dev. of 7 runs, 10 loops each&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It took nearly half of a second to process roughly one thousand claims. We can do better than that.&lt;/p&gt;

&lt;h2 id=&quot;optimization-with-numpy&quot;&gt;Optimization with NumPy&lt;/h2&gt;
&lt;h3 id=&quot;vecorization&quot;&gt;Vecorization&lt;/h3&gt;
&lt;p&gt;NumPy has a concept called &lt;a href=&quot;https://numpy.org/devdocs/reference/ufuncs.html&quot;&gt;Universal functions, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ufuncs&lt;/code&gt;&lt;/a&gt;, which are &lt;a href=&quot;https://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/VectorizedOperations.html&quot;&gt;vectorized functions over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ndarrays&lt;/code&gt;&lt;/a&gt;. Vectorized functions &lt;a href=&quot;https://en.wikipedia.org/wiki/Array_programming&quot;&gt;work over entire arrays&lt;/a&gt; and, if the underlying hardware supports it, can take advantage of &lt;a href=&quot;https://en.wikipedia.org/wiki/SIMD&quot;&gt;SIMD instructions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;SIMD stands for &lt;strong&gt;s&lt;/strong&gt;ingle &lt;strong&gt;i&lt;/strong&gt;nstruction, &lt;strong&gt;m&lt;/strong&gt;utiple &lt;strong&gt;d&lt;/strong&gt;ata. SIMD instructions allow us to apply an instruction over multiple points of data at the same time. They implement &lt;a href=&quot;https://en.wikipedia.org/wiki/Data_parallelism&quot;&gt;parallelism at the data-level&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
        &lt;img src=&quot;/assets/imgs/posts/SIMD.svg&quot; loading=&quot;lazy&quot; /&gt;
	&lt;/div&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
        &lt;h5&gt;SIMD diagram created by &lt;a href=&quot;https://en.wikipedia.org/wiki/User:Cburnett&quot;&gt;Colin M.L. Burnett&lt;/a&gt; for &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:SIMD.svg#Licensing&quot;&gt;Wikipedia&lt;/a&gt;&lt;/h5&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Examples of SIMD instructions are &lt;a href=&quot;https://en.wikipedia.org/wiki/MMX_(instruction_set)&quot;&gt;MMX&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions&quot;&gt;SSE/SSE2/SSE3/SSE4&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Advanced_Vector_Extensions&quot;&gt;AVX&lt;/a&gt; instruction sets on &lt;a href=&quot;https://en.wikipedia.org/wiki/X86&quot;&gt;x86 processors&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/ARM_architecture#Advanced_SIMD_(Neon)&quot;&gt;NEON instruction sets&lt;/a&gt; on &lt;a href=&quot;https://en.wikipedia.org/wiki/ARM_architecture&quot;&gt;ARM processors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When all that’s said and done, there’s no guarantee that NumPy will use SIMD instructions in our program. However, we’ll still benefit from a performance boost, because &lt;a href=&quot;https://en.wikipedia.org/wiki/NumPy#Features&quot;&gt;NumPy is built upon natively compiled and architectually efficient data structures and operations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have several clustered &lt;a href=&quot;https://en.wikipedia.org/wiki/ARM7&quot;&gt;ARMv7&lt;/a&gt; machines. In the past, NumPy wasn’t optimized for ARM’s NEON instruction set in the same way that it’s optimized for x86 processors with &lt;a href=&quot;https://github.com/numpy/numpy/search?q=sse&amp;amp;unscoped_q=sse&quot;&gt;SSE&lt;/a&gt; and &lt;a href=&quot;https://github.com/numpy/numpy/search?q=avx&amp;amp;unscoped_q=avx&quot;&gt;AVX&lt;/a&gt; instructions. &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html&quot;&gt;GCC’s ability to optimize NumPy at compile time will take advantage of NEON&lt;/a&gt;, although in a more generalized fashion.&lt;/p&gt;

&lt;p&gt;Then, in late 2019, &lt;a href=&quot;https://github.com/numpy/numpy/blob/5eff78bb16df99ffe2e9cad86c4ec649893c0646/doc/neps/nep-0038-SIMD-optimizations.rst&quot;&gt;NumPy received some new NEON optimizations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even when NumPy wasn’t optimized for NEON, I still saw a performance increase when using NumPy instead of pure Python.&lt;/p&gt;

&lt;h3 id=&quot;optimizing-our-solution&quot;&gt;Optimizing Our Solution&lt;/h3&gt;
&lt;p&gt;In our previous solution, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_fabric()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;count_overlapping()&lt;/code&gt; are sequential functions. That is to say that we apply an operation to each item in the array sequentially: we increment the first element in the array, then the next element and so on.&lt;/p&gt;

&lt;p&gt;To optimize our solution, we’ll need to use something beyond just pure Python.&lt;/p&gt;

&lt;p&gt;NumPy is a Python wrapper over lower-level C and Fortran code that implements optimized and natively compiled routines, so we’ll use that.&lt;/p&gt;

&lt;p&gt;Here, we’ll use NumPy’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add()&lt;/code&gt; vectorized &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ufunc&lt;/code&gt; instead of sequentially adding one to each item in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fabric&lt;/code&gt; array.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndarray&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dtype&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;int8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INCREMENT&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our above solution will benefit from NumPy’s memory efficient arrays, compared to our previous solution using Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;Next, we’ll use NumPy’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sum()&lt;/code&gt; routine to locate coordinates that specify values that are greater than 1.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count_overlapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_OVERLAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s see what kind of performance boost we’ll get using our new solution.&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeit&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeit&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count_overlapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s our output on a relatively recent Intel processor:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;12.8 ms ± 883 µs per loop &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mean ± std. dev. of 7 runs, 100 loops each&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
1.76 ms ± 79.8 µs per loop &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mean ± std. dev. of 7 runs, 100 loops each&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Compared to our previous solution, our new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_fabric()&lt;/code&gt; implementation is &lt;em&gt;22 times faster&lt;/em&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;count_overlapping()&lt;/code&gt; is &lt;em&gt;63 times faster&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Not bad.&lt;/p&gt;

&lt;h2 id=&quot;writing-it-in-rust&quot;&gt;Writing It in Rust&lt;/h2&gt;
&lt;p&gt;First, we can write the naive solution in Rust and cut the run time in half compared to our NumPy solution. Then, we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ndarray&lt;/code&gt; crate to further optimize our Rust code along the lines of our NumPy code.&lt;/p&gt;

&lt;p&gt;Here’s the naive solution in Rust.&lt;/p&gt;
&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;itertools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Itertools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NO_CLAIM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INCREMENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_OVERLAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;START&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Claim&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Claim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 
    &lt;span class=&quot;nd&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NO_CLAIM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Claim&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.cartesian_product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INCREMENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count_overlapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_OVERLAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//snip&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;overlapping&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count_overlapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can cut the run time in half &lt;em&gt;again&lt;/em&gt; with the rough translation of the NumPy code below, for a total run time of roughly 3ms.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ndarray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;prelude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ndarray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Ix2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Ix2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Claims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 
    &lt;span class=&quot;nn&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SIDE_LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Claim&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;claims&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pt&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_indices&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.cartesian_product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INCREMENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count_overlapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fabric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fabric&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MIN_OVERLAP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Thu, 06 Dec 2018 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/programming/2018/12/06/numpy.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/programming/2018/12/06/numpy.html</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Social Media Trend Visualization</title>
        <description>&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;

&lt;p&gt;I run &lt;a href=&quot;https://reddit.com/user/DupeBro&quot;&gt;a Reddit bot that identifies duplicate submissions&lt;/a&gt;, and &lt;a href=&quot;https://dupebot.ml&quot;&gt;a companion reverse image search engine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Right now, the bot is active on meme subreddits, but I built a generalized pipeline to mine new Reddit submissions.&lt;/p&gt;

&lt;p&gt;I decided to track a few other subreddits a few months ago. I wanted to mine contentious subreddits, especially those with identified bot activity.&lt;/p&gt;

&lt;p&gt;I settled on mining &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/news&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/politics&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/The_Donald&lt;/code&gt; and a few others.&lt;/p&gt;

&lt;h1 id=&quot;the-caravan&quot;&gt;The “Caravan”&lt;/h1&gt;

&lt;p&gt;It seemed like one day in October, people were suddenly talking about &lt;a href=&quot;https://www.nytimes.com/2018/10/29/us/politics/caravan-trump-shooting-elections.html&quot;&gt;the “caravan”&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
		&lt;a href=&quot;/assets/imgs/converted/caravan_trends-fs8.png&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/caravan_trends-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
		&lt;/a&gt;
	&lt;/div&gt;

	&lt;div class=&quot;flex-item&quot;&gt;
		&lt;a href=&quot;/assets/imgs/converted/caravan_sans-fs8.png&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/caravan_sans-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
		&lt;/a&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The popularity of the “caravan” grew after &lt;a href=&quot;https://www.foxnews.com/world/spontaneous-caravan-of-migrants-winds-way-through-honduras&quot;&gt;Fox News covered stories that used the term&lt;/a&gt; over a couple of days. Before that, a few other sources used the term throughout the end of September and the beginning of October.&lt;/p&gt;

&lt;p&gt;The term exploded after &lt;a href=&quot;https://twitter.com/realDonaldTrump/status/1052183647552491521&quot;&gt;the President, via Twitter, warned Honduras that US aid would stop&lt;/a&gt; if the “caravan” didn’t turn around.&lt;/p&gt;

&lt;p&gt;Over the next two weeks, the President tweeted about the “caravan” 9 times, including posting &lt;a href=&quot;https://twitter.com/realDonaldTrump/status/1057728445386539008&quot;&gt;an attack ad focusing on immigration that included footage of the migrants&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
		&lt;a href=&quot;/assets/imgs/converted/caravan_trends_events-fs8.png&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/caravan_trends_events-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
		&lt;/a&gt;
	&lt;/div&gt;

	&lt;div class=&quot;flex-item&quot;&gt;
		&lt;a href=&quot;/assets/imgs/converted/caravan-fs8.png&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/caravan-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
		&lt;/a&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Let’s see how those trends compare to a related term and the overall new submission trend on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/The_Donald&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;flex&quot;&gt;
	&lt;div class=&quot;flex-item&quot;&gt;
		&lt;a href=&quot;/assets/imgs/converted/immigration_trends-fs8.png&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/immigration_trends-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
		&lt;/a&gt;
	&lt;/div&gt;

	&lt;div class=&quot;flex-item&quot;&gt;
		&lt;a href=&quot;/assets/imgs/converted/total-fs8.png&quot;&gt;
			&lt;img src=&quot;/assets/imgs/converted/total-fs8.png&quot; loading=&quot;lazy&quot; /&gt;
		&lt;/a&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The larger the text is in the image below, the more often the term was used in  submissions to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/The_Donald&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/imgs/mask1124-fs8.png&quot; class=&quot;flex&quot;&gt;&lt;img src=&quot;/assets/imgs/converted/mask1124-fs8.png&quot; alt=&quot;Wordcloud of Caravan-related words&quot; class=&quot;wordcloud&quot; loading=&quot;lazy&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The top 14% of submitters that posted about this topic were responsible for exactly half of caravan-related submissions during the time period examined in the images above.&lt;/p&gt;

&lt;p&gt;45 of the top 50 submitters that posted submissions related to this topic were also within the top 150 submitters to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/The_Donald&lt;/code&gt; during that time.&lt;/p&gt;

&lt;!-- # h1
## h2
### h3
#### h4
##### h5 
###### h6
 --&gt;

</description>
        <pubDate>Mon, 12 Nov 2018 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/programming/2018/11/12/reddit-viz.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/programming/2018/11/12/reddit-viz.html</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Process Scheduling on Linux and macOS</title>
        <description>&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;

&lt;p&gt;Sometimes a task will be heavily disk, network or CPU dependent, and will starve other tasks of those resources. It’s important that such tasks won’t steal resources from other tasks.&lt;/p&gt;

&lt;p&gt;Ideally, some resource intensive tasks would run only when the resources they depend on are idle. That, or resource intensive tasks would have their resource consumption throttled to favor other tasks.&lt;/p&gt;

&lt;p&gt;In this article, we will review CPU and I/O scheduling at the process-level on both Linux and Darwin.&lt;/p&gt;

&lt;h1 id=&quot;process-scheduling&quot;&gt;Process Scheduling&lt;/h1&gt;
&lt;p&gt;Process scheduling priority can be easily tuned with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nice&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Linux processes given a lower &lt;em&gt;niceness&lt;/em&gt; value on the interval &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[-20, 19]&lt;/code&gt;  via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nice&lt;/code&gt; shell interface have priority over those with a larger &lt;em&gt;niceness&lt;/em&gt; value. Internally, &lt;em&gt;niceness&lt;/em&gt; has an interval of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0, 139]&lt;/code&gt;, of which only the last 39 priorities are available to users.&lt;/p&gt;

&lt;p&gt;Here’s how we’d run a process with a lower scheduling precedence:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;nice&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 19 our_expensive_cmd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On macOS, priorities given to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nice&lt;/code&gt; on the command-line, or via the C process management interface, exist on the interval &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[-20, 20]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Darwin, the open source basis for macOS, has &lt;a href=&quot;https://www.manpagez.com/man/2/setpriority/&quot;&gt;additional process priority concepts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, a process with priority &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PRIO_DARWIN_BG&lt;/code&gt; has these properties:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;When a thread or process is in a background state the scheduling priority is set to the lowest value, disk IO is throttled (with behavior similar to using setiopolicy_np(3) to set a throttleable policy), and network IO is throttled for any sockets opened after going into background state.  Any previously opened sockets are not affected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’ll use Darwin’s process priority concepts in the next section.&lt;/p&gt;

&lt;h2 id=&quot;processor-affinity&quot;&gt;Processor Affinity&lt;/h2&gt;
&lt;p&gt;On Linux, we can set a task’s CPU affinity with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskset&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you run a heterogenous multiprocessing (HMP) setup, like those found in &lt;a href=&quot;https://en.wikipedia.org/wiki/ARM_big.LITTLE&quot;&gt;ARM &lt;em&gt;big.LITTLE&lt;/em&gt; designs&lt;/a&gt;, this means you can pin background tasks to the &lt;em&gt;little&lt;/em&gt; processor cores, or a CPU intensive task you’d like to finish quickly to the &lt;em&gt;big&lt;/em&gt; processor cores.&lt;/p&gt;

&lt;p&gt;If you want to take advantage of a processor’s cache or a multicore processor’s shared cache, this can eliminate overhead associated with switching processes between many processors or cache misses/coherency.&lt;/p&gt;

&lt;p&gt;XNU, the kernel from which Darwin is based, exposes &lt;a href=&quot;https://developer.apple.com/library/archive/releasenotes/Performance/RN-AffinityAPI/#//apple_ref/doc/uid/TP40006635-CH1-DontLinkElementID_2&quot;&gt;a thread affinity API&lt;/a&gt;, but there isn’t a convenient &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskset&lt;/code&gt;-like wrapper around it.&lt;/p&gt;

&lt;h1 id=&quot;network-and-disk-io-scheduling&quot;&gt;Network and Disk I/O Scheduling&lt;/h1&gt;

&lt;p&gt;The Linux kernel has a variety of &lt;a href=&quot;https://en.wikipedia.org/wiki/Input/output&quot;&gt;input/ouput (I/O)&lt;/a&gt; queues. I/O is prioritized by each process’s given I/O scheduling class. The classes are &lt;em&gt;idle&lt;/em&gt;, &lt;em&gt;best effort&lt;/em&gt; and &lt;em&gt;real time&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A process with the I/O scheduling class of &lt;em&gt;idle&lt;/em&gt; will be given disk access when the resource is idle.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Best effort&lt;/em&gt; classes have priorities on the interval &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0, 7]&lt;/code&gt;, with lower numbers given a higher priority. &lt;em&gt;Best effort&lt;/em&gt; scheduling is done via round-robin.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Real time&lt;/em&gt; classes are given disk priority, have the same number of priority levels as &lt;em&gt;best effort&lt;/em&gt; and can only be used by root. &lt;em&gt;Real time&lt;/em&gt; scheduled processes can starve other processes of resources. If you don’t know if you should use &lt;em&gt;real time&lt;/em&gt; I/O scheduling, that most likely means that you don’t need it.&lt;/p&gt;

&lt;p&gt;We can set I/O priority on Linux via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ionice&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# run a command with `idle` disk priority&lt;/span&gt;
ionice &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; idle our_expensive_cmd

&lt;span class=&quot;c&quot;&gt;# run a command with the lowest `best effort` disk priority&lt;/span&gt;
ionice &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; best-effort &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 7 our_expensive_cmd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Linux does not have a convenient interface to set network I/O priority. There are many options one can implement to that end, perhaps using kernel network QoS policies or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt;. I’m sure something involving network namespaces could be hacked together and would be pretty cool. However, &lt;a href=&quot;https://github.com/mariusae/trickle&quot;&gt;someone built a userspace solution&lt;/a&gt; with a nice command-line interface, so why not use that?&lt;/p&gt;

&lt;p&gt;Since Linux is well-documented, I will not go into its different tiers of I/O queues, but I will expound on the macOS equivalent when we get to them, as I was unable to find much documentation in macOS-land.&lt;/p&gt;

&lt;p&gt;Unlike Linux, XNU-derived systems have the concept of network I/O priority classes for processes.&lt;/p&gt;

&lt;p&gt;XNU-derived macOS does not have the same scheduling structure as Linux, but does have the ability to prioritize disk I/O.
If we look at the &lt;a href=&quot;https://www.manpagez.com/man/3/setiopolicy_np/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setiopolicy_np()&lt;/code&gt; manpage&lt;/a&gt;, we’ll see that macOS has a handful of I/O priority classes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_IMPORTANT&lt;/code&gt; processes are given utmost priority.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_STANDARD&lt;/code&gt; processes may be delayed in favor of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_IMPORTANT&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_UTILITY&lt;/code&gt; processes are intended to be short-running and are throttled to favor the two priority classes above.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_THROTTLE&lt;/code&gt; processs are intended to be long-running and are throttled to favor the above classes.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_PASSIVE&lt;/code&gt; processes are intended for server-type processes for which I/O is the result of requests from client applications. The intent is that client application I/O will not be slowed down by server I/O initiated by the client. Other priority classes will ignore this class, giving the above classes priority over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_PASSIVE&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Darwin gives us a nice command-line interface around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setiopolicy_np()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setpriority()&lt;/code&gt;, called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskpolicy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can &lt;a href=&quot;https://opensource.apple.com/source/system_cmds/system_cmds-597.1.1/taskpolicy.tproj/taskpolicy.c.auto.html&quot;&gt;browse its source here&lt;/a&gt;, given that it’s part of the Darwin open-source project. Here’s a &lt;a href=&quot;https://www.real-world-systems.com/docs/taskpolicy.1.html&quot;&gt;copy of the relevant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskpolicy&lt;/code&gt; manpage&lt;/a&gt;, since Apple took their copy down.&lt;/p&gt;

&lt;p&gt;Let’s take a look at how we’d run a process with the lowest CPU and I/O priority in Linux:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ionice &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; idle &lt;span class=&quot;nb&quot;&gt;nice&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 19 our_expensive_cmd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s how we’d do something very similar to the above on macOS:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;taskpolicy &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; our_expensive_cmd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-b&lt;/code&gt; flag runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;our_expensive_cmd&lt;/code&gt; with the process priority &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PRIO_DARWIN_BG&lt;/code&gt;, which was touched upon in the previous section.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskpolicy&lt;/code&gt; also allows us to set one of the five disk policies that were listed above. For example, if we wanted to run a process with the policy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_THROTTLE&lt;/code&gt; and scope &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_SCOPE_PROCESS&lt;/code&gt;, we could run:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;taskpolicy &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; throttle our_expensive_cmd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we ran &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskpolicy&lt;/code&gt; with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt; flag, it would do the same as above, but with the scope &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_SCOPE_DARWIN_BG&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Digging around &lt;a href=&quot;https://github.com/apple/darwin-xnu/blob/master/bsd/kern/kern_resource.c&quot;&gt;the XNU kernel source&lt;/a&gt;, we will find that &lt;a href=&quot;https://github.com/apple/darwin-xnu/blob/master/bsd/kern/kern_resource.c#L1534&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_SCOPE_DARWIN_BG&lt;/code&gt; is given the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TASK_POLICY_DARWIN_BG_IOPOL&lt;/code&gt; I/O policy flavor&lt;/a&gt;, which is used to decide the background process I/O tier.&lt;/p&gt;

&lt;p&gt;We’ll also see that the &lt;a href=&quot;https://github.com/apple/darwin-xnu/blob/master/bsd/kern/kern_resource.c#L1547&quot;&gt;default I/O policy for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_SCOPE_DARWIN_BG&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_UTILITY&lt;/code&gt;&lt;/a&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_UTILITY&lt;/code&gt; is given &lt;a href=&quot;https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/osfmk/kern/task_policy.c#L1699&quot;&gt;tier &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THROTTLE_LEVEL_TIER2&lt;/code&gt;&lt;/a&gt;, which is one tier &lt;a href=&quot;https://opensource.apple.com/source/xnu/xnu-3789.41.3/osfmk/kern/policy_internal.h&quot;&gt;above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THROTTLE_LEVEL_TIER3&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Interestingly enough, mobile XNU-derived systems like iOS have a slightly different I/O scheduling scheme than non-mobile systems, based on what I can glean from preprocessor directives.&lt;/p&gt;

&lt;p&gt;Here’s a breakdown of tiers:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THROTTLE_LEVEL_TIER0&lt;/code&gt;, the default scheduling tier for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_NORMAL&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_DEFAULT&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_PASSIVE&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THROTTLE_LEVEL_TIER1&lt;/code&gt;, default for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_STANDARD&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THROTTLE_LEVEL_TIER2&lt;/code&gt;, default for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_UTILITY&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THROTTLE_LEVEL_TIER3&lt;/code&gt;, default for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_THROTTLE&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we try to give a process the scope of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_SCOPE_DARWIN_BG&lt;/code&gt;, but give it any policy but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_UTILITY&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOPOL_THROTTLE&lt;/code&gt;, we’ll get an error:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alex@mbp:~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;taskpolicy &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; passive bash
taskpolicy: setiopolicy_np&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...IOPOL_SCOPE_DARWIN_BG...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: Invalid argument
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At some point I’ll do a write up on XNU QoS latency and throughput tiers, but that’s for another day.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;We took a look at what CPU and I/O prioritization options are available on Linux. We’ve contrasted them with that which are available on macOS.&lt;/p&gt;

&lt;p&gt;While Linux has utilities like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nice&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ionice&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskset&lt;/code&gt;, it lacks a convenient process-level network throttling option. macOS, on the otherhand, has network and disk throttling built-in and available behind the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskpolicy&lt;/code&gt; command-line utility.&lt;/p&gt;

&lt;p&gt;Setting processor affinity is as easy as issuing a shell command on Linux, but on macOS such functionality must implemented at the application level, per application.&lt;/p&gt;
</description>
        <pubDate>Thu, 23 Aug 2018 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/programming/2018/08/23/ionice.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/programming/2018/08/23/ionice.html</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Reverse Engineering CoreDisplay API</title>
        <description>&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;

&lt;!-- When I&apos;m busy doing computer things and get interrupted, I usually leave my MacBook open (I still have decade old scars from data loss triggered by improper hibernation). If my MacBook&apos;s display is on, that will quickly drain my battery. 

Why not set my MacBook to sleep after N minutes?  --&gt;

&lt;p&gt;In this article, we’ll review methods for changing display brightness on a Mac.&lt;/p&gt;

&lt;p&gt;I personally find it irritating when my display shuts off, or my computer locks down, while I’m still looking at it. This happens frequently when watching videos, following a recipe or slowly trying to grok something on the screen. Therefore, I have my display set to turn off at an interval that’s over 1 hour. I know this makes me a bad person.&lt;/p&gt;

&lt;p&gt;I wrote a daemon that dims my display’s backlight if my computer becomes idle &lt;em&gt;and&lt;/em&gt; my face isn’t within the viewing area of my built-in FaceTime webcam.&lt;/p&gt;

&lt;p&gt;You can check it out &lt;a href=&quot;https://github.com/thismachinechills/brightness&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;adjusting-brightness-on-macos&quot;&gt;Adjusting Brightness on macOS&lt;/h1&gt;

&lt;p&gt;Unlike iOS, there is no convenient screen brightness API for macOS.&lt;/p&gt;

&lt;p&gt;Here’s how you’d change your screen’s brightness programmatically with Swift in iOS, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;someBrightnessFloat&lt;/code&gt; is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt; in the interval &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0.0, 1.0]&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;UIScreen&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mainScreen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someBrightnessFloat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It would be convenient if that API were available, but to accomplish this on a Mac, we’ll need to jump through some hoops.&lt;/p&gt;

&lt;p&gt;Eventually, through some research, I came across the relevant APIs in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt; Framework. Great!&lt;/p&gt;

&lt;h2 id=&quot;bridging-between-objective-c-and-python&quot;&gt;Bridging Between Objective-C and Python&lt;/h2&gt;

&lt;p&gt;I decided to build my daemon with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt; and Python 3.7.0, simply because developing command line daemons with Python is fun.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt; tends to have wrappers for Apple’s development frameworks, except none exist for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt;. That’s fine, we can wrap it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt; or even &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctypes&lt;/code&gt; if we’re desperate.&lt;/p&gt;

&lt;p&gt;Let’s look at the relevant Objective-C code. In Objective-C, we’d want to do something along these lines:&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ourBrightnessFloatGoesHere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CGDirectDisplayID&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;display&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGMainDisplayID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;io_service_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOServiceGetMatchingService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kIOMasterPortDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOServiceMatching&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;IODisplaySetFloatParameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kNilOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFSTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kIODisplayBrightnessKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ll need to translate that to Python code with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;bridgesupport&quot;&gt;BridgeSupport&lt;/h2&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctypes&lt;/code&gt;, we need to provide the library with correct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arg_types&lt;/code&gt; and return types. This can be tedious.&lt;/p&gt;

&lt;p&gt;Thankfully, BridgeSupport files can be generated from the library with macOS system tools. These files keep function signatures and typing information in an XML structure. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt; can use BridgeSupport data so we don’t have to manually annotate each function we want to call.&lt;/p&gt;

&lt;p&gt;We’ll need to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit.framework&lt;/code&gt; to find the values we need, which are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kIOMasterPortDefault&lt;/code&gt;, a constant.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kIODisplayBrightnessKey&lt;/code&gt;, a constant.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOServiceMatching&lt;/code&gt;, a function.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOServiceGetMatchingService&lt;/code&gt;, a function.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IODisplaySetFloatParameter&lt;/code&gt;, a function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After poking around the framework, we’ll find that information we need is located in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;graphics/IOGraphicsLib.h&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKitLib.h&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;graphics/IOGraphicsTypes.h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, we’ll need to generate a BridgeSupport file.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRIDGESUPPORT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.bridgesupport&quot;&lt;/span&gt;

gen_bridge_metadata &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-l/System/Library/Frameworks/IOKit.framework/IOKit
                    -I/System/Library/Frameworks/IOKit.framework/Headers/graphics
                    -I/System/Library/Frameworks/IOKit.framework/Headers&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                    /System/Library/Frameworks/IOKit.framework/Headers/graphics/IOGraphicsLib.h &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                    /System/Library/Frameworks/IOKit.framework/Headers/IOKitLib.h  &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                    /System/Library/Frameworks/IOKit.framework/Headers/graphics/IOGraphicsTypes.h &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$BRIDGESUPPORT&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you’re on MacOS 10.13+, you’ll get an error. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gen_bridge_metadata&lt;/code&gt; will look in a directory that doesn’t exist, so we’ll need to symlink the directory we need to the location that doesn’t yet exist.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TOOLCHAINS_DIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Applications/Xcode.app/Contents/Developer/Toolchains&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;WORKING_DIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;


&lt;span class=&quot;c&quot;&gt;# fix issue where gen_bridge_metadata cannot find toolchain&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# https://trac.macports.org/ticket/54939&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;defaults &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;loginwindow SystemVersionStampAsString | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;10.13&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$TOOLCHAINS_DIR&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; OSX10.13.xctoolchain &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; XcodeDefault.xctoolchain OSX10.13.xctoolchain
    &lt;span class=&quot;k&quot;&gt;fi

    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$WORKING_DIR&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Rerun the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gen_bridge_metadata&lt;/code&gt; command again, and we’ll get a nice BridgeSupport file.&lt;/p&gt;

&lt;p&gt;We aren’t in the clear yet. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt; supports a certain dialect in BridgeSupport files, and the one we generated will have values the library doesn’t understand. We’ll need to scrub the BridgeSupport file of those values.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOTimingInformation&lt;/code&gt; has a weird signature, and it’s irrelevant to our use case, so let’s get rid of it.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;/name=&apos;IOTimingInformation&apos;/d&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$BRIDGESUPPORT&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;changing-brightness&quot;&gt;Changing Brightness&lt;/h2&gt;

&lt;p&gt;Great, now we’ve generated a BridgeSupport file for the utilities in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt; we’ll use. Now, we can write some application code.&lt;/p&gt;

&lt;p&gt;Let’s import our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFString&lt;/code&gt; manipulation libraries:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreFoundation&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFStringCreateWithCString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CFRelease&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kCFStringEncodingASCII&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, let’s write a function to import &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__future__&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;annotations&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Callable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Any&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pathlib&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;objc&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;IOKIT_FRAMEWORK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/System/Library/Frameworks/IOKit.framework&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BRIDGESUPPORT_FILE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.bridgesupport&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;DISPLAY_CONNECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;IODisplayConnect&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;import_iokit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iokit_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOKIT_FRAMEWORK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;globals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;bridgesupport_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BRIDGESUPPORT_FILE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;objc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parseBridgeSupport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bridgesupport_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;objc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pathForFramework&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iokit_location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import_iokit()&lt;/code&gt; it will read the BridgeSupport file into a buffer, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt; will parse and load our wrapped functions and values into global namespace.&lt;/p&gt;

&lt;p&gt;Now, let’s write a function that uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt; to change our Mac’s brightness:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_brightness_iokit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IOServiceGetMatchingService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kIOMasterPortDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                          &lt;span class=&quot;nc&quot;&gt;IOServiceMatching&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DISPLAY_CONNECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IODisplaySetFloatParameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                      &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                      &lt;span class=&quot;n&quot;&gt;kIODisplayBrightnessKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                      &lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_brightness_iokit(50)&lt;/code&gt; will dim our display to 50% brightness. Great!&lt;/p&gt;

&lt;h1 id=&quot;undocumented-coredisplay-api&quot;&gt;Undocumented CoreDisplay API&lt;/h1&gt;

&lt;p&gt;Well, if you’re on macOS 10.13+, things aren’t so great. You’ll notice that brightness adjustments using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt;’s  API reset after a certain period. That is, on macOS 10.13, your brightness will go back to its default setting after N seconds/minutes/hours.&lt;/p&gt;

&lt;p&gt;This is because Apple has deprecated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt;’s brightness functionality in favor of a private, undocumented API. The words ‘private undocumented API’ should instill fear in any developer who encounters them on their journey to solve a problem. They’re the &lt;a href=&quot;/assets/imgs/converted/here-be-dragons.png&quot;&gt;&lt;em&gt;Here be dragons&lt;/em&gt;&lt;/a&gt; of software development and dragons are less scary than undocumented features.&lt;/p&gt;

&lt;p&gt;After doing some digging, it appears nobody has documented this API, nor is there a convenient Python bridge for it. The closest I’ve come to seeing developers use this API in the open is the hardcore macOS hacking community, who have patched the framework to support older hardware with newer displays &amp;amp; resolutions. Nobody’s touched it in an effort to change screen brightness.&lt;/p&gt;

&lt;p&gt;Normally, this is the point where I throw my hands up and say, “well, that was a waste of time” and focus my energy somewhere else. However, I built out a pretty good solution around the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOKit&lt;/code&gt; enabled functionality and I am not ready to give that up.&lt;/p&gt;

&lt;h2 id=&quot;reverse-engineering-coredisplay&quot;&gt;Reverse Engineering CoreDisplay&lt;/h2&gt;

&lt;p&gt;First, let’s see if there’s anything we can glean from this framework. We could break out a hex editor, disassembler and all sorts of fun things, but I don’t want to get too crazy, lest it be for naught.&lt;/p&gt;

&lt;p&gt;We need to determine which functions handle setting brightness, or if they even exist.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alex@mbp:/System/Library/Frameworks/CoreDisplay.framework&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rn&lt;/span&gt; Brightness &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Binary file ./CoreDisplay matches
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cool, while there aren’t any header files or code we can use, there seems to be &lt;em&gt;something&lt;/em&gt; related to brightness in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDisplay.framework&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Looking in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDisplay.framework&lt;/code&gt;, we don’t have much to work with: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PList&lt;/code&gt; files and compiled libraries.&lt;/p&gt;

&lt;p&gt;Let’s dig into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDisplay.framework/CoreDisplay&lt;/code&gt; a little further:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alex@mbp:/System/Library/Frameworks/CoreDisplay.framework&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;strings CoreDisplay | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;Brightness | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
  49
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are 49 relevent lines. This is a good thing. Let’s take a deeper look:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alex@mbp:/System/Library/Frameworks/CoreDisplay.framework&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;strings CoreDisplay | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;Brightness | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;Set
void CoreDisplay::Display::SetUserBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay::Display::SetLinearBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay::Display::SetLinearBacklightBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay::Display::SetBacklightBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay_Display_SetDynamicLinearBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay_Display_SetDynamicLinearBrightness_Server&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Skip SetLinearBrightness on offline display 0x%08x
void CoreDisplay::Display::SetDynamicLinearBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
SetDynamicLinearBrightness
void CoreDisplay_Display_SetLinearBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay_Display_SetLinearBrightness_Server&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay_Display_SetUserBrightness&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay_Display_SetUserBrightness_Server&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Skip SetUserBrightness on offline display 0x%08x
void CoreDisplay_Display_SetAutoBrightnessIsEnabled&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, bool&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay_Display_SetAutoBrightnessIsEnabled_Server&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;CGDirectDisplayID, bool&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Skip SetAutoBrightnessIsEnabled on offline display 0x%08x
void CoreDisplay::Display::SetAutoBrightnessIsEnabled&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bool&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
void CoreDisplay::EDRDisplay::ScheduleSetBrightnessIn&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;double&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;_block_invoke
ScheduleSetBrightnessIn_block_invoke
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ve got function signatures! This was &lt;em&gt;easy&lt;/em&gt;, no need for breaking out heavier tools and methods.&lt;/p&gt;

&lt;p&gt;Inspecting futher, it seems like we’ve got a few functions that are relevant to the problem at hand:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Display&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetUserBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Display&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetLinearBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Display&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetLinearBacklightBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Display&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetBacklightBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay_Display_SetDynamicLinearBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGDirectDisplayID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay_Display_SetDynamicLinearBrightness_Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGDirectDisplayID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Skip&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SetLinearBrightness&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offline&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;display&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;08&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Display&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetDynamicLinearBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;SetDynamicLinearBrightness&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay_Display_SetLinearBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGDirectDisplayID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay_Display_SetLinearBrightness_Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGDirectDisplayID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay_Display_SetUserBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGDirectDisplayID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That last line looks pretty relevant to me, so let’s try to call that function from Python.&lt;/p&gt;

&lt;h2 id=&quot;using-ctypes-to-call-coredisplays-private-api&quot;&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctypes&lt;/code&gt; to Call CoreDisplay’s Private API&lt;/h2&gt;

&lt;p&gt;Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctypes&lt;/code&gt; gives us a convenient foreign function interface. Here’s how we’d use it for our problem:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CDLL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c_int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c_double&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CDLL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/System/Library/Frameworks/CoreDisplay.framework/CoreDisplay&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we’ve got a handle on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDisplay&lt;/code&gt; through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctypes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctypes&lt;/code&gt; needs to know how to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDisplay_Display_SetUserBrightness&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CoreDisplay_Display_SetUserBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argtypes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c_double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s test it out:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;CoreDisplay_Display_SetUserBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yes! This successfully changes the brightness on display &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; to 50%!&lt;/p&gt;

&lt;p&gt;Finally, we’ll wrap it in a function so that we can easily call it elsewhere from Python :&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_brightness_coredisplay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CoreDisplay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;CoreDisplay_Display_SetUserBrightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;We’ve learned how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyObjc&lt;/code&gt; and BundleSupport files to wrap macOS libraries that aren’t conveniently wrapped for us. We poked around undocumented libraries to locate functionality we’re interested in, and we’ve also learned how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctypes&lt;/code&gt; to call out to those private macOS frameworks.&lt;/p&gt;

&lt;p&gt;Apparently, we’ve also learned that there’s no limit to the amount of hoops I’ll jump through to make inconsequential things work.&lt;/p&gt;

&lt;p&gt;In conclusion, we built the foundation for my &lt;a href=&quot;https://github.com/thismachinechills/brightness&quot;&gt;daemon that uses facial recognition to manipulate your screen’s brightness&lt;/a&gt;. You should check it out!&lt;/p&gt;
</description>
        <pubDate>Thu, 16 Aug 2018 18:00:00 +0000</pubDate>
        <link>https://alexdelorenzo.dev/programming/2018/08/16/reverse_engineering_private_apple_apis.html</link>
        <guid isPermaLink="true">https://alexdelorenzo.dev/programming/2018/08/16/reverse_engineering_private_apple_apis.html</guid>
        
        
        <category>programming</category>
        
      </item>
    
  </channel>
</rss>
