<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>Daniel Duan's Articles About Rust</title>
        <link>https://duan.ca/tag/rust/</link>
        <atom:link href="https://duan.ca/tag/rust/feed.xml" rel="self" type="application/rss+xml" />
            <item>
                <title>StreamLogger</title>
                <description>&#60;p&#62;After turning off stream on &#60;a href=&#34;https://twitch.tv/daniel_duan&#34;&#62;Twitch&#60;/a&#62;, the first thing I normally do is
exporting the stream video to YouTube, so that the stream has an archive that
survives Twitch&#39;s short-ish retain policy.&#60;/p&#62;
&#60;p&#62;These videos, perhaps surprisingly, get a few views! It&#39;s not a lot by any
measures, but I&#39;m conscientious of the fact that a typical stream archive is
a multi-hour long video with no content curation, no clear schedule, and
it sometimes contains breaks. Needless to say, watching them after-the-fact
requires some (or a lot of) fast-forwarding.&#60;/p&#62;
&#60;p&#62;So, last week &#60;a href=&#34;https://twitch.tv/daniel_duan&#34;&#62;on stream&#60;/a&#62;, I set out to improve the fast-forwarding
experience. YouTube has this feature that lets you jump to specific timestamp
in the video through a URL parameter in the video&#39; link. Further, they generate
this parameter for text in video&#39;s description, if the text is in the right
format. This is handy for generating a &#38;quot;table of content&#38;quot; for the video so that
viewers can click the timestamp in the description to jump to the section they
are most interested in.&#60;/p&#62;
&#60;p&#62;&#60;a href=&#34;https://github.com/dduan/StreamLogger&#34;&#62;StreamLogger&#60;/a&#62; is a little utility that lets me note down what happened while
I&#39;m streaming. It&#39;s kind of like writing a commit message, except the message
describes what happened since the last &#38;quot;commit&#38;quot;. These messages, along with
their associated timestamps, will be used by StreamLogger to generate the &#38;quot;table
of content&#38;quot;. Using it in command line looks like this:&#60;/p&#62;
&#60;pre&#62;&#60;code class=&#34;language-bash&#34;&#62;# Turn on stream, maybe check signs of being live, etc. Then
slog start # start a new log

# Do stuff, when it comes to a natural conclusion point...
slog -- &#39;I did stuff&#39;

# Do more stuff...
slog -- &#39;some other stuff&#39;

# Some time later... end stream
# No action is required to end the stream as far as StreamLogger is concerned.

# Now, to generate the table-of-content
slog stamp -s 1:32
&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;That last command outputs&#60;/p&#62;
&#60;pre&#62;&#60;code&#62;0:01:32 I did stuff
1:41:59 some other stuff
&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;... which goes to the video&#39;s description.&#60;/p&#62;
&#60;p&#62;There&#39;s a few subtleties in this overall simple tool.&#60;/p&#62;
&#60;p&#62;Whenever a message is added, it gets associated with the time at which the
&#60;em&#62;previous&#60;/em&#62; message was add. So the act of logging marks both the end of
a chapter and the beginning of the next.&#60;/p&#62;
&#60;p&#62;In reality, there&#39;s always going to be a gap between the start of the stream and
the time the log is initialized. That&#39;s what the &#60;code&#62;-s 1:32&#60;/code&#62; in the last command
is trying to correct. It tells StreamLogger the length of the gap. Now the
absolute time associated with each event has a relationship with the archive
video.&#60;/p&#62;
&#60;hr /&#62;
&#60;p&#62;I chose to write this in Rust because I&#39;m going to need the final product on
Linux, macOS, and Windows since I stream on all 3 platforms. (fun fact: I never
built it directly on my PC running Linux. Instead, I simply downloaded the
musl-based build from the GitHub release, which was built by GitHub Actions. It
works beautifully.) Maybe one day I&#39;ll add a GUI for it that works across these
platforms, too, so that it&#39;s more friendly to wider group of users.&#60;/p&#62;
&#60;hr /&#62;
&#60;p&#62;The more I use and think about StreamLogger, the more I like it. You can see
me working its entirety in the following archives ;)&#60;/p&#62;
&#60;p&#62;Part 1: https://youtu.be/xWRcdaEjir4
Part 2: https://youtu.be/RS-ZMBzu9Dg&#60;/p&#62;
</description>
                <pubDate>Sat, 13 Jun 2020 12:36:55 -0700</pubDate>
                <link>https://duan.ca/2020/06/13/stream-logger/</link>
                <guid isPermaLink="true">https://duan.ca/2020/06/13/stream-logger/</guid>
            </item>
            <item>
                <title>Naive NixOS Rust Development</title>
                <description>&#60;p&#62;tl;dr: To work on Rust project with nix-shell, rls and extensions such as
&#60;code&#62;rust-analysis&#60;/code&#62;, &#60;code&#62;rust-src&#60;/code&#62;, without caring too much about specific Rust
toolchain version (except for it being &#60;code&#62;stable&#60;/code&#62;), use the following &#60;code&#62;shell.nix&#60;/code&#62;:&#60;/p&#62;
&#60;pre&#62;&#60;code class=&#34;language-nix&#34;&#62;let
  moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
  nixpkgs = import &#38;lt;nixpkgs&#38;gt; {
    overlays = [ moz_overlay ];
  };
  ruststable = (nixpkgs.latest.rustChannels.stable.rust.override {
    extensions = [ &#38;quot;rust-src&#38;quot; &#38;quot;rust-analysis&#38;quot; ];}
  );
in
  with nixpkgs;
  stdenv.mkDerivation {
    name = &#38;quot;rust&#38;quot;;
    buildInputs = [ rustup ruststable ];
  }
&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;When you have a Nix hammer, everything looks like a Nix expression.&#60;/p&#62;
&#60;p&#62;Having used NixOS on a real PC for a number of days, this is the impression
I get from the world of Nix. Unfortunately, so far, it&#39;s been a negative for me.&#60;/p&#62;
&#60;p&#62;One of the most exciting thing I want to use Nix for is to bootstrap development
environment with &#60;code&#62;nix-shell&#60;/code&#62;. I imagined it to be similar to using &#60;a href=&#34;https://pipenv-fork.readthedocs.io/en/latest/&#34;&#62;pipenv&#60;/a&#62;
with Python, except for everything. Well, I&#39;ve since learned that it&#39;s not true
(yet?) for many reasons.&#60;/p&#62;
&#60;p&#62;Modern programming languages come with their own attempt at &#60;em&#62;reproducibility&#60;/em&#62;.
Some does it better than others. To make it concrete, I&#39;m talking about things
like &#60;a href=&#34;https://haskellstack.org&#34;&#62;Stack&#60;/a&#62; for Haskell or &#60;a href=&#34;https://rustup.rs/&#34;&#62;rustup&#60;/a&#62; for Rust: given the source code, how do
I make it build in the way the project intended? What&#39;s the correct version of
the compiler, runtime, and tools that works best with this revision of the
source code? The common solution usually follows this pattern: as author of
a project, specify as much as you can, the environment best suited for the
current state of the project. As a &#38;quot;builder&#38;quot;, use a &#60;em&#62;single program&#60;/em&#62; that&#39;s
capable of updating itself, as well as ensuring that the project builds exactly
as specified, including managing the compiler/runtime/tooling versions, etc.&#60;/p&#62;
&#60;p&#62;This &#60;em&#62;single program&#60;/em&#62;&#39;s role is very much the same as the Nix system, except the
latter is independent of programming languages: &#60;code&#62;rustup&#60;/code&#62; installs Rust, so does
Nix. That&#39;s a bad thing. As a package manager, Nix either have to tightly
integrate with each of these other package managers, leveraging their evolving
behaviors to give its user the build environment; or, it must replace them.
The former is impractical; the latter, well, sucks.&#60;/p&#62;
&#60;p&#62;Back to reality. This is the experience I want to have with NixOS: Some programs
I use daily such as Alacritty, NeoVim, Firfox, etc, are installed globally and
readily available. They are part of my &#60;code&#62;/etc/nixos/configuration.nix&#60;/code&#62;. So far so
good. Now, I regularly program in a few languages. For each of the project, I&#39;d
like to have a &#60;code&#62;shell.nix&#60;/code&#62; that brings in its compilers, libraries, LSP servers,
etc. This is what &#60;code&#62;nix-shell&#60;/code&#62; is supposed to give me! This is known as the &#38;quot;per
project&#38;quot; setup.&#60;/p&#62;
&#60;p&#62;Let&#39;s see: with Rust, that means &#60;code&#62;rustc&#60;/code&#62; (compiler), &#60;code&#62;cargo&#60;/code&#62; (package manager),
&#60;code&#62;rls&#60;/code&#62;, &#60;code&#62;rust-src&#60;/code&#62; and &#60;code&#62;rust-analysis&#60;/code&#62; (LSP). In macOS, I&#39;d install all of these
globally with &#60;code&#62;rustup&#60;/code&#62;. In NixOS...well, I can ask for &#60;code&#62;rustup&#60;/code&#62; for my project:&#60;/p&#62;
&#60;pre&#62;&#60;code class=&#34;language-nix&#34;&#62;with import &#38;lt;nixpkgs&#38;gt; {};

stdenv.mkDerivation {
  name = &#38;quot;rust&#38;quot;;
  nativeBuildInputs = [ rustup ];
}
&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;...which gives me &#60;code&#62;rustup&#60;/code&#62; and nothing else. That&#39;s right, you don&#39;t even get
a &#60;code&#62;rustc&#60;/code&#62; after running &#60;code&#62;nix-shell&#60;/code&#62;. But &#60;code&#62;rustup&#60;/code&#62; can get you everything else,
all I need to do is ask. Hmm, do I need to run a series of set-up commands with
&#60;code&#62;rustup&#60;/code&#62; every time I enter the environment? No? I just need to run it the first
time? Until the cached tools get deleted by some garbage collection mechanism?
That seems unsatisfying, doesn&#39;t it?&#60;/p&#62;
&#60;p&#62;Instead of &#60;code&#62;rustup&#60;/code&#62;, I could also ask Nix to use the &#60;code&#62;rustc&#60;/code&#62;/&#60;code&#62;cargo&#60;/code&#62;/&#60;code&#62;rls&#60;/code&#62; it
knows about directly. This is marginally better. Except I still need &#60;code&#62;rust-src&#60;/code&#62;
and &#60;code&#62;rust-analysis&#60;/code&#62; for my needs. As far as I can tell, these &#60;a href=&#34;https://github.com/rust-lang/rls&#34;&#62;RLS&#60;/a&#62; components
are out of Nix&#39;s control (as of today).&#60;/p&#62;
&#60;p&#62;Everywhere on the internet I looked, for every problem that
Nix-the-package-manager doesn&#39;t work out-of-the-box, there&#39;s someone responding
along the line of &#38;quot;you can write some Nix expression yourself&#38;quot;. In other words,
Nix-the-language is powerful enough to solve it, probably. In the case of Rust,
luckily, Mozilla wrote enough Nix expressions for us and provides them via an
&#60;a href=&#34;https://github.com/mozilla/nixpkgs-mozilla&#34;&#62;overlay&#60;/a&#62;. These expressions are rich enough to meet my needs.
As you can see in the tl;dr at the top, when entering the development
environment, nix-shell would: download the overlay&#39;s source code (from the
internet, or local cache), load the expression it includes, mix in my
customization, and execute it.&#60;/p&#62;
&#60;p&#62;That marks the end of my search. I like the final solution because it&#39;s mostly
&#38;quot;vanilla&#38;quot; Nix and doesn&#39;t require me to mess with a bunch of other tools. For
solutions that do, read &#60;a href=&#34;https://xeiaso.net/blog/how-i-start-nix-2020-03-08/&#34;&#62;this&#60;/a&#62;.&#60;/p&#62;
&#60;hr /&#62;
&#60;p&#62;At end of the day, my needs are pretty basic: consistency from rustup and
convenience from nix-shell. I didn&#39;t need to pin the compiler to a specific Rust
release, or checksum the final build output.&#60;/p&#62;
&#60;p&#62;I&#39;m very new to both technologies so there may be a follow-up post sometime in
the future.&#60;/p&#62;
</description>
                <pubDate>Thu, 07 May 2020 11:04:58 -0700</pubDate>
                <link>https://duan.ca/2020/05/07/nix-rust-development/</link>
                <guid isPermaLink="true">https://duan.ca/2020/05/07/nix-rust-development/</guid>
            </item>
            <item>
                <title>Site Improvements 2020</title>
                <description>&#60;p&#62;I took back my website.&#60;/p&#62;
&#60;p&#62;I took it back from the claws of Jekyll and Ruby. I took it back from some
random template among a few that were immediately available. I took it back
from my own ignorance of modern web technology.&#60;/p&#62;
&#60;p&#62;This time, I rewrote the hole effing thing from scratch.&#60;/p&#62;
&#60;h3&#62;The Why&#60;/h3&#62;
&#60;p&#62;The &#60;a href=&#34;/2017/01/16/site-changes/&#34;&#62;last time&#60;/a&#62; I ended with&#60;/p&#62;
&#60;blockquote&#62;
&#60;p&#62;I wrote the most Ruby in my life today. Yay?&#60;/p&#62;
&#60;/blockquote&#62;
&#60;p&#62;That question mark turned out to be prescient. Ruby is not my thing. No
judgement against the language per ce. But the Ruby ecosystem is not friendly to
a casual user who needs it once every few months. No really, when I write an
article, it&#39;s a toss-up whether I can deploy it without being forced to mess
with Ruby/Gems/Jekyll/Homebrew etc. I&#39;m almost certain there&#39;s a set of best
practices I could learn to improve this. But it&#39;d be a skill that I barely need
and probably forget a few times. Meanwhile I just want to translate a new
Markdown file to HTML and put it on Github.&#60;/p&#62;
&#60;p&#62;As a teen, one of my favorite things about the web is how accessible it is.
I could sit in front of anyone&#39;s computer, open Notepad.exe and type in some
tags, and open the file with a browser to see the result. That simple bootstrap
process, however repetitive, never got old for me.&#60;/p&#62;
&#60;p&#62;In the last decade, my professional work is focused on native, mobile
applications. This experience biased me in a few ways. &#38;quot;Native&#38;quot; made me
appreciate the closeness to &#38;quot;the metal&#38;quot;: you have an OS; you get the executable;
you launch strace, and boom, everything the OS thinks what your code does is
revealed to you. &#38;quot;Mobile&#38;quot; forced me to reckon with the reality: desktop
experience has become a niche. It&#39;s nowhere near as important as it was prior to
the iPhone. Not making your software run well on mobile devices is a particular
kind of choice that come with some severe trade-offs.&#60;/p&#62;
&#60;p&#62;And, finally, I subscribe to the idea that &#60;em&#62;plain text is supreme&#60;/em&#62;. Yes, even
more supreme than the web. This website is a derivative of the articles I write
in Markdown. Plain text as a format will out-last the web in the long run (not
necessarily &#60;em&#62;these&#60;/em&#62; texts). So it really bothers me when I have to put &#38;quot;front
matter&#38;quot; in YAML/TOML/whatever in front of the real Markdown. Yes, if you want
reasonable HTMLs, these metadata is necessary. But the text is &#60;em&#62;Supreme&#60;/em&#62;. The
text is to be readable directly. Succumbing the supreme to the derivative is
&#60;em&#62;wrong&#60;/em&#62;.&#60;/p&#62;
&#60;p&#62;Okay, so where does all that leave me? In this iteration of this website,
I wrote every single line of CSS and HTML (there&#39;s barely any JavaScript) which
look decent on mobile. It&#39;s generated by portable Linux and Darwin executables
that are part of the website. As long as the OSes stay relatively stable, the
site will build without any dependencies, in a matter of milliseconds. The best
part?  It&#39;ll stay like this unless I wish it otherwise.&#60;/p&#62;
&#60;h3&#62;The Frontend&#60;/h3&#62;
&#60;p&#62;A few words on the design of the site.&#60;/p&#62;
&#60;p&#62;This site gained the concept of &#38;quot;links&#38;quot; the &#60;a href=&#34;/2017/01/16/site-changes/&#34;&#62;last time&#60;/a&#62;. It has since become
clear that I don&#39;t use this feature (blame Twitter). It&#39;s gone, for now. The old
&#38;quot;about&#38;quot; page is replaced by the home page.&#60;/p&#62;
&#60;p&#62;When I decided the site needed a rewrite, I fantasized a place with only HTML.
Perhaps users who want a better reading experience can simply put it in Reader
mode. Alas, if browsers (with the exception of Safari) implemented automatic
dark mode with a &#60;a href=&#34;https://drafts.csswg.org/css-color-adjust-1/#color-scheme-meta&#34;&#62;color-scheme meta&#60;/a&#62; tag, it&#39;d almost be a working idea.&#60;/p&#62;
&#60;p&#62;So, that&#39;s my starting point.&#60;/p&#62;
&#60;p&#62;The site is a list of articles organized by tags and dates, and a few web pages.
&#60;em&#62;I want you to read the site, not navigate it&#60;/em&#62;. So text is the point. It&#39;s the
only design element. The site uses 2 fonts and 2 text-color (not counting
highlighted code). Links are always underscored (because you can&#39;t hover in
mobile browsers to find something clickable).&#60;/p&#62;
&#60;p&#62;The site is responsive to mobile layout, and dark mode. It&#39;s aware that it could
be added to the home screen of a mobile device, or linked to some external site
that wants to generate a preview.&#60;/p&#62;
&#60;p&#62;I did end up using &#60;a href=&#34;https://ethanschoonover.com/solarized/&#34;&#62;solarized&#60;/a&#62; theme for code highlighting, which lead to 2
static CSS files. Other than that, all CSS and HTML are hand-written. There&#39;s no
build step for them, farm to table, Vim to your browser.&#60;/p&#62;
&#60;p&#62;It turned out standardized CSS variable is game-changing. Combined with media
queries, I barely needed any class to support dark mode/mobile layout. More
importantly, it makes my programmer brain happy. Oh, yes I&#39;m talking about them
here because this is the first time I truly attempted to catch up since they
were introduced to the world. It&#39;s freeing to let go of constrains of an
read-to-use theme, or some CSS frameworks.&#60;/p&#62;
&#60;h3&#62;The Backend&#60;/h3&#62;
&#60;p&#62;This site is a collection of static files. The so-called backend is a program
that assembles these files from some HTML templates and Markdown files. In the
past, this program had been &#60;a href=&#34;https://jekyllrb.com/&#34;&#62;Jekyll&#60;/a&#62;. This time around, I replaced it with
some Rust code.&#60;/p&#62;
&#60;p&#62;Boy, this thing is cool, if I say so myself. I&#39;m going to refer to it as &#38;quot;the
generator&#38;quot;.&#60;/p&#62;
&#60;p&#62;The biggest &#38;quot;feature&#38;quot; is the fact that it doesn&#39;t pretend to be re-usable.
The generator is as part of this site as the articles.&#60;/p&#62;
&#60;p&#62;Thanks to Rust, the programs are built into executable binaries. On macOS, it
requires libSystem to run. On Linux, I can (and prefer) build with &#60;a href=&#34;https://www.musl-libc.org/&#34;&#62;musl&#60;/a&#62;. The
binaries for these two OSes are checked in with the content of the site. So
it requires zero installation to &#38;quot;build&#38;quot; the site. (I may need to
include a 3rd executable for the upcoming ARM-based Macs soon).&#60;/p&#62;
&#60;p&#62;The generator spits out the final content of the website. It&#39;s deployed without
further modification.&#60;/p&#62;
&#60;p&#62;The build process is pretty fast. As of this writing, it averages around 250 ms.
I could probably make it faster by avoiding some repeated reads when it comes to
article inputs.&#60;/p&#62;
&#60;p&#62;The generator handles HTML/XML templating with a library named &#60;a href=&#34;https://github.com/djc/askama&#34;&#62;Askama&#60;/a&#62;.
Learning it had been an eye opening experience. Askama is built atop Rust&#39;s
macro system. For each template (e.g. web page), it requires users to write
a Rust data structure that fulfills its variable requirements.  Here&#39;s the
kicker: in this data structure, you &#60;em&#62;cannot&#60;/em&#62; miss any variable the corresponding
template requires.  When you do, the Rust project won&#39;t compile! Rust&#39;s tooling
is so good that these errors were surfaced in my editor as I wrote this part
in real time. This level of type-safety for template language felt like magic.&#60;/p&#62;
&#60;p&#62;Syntax highlighting is powered by &#60;a href=&#34;https://github.com/trishume/syntect&#34;&#62;syntect&#60;/a&#62;, the library behind &#60;a href=&#34;https://github.com/sharkdp/bat&#34;&#62;bat&#60;/a&#62;. But
the interesting bit here is how the syntax definitions are embedded within the
final executable. To support a particular syntax, syntect takes the syntax&#39;s
SublimeText definition. So this is a configurable, extendible system. The
generator includes 118 syntax definitions. Uncompressed, their files take up 5MB
of disk space. As one can imagine, loading 5MB from 118 files each time the
program runs is quite slow. Turns out, Rust has a standard library macro
&#60;a href=&#34;https://doc.rust-lang.org/std/macro.include_bytes.html&#34;&#62;include_bytes!&#60;/a&#62; that solves this problem. &#60;a href=&#34;https://doc.rust-lang.org/std/macro.include_bytes.html&#34;&#62;include_bytes!&#60;/a&#62; embeds
contents of a file as literals in source code, as if it&#39;s hand-written. syntect
takes advantage of this feature by supporting serialization of its in-memory
representation of syntaxes into bytes, and accepting in-line byte literals in
reverse in order to create these representations. This system solves two
problems for me:&#60;/p&#62;
&#60;ol&#62;
&#60;li&#62;I no longer need to ship the SublimeText syntax files along with the
generator.&#60;/li&#62;
&#60;li&#62;The generator doesn&#39;t need to perform all that disk I/O, so it runs
significantly faster.&#60;/li&#62;
&#60;/ol&#62;
&#60;p&#62;Overall, the Rust ecosystem delivered. Although a lot of library are still in
rough shape/early stage, there usually are multiple alternatives for roughly the
same purpose. Gluing a few of them together for this generator project had been
fun.&#60;/p&#62;
&#60;p&#62;Finally, let&#39;s talk metadata, I can&#39;t realistically manage to generate the site
without them.  Articles and static pages each define their URL by their file
locations relative to the root. For example, &#60;code&#62;/articles/2020/04/23/hello.md&#60;/code&#62;
means the URL is &#60;code&#62;/2020/04/23/hello/&#60;/code&#62;. Each article still has a front matter.
But I made the text version look as &#38;quot;natural&#38;quot; as possible. There&#39;s no markers
for beginning and end of the metadata since I know exactly what&#39;s needed. The
title is marked as an H1. Date is in RFC3339 format. Tags are comma-separated
values. So an example of an article&#39;s beginning looks like:&#60;/p&#62;
&#60;pre&#62;&#60;code class=&#34;language-markdown&#34;&#62;# Site Improvements 2020
2020-04-22T21:58:03-07:00
tags: Rust, HTML, CSS, Ruby, Jekyll, Markdown

I took back my website...
&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;Text supremacy! Glory!&#60;/p&#62;
&#60;h3&#62;Onward&#60;/h3&#62;
&#60;p&#62;Over the course of roughly 15 years, I&#39;ve had blogs of quite a few variates.
I wish I&#39;d done a better job archiving them as I moved on from one to the next.
This is not the first time I attempted to gain full control over the theming,
generating, hosting, and deployment of a site. But I&#39;m hopeful that it&#39;ll last
longer. You could say that&#39;s what I optimized for. And who knew, maybe my
experience from past failures counts for something.&#60;/p&#62;
&#60;p&#62;Here&#39;s to less stressful deploys and more writing!&#60;/p&#62;
</description>
                <pubDate>Wed, 22 Apr 2020 21:58:03 -0700</pubDate>
                <link>https://duan.ca/2020/04/22/site-improvements-2020/</link>
                <guid isPermaLink="true">https://duan.ca/2020/04/22/site-improvements-2020/</guid>
            </item>
    </channel>
</rss>