<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://danapplegate.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://danapplegate.com/" rel="alternate" type="text/html" /><updated>2026-04-11T23:07:21+00:00</updated><id>https://danapplegate.com/feed.xml</id><title type="html">Dan Applegate</title><subtitle>Software Engineer</subtitle><entry><title type="html">Realmz - Reviving a Classic Macintosh Game</title><link href="https://danapplegate.com/projects/2025/11/24/reviving-realmz.html" rel="alternate" type="text/html" title="Realmz - Reviving a Classic Macintosh Game" /><published>2025-11-24T00:00:00+00:00</published><updated>2025-11-24T00:00:00+00:00</updated><id>https://danapplegate.com/projects/2025/11/24/reviving-realmz</id><content type="html" xml:base="https://danapplegate.com/projects/2025/11/24/reviving-realmz.html"><![CDATA[<p><a id="github-repo-link" class="icon" href="https://github.com/Realmz-Castle/realmz" target="_blank"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 28" height="24" width="28"><path d="M12 2c6.625 0 12 5.375 12 12 0 5.297-3.437 9.797-8.203 11.391-0.609 0.109-0.828-0.266-0.828-0.578 0-0.391 0.016-1.687 0.016-3.297 0-1.125-0.375-1.844-0.812-2.219 2.672-0.297 5.484-1.313 5.484-5.922 0-1.313-0.469-2.375-1.234-3.219 0.125-0.313 0.531-1.531-0.125-3.187-1-0.313-3.297 1.234-3.297 1.234-0.953-0.266-1.984-0.406-3-0.406s-2.047 0.141-3 0.406c0 0-2.297-1.547-3.297-1.234-0.656 1.656-0.25 2.875-0.125 3.187-0.766 0.844-1.234 1.906-1.234 3.219 0 4.594 2.797 5.625 5.469 5.922-0.344 0.313-0.656 0.844-0.766 1.609-0.688 0.313-2.438 0.844-3.484-1-0.656-1.141-1.844-1.234-1.844-1.234-1.172-0.016-0.078 0.734-0.078 0.734 0.781 0.359 1.328 1.75 1.328 1.75 0.703 2.141 4.047 1.422 4.047 1.422 0 1 0.016 1.937 0.016 2.234 0 0.313-0.219 0.688-0.828 0.578-4.766-1.594-8.203-6.094-8.203-11.391 0-6.625 5.375-12 12-12zM4.547 19.234c0.031-0.063-0.016-0.141-0.109-0.187-0.094-0.031-0.172-0.016-0.203 0.031-0.031 0.063 0.016 0.141 0.109 0.187 0.078 0.047 0.172 0.031 0.203-0.031zM5.031 19.766c0.063-0.047 0.047-0.156-0.031-0.25-0.078-0.078-0.187-0.109-0.25-0.047-0.063 0.047-0.047 0.156 0.031 0.25 0.078 0.078 0.187 0.109 0.25 0.047zM5.5 20.469c0.078-0.063 0.078-0.187 0-0.297-0.063-0.109-0.187-0.156-0.266-0.094-0.078 0.047-0.078 0.172 0 0.281s0.203 0.156 0.266 0.109zM6.156 21.125c0.063-0.063 0.031-0.203-0.063-0.297-0.109-0.109-0.25-0.125-0.313-0.047-0.078 0.063-0.047 0.203 0.063 0.297 0.109 0.109 0.25 0.125 0.313 0.047zM7.047 21.516c0.031-0.094-0.063-0.203-0.203-0.25-0.125-0.031-0.266 0.016-0.297 0.109s0.063 0.203 0.203 0.234c0.125 0.047 0.266 0 0.297-0.094zM8.031 21.594c0-0.109-0.125-0.187-0.266-0.172-0.141 0-0.25 0.078-0.25 0.172 0 0.109 0.109 0.187 0.266 0.172 0.141 0 0.25-0.078 0.25-0.172zM8.937 21.438c-0.016-0.094-0.141-0.156-0.281-0.141-0.141 0.031-0.234 0.125-0.219 0.234 0.016 0.094 0.141 0.156 0.281 0.125s0.234-0.125 0.219-0.219z"></path>
</svg>
 Project on Github</a></p>

<blockquote>
  <p>Not only was a piece of computer gaming history fading into obscurity, like the countless silent movies lost forever
when their film disintegrated, but a cherished part of my childhood was becoming no more than a memory and a cultural
anecdote. I decided to try to do something.</p>
</blockquote>

<p>When I was about 7, one of my favorite things to do was watch my dad play <a href="https://en.wikipedia.org/wiki/Realmz" title="Realmz Wikipedia page">Realmz</a>. Compared to the computer games I was
playing at the time, such as <a href="https://en.wikipedia.org/wiki/SimCity_(1989_video_game)" title="SimCity Wikipedia page">SimCity</a> and <a href="https://en.wikipedia.org/wiki/Lemmings_(video_game)" title="Lemmings Wikipedia page">Lemmings</a>, Realmz stood apart as a portal into an expansive world of
adventure. Like many games of the era, it was released as shareware, with a restricted, free-to-play base game that
could be unlocked and additional content purchased by mailing in registration fees. But unlike others, Fantasoft offered
companion scenario and character editors, which allowed users to create their own content. Watching my dad roam around
fantastical worlds with a band of powerful adventurers wielding magical weapons, and imagining the awesome items and
stories I could create myself, was a key inspiration to me to become a programmer.</p>

<figure>
  <img src="/assets/img/Realmzscreenshot.gif" alt="Screenshot of Realmz" />
  <figcaption>Screenshot of Realmz, from <a href="https://en.wikipedia.org/wiki/File:Realmzscreenshot.gif" target="_blank">Wikipedia</a></figcaption>
</figure>

<p>Recently, a wave of nostalgia hit me, and I went digging into what it might take to fire up Realmz again. Visiting the
disappearing or aging <a href="https://web.archive.org/web/20220520045443/http://rlmz.org/" title="Archive of rlmz.org, last semi-official site">websites</a> that were keeping the game alive confirmed my fears: Realmz was getting more and more
difficult to play. The game had long since become <a href="https://en.wikipedia.org/wiki/Abandonware" title="Wikipedia page for Abandonware">abandonware</a>, no one seemed to have heard from the creator Tim
Phillips nor the apparent custodian <a href="https://gamefaqs.gamespot.com/boards/564322-realmz/58236425" title="GameSpot forum thread mentioning Skip">Skip Meier</a> in years, and aside from a buggy 1999 Windows port and a now-obsolete
<a href="https://en.wikipedia.org/wiki/Carbon_(API)" title="Wikipedia page for Carbon (API)">Carbon</a>-ization project from the 2010s, very little had been done to keep the game playable. It seemed that the only
options were to try to get the Windows executable working and play through the bugs, set up one of the notoriously
tricky Macintosh emulators like Sheepsaver or Basilisk, or simply dust off any old Macintosh that one might happen to
have lying around in storage.</p>

<p>I found this incredibly sad. Not only was a piece of computer gaming history fading into obscurity, like the countless
silent movies lost forever when their film disintegrated, but a cherished part of my childhood was becoming no more than
a memory and a cultural anecdote. I decided to try to do something.</p>

<p>The ultimate way to ensure a piece of software can survive is to open source its code. Although I had no idea how to
begin, I made my primary goal to open source Realmz so that, even if I were to fail to keep it updated for modern
systems, other enthusiasts might be able to continue the work and eventually succeed. The major obstacle to this goal
was that no one seemed to know who currently holds the rights to Realmz, and the two most likely people, Tim and Skip,
seemed to have vanished from the internet.</p>

<p>After weeks of research, cold reachouts, consultations with an open source lawyer, and wild geese, I managed to contact
Tim. He graciously agreed to release the Realmz source code under a <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" title="CC-BY-NA-SA License">CC NonCommercial license</a>, and I obtained a copy of
the codebase from the programmer who worked on the Carbon port years ago. The hardest, most uncertain part of the
project was complete!</p>

<p>Now that I had access to the codebase and permission from the original author, I got to work. My plan was to first
simply get the code to compile, even if it crashed immediately upon startup. From an interview with one of the original
members of Fantasoft, I knew to expect C code written under the c89 standard, so I hoped that it would be mostly
compilable, as long as I could stub out the missing Macintosh System 7 system calls. From there, I figured I could
re-implement the system calls that were still necessary for the game to run. Others, such as those that took care to
lock and unlock moveable and purgeable <a href="https://en.wikipedia.org/wiki/Classic_Mac_OS_memory_management" title="Classic Mac OS memory management on Wikipedia">memory handles</a>, could be left unimplemented and would be elided by the
compiler.</p>

<p>This process turned out to be relatively straightforward, if labor-intensive. I would attempt to compile, then look for
the missing function symbol in the resulting error. I would then reference an <a href="https://archive.org/details/inside-macintosh-1992-1994/1992-files/" title="Archive of Inside Macintosh">archived copy</a> of <a href="https://en.wikipedia.org/wiki/Inside_Macintosh" title="Inside Macintosh Wikipedia page">Inside Macintosh</a> to
find out the signature of the missing function<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. Finally, I would write a declaration and an empty definition of the
missing function, recompile, and repeat. Aside from a few minor snags<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>, the process went well, and I soon had a
compiled executable which crashed as soon as it launched!</p>

<p>One of the earliest sources of crashes was, predictably, the <code class="language-plaintext highlighter-rouge">NULL</code> pointers returned by my stubbed versions of
<a href="https://archive.org/details/inside-macintosh-1992-1994/1992-macintosh_toolbox_essentials/page/n425/mode/1up" title="Inside Macintosh, Macintosh Toolbox Essentials, p. 4-78 on archive.org">functions like <code class="language-plaintext highlighter-rouge">GetNewWindow</code></a>. <code class="language-plaintext highlighter-rouge">GetNewWindow</code>, like many of the missing system calls, loads a game asset, in this case
a <code class="language-plaintext highlighter-rouge">WIND</code> resource representing an application window definition, then draws it to the screen. “Resources” are what early
Macintosh called application data such as images, text that could be localized, sound files, or any other data that the
application might use. Historically they were stored in <a href="https://en.wikipedia.org/wiki/Resource_fork" title="Wikipedia page on Classic Mac resource forks">resource forks</a>, an archival format that was hidden within each
file, but in the repository that I gained access to, the resource forks had already been extracted into separate files,
making them a little easier to deal with.</p>

<p>My plan for rendering windows and graphics, playing sounds, and receiving inputs was to simply write an adapter layer to
SDL3 calls, essentially implementing replacement <a href="https://archive.org/details/inside-macintosh-1992-1994/1992-overview/page/109/mode/1up&quot;" title="Inside Macintosh, Overview, p. 109 on archive.org">Window Manager</a>, <a href="https://archive.org/details/inside-macintosh-1992-1994/1992-overview/page/85/mode/1up" title="Inside Macintosh, Overview, p. 85">QuickDraw</a>, etc. functionality while leaving the
existing API and the callsites in Realmz intact. The harder part would be to write the code to parse and extract the
individual resources from the resource fork files. Each resource type has its own storage format, and while there didn’t
seem to be anything too difficult involved in unpacking each field, I wasn’t looking forward to the slog of implementing
each extractor (and decoder of compressed formats, in the case of certain resources). I started looking around for any
existing tools or libraries that I could use.</p>

<figure>
  <img src="/assets/img/inside_macintosh_resource_example.png" alt="Example of resource storage" />
  <figcaption>An example diagram of resource storage, the PICT resource, from <a href="https://archive.org/details/inside-macintosh-1992-1994/1994-imaging_with_quickdraw/page/n561/mode/1up" target="_blank">Inside Macintosh, Imaging with Quickdraw p. 7-68</a></figcaption>
</figure>

<p>My search led me to the excellent <a href="https://github.com/fuzziqersoftware/resource_dasm" title="The resource_dasm project on Github">resource_dasm</a> tool and library, authored by <a href="https://github.com/fuzziqersoftware" title="Github profile of Martin Michelsen">fuzziqersoftware</a>. Not only had Martin
implemented a tool that unpacks and converts each resource type to a modern equivalent, but the library is written in
C++ and I had high hopes that I could integrate it directly into my project to handle all resource file manipulations. I
quickly got bare-bones implementations of Window Manager and Resource Manager working, calling into resource_dasm to
load the image data, and calling into SDL3 for window creation and rendering, and was greeted by a friendly image from
my past:</p>

<figure>
  <img src="/assets/img/realmz_title_page.png" alt="The Realmz main screen, in a modern Macos frame, rendered using SDL3" />
  <figcaption>The Realmz main screen, in a modern Macos frame, rendered using SDL3</figcaption>
</figure>

<p>Encouraged by reaching this huge milestone so quickly, I decided to reach out to Martin to see if he was interested in
joining the project. His depth of expertise would mean that together we’d be able to get the game running smoothly much
sooner than I could by continuing on my own, stumbling forward without much experience on this ancient system.
Thankfully, he quickly agreed, and we set ourselves to the task of implementing the rest of the missing Classic Mac
functionality. It took us a while to work through all of the crashes and unimplemented behavior, since we could only
spare an hour of our free time here or there, but we were able to overcome some interesting problems<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> and achieved a
smooth, crash-free experience that allows one to play through entire scenarios successfully.</p>

<p>And so, today, I’m thrilled to announce the first public (beta) release of the Realmz Classic project! I’ll be forever
grateful to Tim Phillips for entrusting me with this work and his desire to see the Realmz community continue to thrive;
to Sean Sayrs for responding to me and helping me contact Tim; to <a href="https://www.williamson.legal/team" title="Aaron Williamson profile on Williamson Legal's website">Aaron Williamson</a> for his advice on options for open
sourcing Realmz; to Dave Riley for preserving the Realmz codebase for all these years and for sharing it with me; and to
my project partner Martin Michelsen, for laying the excellent groundwork and for agreeing to lend his exceptional talent
to the project.</p>

<p>You can visit the <a href="https://github.com/Realmz-Castle/realmz/releases" title="Link to Realmz releases page on Github">releases page</a> and download an installer for either MacOS or Windows, or a zip archive for custom
Windows installations. Give it a try, and prepare to be whisked away on a strange and fantastical classic RPG adventure!</p>

<!-- prettier-ignore -->

<!-- prettier-ignore -->

<!-- prettier-ignore -->

<!-- prettier-ignore -->

<!-- prettier-ignore -->

<!-- prettier-ignore -->
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">

      <p>Although the function signatures in Inside Macintosh are primarily presented in Pascal, luckily, equivalent C
signatures for each function are usually included towards the ends of each section. When I couldn’t find the
equivalent C declaration, I had to try to convert the Pascal types to C equivalents using my best judgement. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">

      <p>One peculiarity of the early Macintosh systems was their use of <a href="https://en.wikipedia.org/wiki/String_(computer_science)#Length-prefixed" title="Length-prefixed strings on Wikipedia">Pascal-style strings</a>. Instead of c-style strings,
with a null terminator character to signify the end of the string, “p-strings” encode the length of the string in
the first byte. Several sections of the Realmz code manipulated some static string literals expecting them to be
p-strings (denoted with a <code class="language-plaintext highlighter-rouge">\p</code> special character as the first byte), so this required passing the
<a href="https://clang.llvm.org/docs/ClangCommandLineReference.html" title="Clang documentation"><code class="language-plaintext highlighter-rouge">-fpascal-strings</code> option to Clang</a>. Another snag was the liberal use of <code class="language-plaintext highlighter-rouge">long</code> and <code class="language-plaintext highlighter-rouge">short</code>, which appear to have
been defined by Realmz’ original target ABIs to be 32 and 16 bits wide, respectively, but which now are larger. This
caused some bad accesses which had to be corrected by using fixed-width integer types. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">

      <p>One of my goals for the project was to create as seamless of an experience for enthusiasts looking to import their
old character and scenario data. This meant being able to successfully load and write the data files that were
included with the base game and were thankfully intact in the repo I received. Realmz doesn’t have a data
serialization layer – the raw bytes of the data file are simply read into (or written from) the associated <code class="language-plaintext highlighter-rouge">struct</code>.
This led to some crashes and some broken behavior, revealing an interesting quirk about the original runtime
environment of Realmz. The architectures that Classic Macintoshes ran on, the <a href="https://en.wikipedia.org/wiki/Motorola_68000" title="Motorolla 68000 on Wikipedia">Motorolla 68k</a> and <a href="https://en.wikipedia.org/wiki/PowerPC" title="PowerPC on Wikipedia">PowerPC</a>, were
both <a href="https://en.wikipedia.org/wiki/Endianness" title="Endianness on Wikipedia">big-endian</a> architectures. Normally, this wouldn’t be much of an issue, as compilers building the code for
little-endian systems would consistently use little-endian order for all in-memory data. It was only when <em>reading</em>
this data, stored in the original files in big-endian order, and interpreted by the target little-endian
architecture, that the problem would reveal itself. Luckily, I found some <a href="https://github.com/Realmz-Castle/realmz/blob/35d7db746b0e7c4e973c0e372e3d118147b4d173/src/realmz_orig/convert.h" title="Link to Realmz' convert.h, which contains byte-swapping code">existing <code class="language-plaintext highlighter-rouge">struct</code>-aware byte swapping
code</a> in the repo that probably dated from the era of Windows port, and was able to repurpose it fairly easily. A
variation of the <code class="language-plaintext highlighter-rouge">long</code>/<code class="language-plaintext highlighter-rouge">int32_t</code> problem described above<sup id="fnref:2:1" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> also had to be dealt with. Thankfully, other more
complicated data problems resulting from any strange padding or alignment behavior from these old systems never
materialized. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><category term="projects" /><category term="c" /><category term="cplusplus" /><category term="gaming" /><category term="open_source" /><summary type="html"><![CDATA[Project on Github]]></summary></entry><entry><title type="html">An Astronomy Simulator in Rust</title><link href="https://danapplegate.com/projects/2023/11/04/simulator.html" rel="alternate" type="text/html" title="An Astronomy Simulator in Rust" /><published>2023-11-04T00:00:00+00:00</published><updated>2023-11-04T00:00:00+00:00</updated><id>https://danapplegate.com/projects/2023/11/04/simulator</id><content type="html" xml:base="https://danapplegate.com/projects/2023/11/04/simulator.html"><![CDATA[<p><a id="github-repo-link" class="icon" href="https://github.com/danapplegate/simulator" target="_blank"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 28" height="24" width="28"><path d="M12 2c6.625 0 12 5.375 12 12 0 5.297-3.437 9.797-8.203 11.391-0.609 0.109-0.828-0.266-0.828-0.578 0-0.391 0.016-1.687 0.016-3.297 0-1.125-0.375-1.844-0.812-2.219 2.672-0.297 5.484-1.313 5.484-5.922 0-1.313-0.469-2.375-1.234-3.219 0.125-0.313 0.531-1.531-0.125-3.187-1-0.313-3.297 1.234-3.297 1.234-0.953-0.266-1.984-0.406-3-0.406s-2.047 0.141-3 0.406c0 0-2.297-1.547-3.297-1.234-0.656 1.656-0.25 2.875-0.125 3.187-0.766 0.844-1.234 1.906-1.234 3.219 0 4.594 2.797 5.625 5.469 5.922-0.344 0.313-0.656 0.844-0.766 1.609-0.688 0.313-2.438 0.844-3.484-1-0.656-1.141-1.844-1.234-1.844-1.234-1.172-0.016-0.078 0.734-0.078 0.734 0.781 0.359 1.328 1.75 1.328 1.75 0.703 2.141 4.047 1.422 4.047 1.422 0 1 0.016 1.937 0.016 2.234 0 0.313-0.219 0.688-0.828 0.578-4.766-1.594-8.203-6.094-8.203-11.391 0-6.625 5.375-12 12-12zM4.547 19.234c0.031-0.063-0.016-0.141-0.109-0.187-0.094-0.031-0.172-0.016-0.203 0.031-0.031 0.063 0.016 0.141 0.109 0.187 0.078 0.047 0.172 0.031 0.203-0.031zM5.031 19.766c0.063-0.047 0.047-0.156-0.031-0.25-0.078-0.078-0.187-0.109-0.25-0.047-0.063 0.047-0.047 0.156 0.031 0.25 0.078 0.078 0.187 0.109 0.25 0.047zM5.5 20.469c0.078-0.063 0.078-0.187 0-0.297-0.063-0.109-0.187-0.156-0.266-0.094-0.078 0.047-0.078 0.172 0 0.281s0.203 0.156 0.266 0.109zM6.156 21.125c0.063-0.063 0.031-0.203-0.063-0.297-0.109-0.109-0.25-0.125-0.313-0.047-0.078 0.063-0.047 0.203 0.063 0.297 0.109 0.109 0.25 0.125 0.313 0.047zM7.047 21.516c0.031-0.094-0.063-0.203-0.203-0.25-0.125-0.031-0.266 0.016-0.297 0.109s0.063 0.203 0.203 0.234c0.125 0.047 0.266 0 0.297-0.094zM8.031 21.594c0-0.109-0.125-0.187-0.266-0.172-0.141 0-0.25 0.078-0.25 0.172 0 0.109 0.109 0.187 0.266 0.172 0.141 0 0.25-0.078 0.25-0.172zM8.937 21.438c-0.016-0.094-0.141-0.156-0.281-0.141-0.141 0.031-0.234 0.125-0.219 0.234 0.016 0.094 0.141 0.156 0.281 0.125s0.234-0.125 0.219-0.219z"></path>
</svg>
 Project on Github</a></p>

<p>I’ve recently been learning Rust. Originally, I was drawn to it because of my embedded projects: Although I’ve
appreciated the “behind the curtains” look that writing plan-old C gives into the embedded runtime environment, I was
feeling the strain of my limited familiarity with the language and its quirks. Rust seemed like an exciting, modern
language to learn, with plenty of developer-friendly features, and the fact that it apparently <a href="https://docs.rust-embedded.org/book/" title="The Embedded Rust Book">supports embedded
targets</a> was a nice bonus. I read through the <a href="https://doc.rust-lang.org/book/" title="The Rust Book on rust-lang.org">online Rust book</a>, the excellent <a href="https://www.oreilly.com/library/view/programming-rust-3rd/9781098176228/" title="Programming Rust, by Jim Blandy, Jason Orendorff, and Leonora F. S. Tindall, on O'Reilly's website"><em>Programming Rust</em></a>, and had worked
through several of <a href="https://github.com/danapplegate/adventofcode2022" title="Github repo for my solutions to 2022's Advent of Code, written in Rust">this year’s Advent of Code problems</a> using it. I was really enjoying Rust so far, but I wanted to
try using it for a larger project that would help me get a better understanding of building fully functional software
with it.</p>

<p>I decided to see if I could build a performant physics simulator from the ground up. For me, this meant implementing
even basic concepts like vector operations from scratch, to get a feel for the type and trait systems and see what was
possible. Starting with astronomical simulations and working in 2D, but then quickly adding support for 3D, I devised a
simple configuration format in YAML to specify the starting system state. I used the Earth and Moon system as a test
case, drawing starting simulation values from their Wikipedia pages.</p>

<p>Just to get started, I wanted to set up a basic vector multiplication module, which would be essential for representing
and manipulating force vectors. Although it would have been easy to use one of several linear algebra crates to handle
all of this for me, one of my goals with the project was to get a feel for Rust’s expressiveness. I was quickly able to
set up a two-dimensional <code class="language-plaintext highlighter-rouge">Vector</code> type for 2D simulations, and in the process of expanding this to three dimensions, I
was pleasantly surprised to discover Rust’s <a href="https://doc.rust-lang.org/reference/items/generics.html#const-generics" title="Rust reference page for const generics">const generics</a> feature, akin to <a href="https://en.cppreference.com/w/cpp/language/template_parameters.html" title="Template parameters documentation page on cppreference.com">constant template parameters from C++</a>,
which allowed me to write generic definitions for n-dimensional vectors:</p>

<!-- prettier-ignore-start -->

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">ops</span><span class="p">::{</span><span class="nb">Index</span><span class="p">,</span> <span class="n">IndexMut</span><span class="p">};</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span><span class="p">([</span><span class="nb">f32</span><span class="p">;</span> <span class="n">N</span><span class="p">]);</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">From</span><span class="o">&lt;</span><span class="p">[</span><span class="nb">f32</span><span class="p">;</span> <span class="n">N</span><span class="p">]</span><span class="o">&gt;</span> <span class="k">for</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">from</span><span class="p">(</span><span class="n">components</span><span class="p">:</span> <span class="p">[</span><span class="nb">f32</span><span class="p">;</span> <span class="n">N</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span><span class="p">(</span><span class="n">components</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Default</span> <span class="k">for</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">default</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span><span class="p">([</span><span class="mf">0.0</span><span class="p">;</span> <span class="n">N</span><span class="p">])</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Index</span><span class="o">&lt;</span><span class="nb">usize</span><span class="o">&gt;</span> <span class="k">for</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span> <span class="o">=</span> <span class="nb">f32</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">index</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">i</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="n">IndexMut</span><span class="o">&lt;</span><span class="nb">usize</span><span class="o">&gt;</span> <span class="k">for</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">index_mut</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">i</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<!-- prettier-ignore-end -->

<p>Implementing the <code class="language-plaintext highlighter-rouge">Index</code> and <code class="language-plaintext highlighter-rouge">IndexMut</code> traits on N-Vectors provides a generic way to access the vector’s members with
<code class="language-plaintext highlighter-rouge">v[0]</code>, <code class="language-plaintext highlighter-rouge">v[1]</code>, etc., but for convenience I added more ergonomic accessors for my primary 2D and 3D physical simulation
use cases, allowing one to use the more familiar <code class="language-plaintext highlighter-rouge">(x, y, z)</code> coordinate system:</p>

<!-- prettier-ignore-start -->

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="mi">2</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">])</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">x</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">y</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="mi">3</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">z</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">])</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">x</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">y</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">z</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">type</span> <span class="n">Vector2</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="mi">2</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">type</span> <span class="n">Vector3</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="mi">3</span><span class="o">&gt;</span><span class="p">;</span></code></pre></figure>

<!-- prettier-ignore-end -->

<p>With these definitions established, I could now generically implement field operations on my N-dimensional vectors. This
would allow me to perform basic mathematical operations on them, such as addition, subtraction, and even the dot
product, by simply writing expressions like <code class="language-plaintext highlighter-rouge">(v1 + v2).dot(v3)</code>:</p>

<!-- prettier-ignore-start -->

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">ops</span><span class="p">::{</span><span class="nb">Add</span><span class="p">,</span> <span class="nb">Div</span><span class="p">,</span> <span class="nb">Mul</span><span class="p">,</span> <span class="nb">Sub</span><span class="p">};</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Sub</span><span class="o">&lt;&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;</span> <span class="k">for</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">sub</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">components</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">;</span> <span class="n">N</span><span class="p">];</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="p">{</span>
            <span class="n">components</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">other</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="nn">Vector</span><span class="p">::</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">(</span><span class="n">components</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Div</span><span class="o">&lt;&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;</span> <span class="k">for</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">div</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">components</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">;</span> <span class="n">N</span><span class="p">];</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="p">{</span>
            <span class="n">components</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">/</span> <span class="n">other</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="nn">Vector</span><span class="p">::</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">(</span><span class="n">components</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Div</span><span class="o">&lt;</span><span class="nb">f32</span><span class="o">&gt;</span> <span class="k">for</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">div</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">components</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">;</span> <span class="n">N</span><span class="p">];</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="p">{</span>
            <span class="n">components</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">/</span> <span class="n">other</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="nn">Vector</span><span class="p">::</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">(</span><span class="n">components</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Add</span><span class="o">&lt;&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;</span> <span class="k">for</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">components</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">;</span> <span class="n">N</span><span class="p">];</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="p">{</span>
            <span class="n">components</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">other</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="nn">Vector</span><span class="p">::</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">(</span><span class="n">components</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Mul</span><span class="o">&lt;&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;</span> <span class="k">for</span> <span class="nb">f32</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">mul</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">components</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">;</span> <span class="n">N</span><span class="p">];</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="p">{</span>
            <span class="n">components</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span> <span class="o">*</span> <span class="n">other</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="nn">Vector</span><span class="p">::</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">(</span><span class="n">components</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">dot</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">rhs</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">Self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">sum</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">;</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="p">{</span>
            <span class="n">sum</span> <span class="o">+=</span> <span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">rhs</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="n">sum</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<!-- prettier-ignore-end -->

<p>Note the implementation of both vector and scalar versions of <code class="language-plaintext highlighter-rouge">Div</code>. The former is for completeness alongside <code class="language-plaintext highlighter-rouge">Mul</code>, to
allow for inverse operations, while the scalar version would become useful shortly, when implementing a <code class="language-plaintext highlighter-rouge">normalize</code>
function for my <code class="language-plaintext highlighter-rouge">Vector&lt;N&gt;</code> struct:</p>

<!-- prettier-ignore-start -->

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Div</span><span class="o">&lt;&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;</span> <span class="k">for</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="nb">Div</span><span class="o">&lt;</span><span class="nb">f32</span><span class="o">&gt;</span> <span class="k">for</span> <span class="o">&amp;</span><span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span></code></pre></figure>

<!-- prettier-ignore-end -->

<p>With these primitives out of the way, I could now move on to the meat of my simulation project and begin expressing
physical force interactions through code. To start, I augmented the definition of my N-vectors to include behavior that
is specific to simulations of physical objects in space. The primary force interaction between large celestial bodies
like the Earth and Moon is gravity, which correlates the mass of two objects (<em>m<sub>1</sub></em> and <em>m<sub>2</sub></em>) and
the square of the distance between them (expressed as <em>r</em>) with the force of attraction between them, <em>F</em>, scaled by the
universal gravitational constant, <em>G</em>:</p>

\[F = G \dfrac{m_{1}m_{2}}{r^2}\]

<p>The masses of the physical objects aren’t related in any way to the objects’ locations or distances between each other,
so I decided that mass would be stored elsewhere, as attributes of the objects themselves, alongside their position and
velocity vectors. Adding a few quick helper functions to my <code class="language-plaintext highlighter-rouge">Vector&lt;N&gt;</code> implementation, and then adding a new trait
<code class="language-plaintext highlighter-rouge">Distance</code> and implementing it for <code class="language-plaintext highlighter-rouge">Vector&lt;N&gt;</code>:</p>

<!-- prettier-ignore-start -->

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">normalize</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="c1">// Scalar division of vector</span>
        <span class="k">self</span> <span class="o">/</span> <span class="k">self</span><span class="nf">.magnitude</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">magnitude</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="c1">// Use f64 to avoid precision loss</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">sum_of_squares</span> <span class="o">=</span> <span class="mf">0_f64</span><span class="p">;</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="p">{</span>
            <span class="n">sum_of_squares</span> <span class="o">+=</span> <span class="p">(</span><span class="k">self</span><span class="na">.0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">as</span> <span class="nb">f64</span><span class="p">)</span><span class="nf">.powi</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">sum_of_squares</span><span class="nf">.sqrt</span><span class="p">()</span> <span class="k">as</span> <span class="nb">f32</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">trait</span> <span class="n">Distance</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span><span class="p">:</span> <span class="n">Distance</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">distance</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">Self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">direction</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">to</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">Self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="n">Distance</span> <span class="k">for</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Output</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">distance</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">Self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="p">(</span><span class="k">self</span> <span class="o">-</span> <span class="n">other</span><span class="p">)</span><span class="nf">.magnitude</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">direction</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">to</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">Self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Output</span> <span class="p">{</span>
        <span class="p">(</span><span class="n">to</span> <span class="o">-</span> <span class="k">self</span><span class="p">)</span><span class="nf">.normalize</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<!-- prettier-ignore-end -->

<p>…gave me everything I needed to describe a <code class="language-plaintext highlighter-rouge">Force</code> trait and define <code class="language-plaintext highlighter-rouge">Gravity</code> itself:</p>

<!-- prettier-ignore-start -->

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">const</span> <span class="n">G</span><span class="p">:</span> <span class="nb">f32</span> <span class="o">=</span> <span class="mf">6.67430e-11</span><span class="p">;</span>

<span class="k">type</span> <span class="n">PositionVector</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">type</span> <span class="n">VelocityVector</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">Vector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">;</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">ForceVector</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="n">label</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">v</span><span class="p">:</span> <span class="n">PositionVector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="n">ForceVector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">magnitude</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">f32</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.v</span><span class="nf">.magnitude</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">struct</span> <span class="n">Body</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="n">label</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">mass</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">diameter</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">position</span><span class="p">:</span> <span class="n">PositionVector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">velocity</span><span class="p">:</span> <span class="n">VelocityVector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">,</span>

    <span class="k">pub</span> <span class="n">forces</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">ForceVector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="c1">// A ForceMap associates each Body label as the hash key with the list </span>
<span class="c1">// of forces that are acting upon it.</span>
<span class="k">pub</span> <span class="k">type</span> <span class="n">ForceMap</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">ForceVector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;&gt;</span><span class="p">;</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Gravity</span> <span class="p">{</span>
    <span class="n">g</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Gravity</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">g</span><span class="p">:</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">f32</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="n">Gravity</span> <span class="p">{</span> <span class="n">g</span><span class="p">:</span> <span class="n">g</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="n">G</span><span class="p">)</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// Given a list of Bodies, calculates the force of gravity imposed on</span>
    <span class="c1">// each by every other Body.</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="n">forces_from_bodies</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">bodies</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">Vec</span><span class="o">&lt;&amp;</span><span class="n">Body</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">ForceMap</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">force_map</span> <span class="o">=</span> <span class="nn">ForceMap</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
        <span class="k">for</span> <span class="n">body_pair</span> <span class="k">in</span> <span class="n">bodies</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.combinations</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">let</span> <span class="p">(</span><span class="n">b1</span><span class="p">,</span> <span class="n">b2</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">body_pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">body_pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

            <span class="n">force_map</span>
                <span class="nf">.entry</span><span class="p">(</span><span class="n">b1</span><span class="py">.label</span><span class="nf">.clone</span><span class="p">())</span>
                <span class="nf">.or_insert</span><span class="p">(</span><span class="nd">vec!</span><span class="p">[])</span>
                <span class="nf">.push</span><span class="p">(</span><span class="k">self</span><span class="nf">.calculate</span><span class="p">(</span><span class="n">b1</span><span class="p">,</span> <span class="n">b2</span><span class="p">));</span>

            <span class="n">force_map</span>
                <span class="nf">.entry</span><span class="p">(</span><span class="n">b2</span><span class="py">.label</span><span class="nf">.clone</span><span class="p">())</span>
                <span class="nf">.or_insert</span><span class="p">(</span><span class="nd">vec!</span><span class="p">[])</span>
                <span class="nf">.push</span><span class="p">(</span><span class="k">self</span><span class="nf">.calculate</span><span class="p">(</span><span class="n">b2</span><span class="p">,</span> <span class="n">b1</span><span class="p">));</span>
        <span class="p">}</span>
        <span class="n">force_map</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Force</span> <span class="k">for</span> <span class="n">Gravity</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="n">calculate</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="k">const</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">on</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="n">Body</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">from</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="n">Body</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">ForceVector</span><span class="o">&lt;</span><span class="n">N</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">distance</span> <span class="o">=</span> <span class="n">on</span><span class="py">.position</span><span class="nf">.distance</span><span class="p">(</span><span class="o">&amp;</span><span class="n">from</span><span class="py">.position</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">magnitude</span> <span class="o">=</span> <span class="k">self</span><span class="py">.g</span> <span class="o">*</span> <span class="n">on</span><span class="py">.mass</span> <span class="o">*</span> <span class="n">from</span><span class="py">.mass</span> <span class="o">/</span> <span class="n">distance</span><span class="nf">.powi</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>

        <span class="k">let</span> <span class="n">on_force_name</span> <span class="o">=</span> <span class="nd">format!</span><span class="p">(</span><span class="s">"gravity_{}"</span><span class="p">,</span> <span class="n">from</span><span class="py">.label</span><span class="p">);</span>
        <span class="n">ForceVector</span> <span class="p">{</span>
            <span class="n">label</span><span class="p">:</span> <span class="n">on_force_name</span><span class="p">,</span>
            <span class="n">v</span><span class="p">:</span> <span class="n">magnitude</span> <span class="o">*</span> <span class="o">&amp;</span><span class="n">on</span><span class="py">.position</span><span class="nf">.direction</span><span class="p">(</span><span class="o">&amp;</span><span class="n">from</span><span class="py">.position</span><span class="p">),</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<!-- prettier-ignore-end -->

<p>To display the output, I started with plain textual output of the incremental positions and velocities of each object in
the simulation, but soon enough found myself wondering what it would take to render the simulation visually. Working
through the phenomenal free tutorials on <a href="https://learnopengl.com/" title="Learn OpenGL website">learnopengl.com</a>, I was able to get a basic sphere modeled, and to draw an
Earth texture on it. I soon did the same for the moon. Although the tutorials are written for C++, the concepts were
fairly easy to translate into Rust, with the help of a Rust crate called <a href="https://github.com/not-fl3/miniquad" title="Miniquad repo page on Github">miniquad</a> which provides type-safe bindings
for the OpenGL calls.</p>

<figure>
  <img src="/assets/img/simulator_screenshot.png" alt="Screenshot of the simulator" />
  <figcaption>Screenshot of the simulator running an Earth and Moon simulation</figcaption>
</figure>

<p>There’s a lot more to this project that I wasn’t able to cover in this post: My OpenGL learning journey; the structure
of the actual <code class="language-plaintext highlighter-rouge">Simulation</code> struct which uses these code snippets; my brief encounter with <a href="https://en.wikipedia.org/wiki/Quaternion" title="Quaternion on Wikipedia">quaternions</a> in order to
simply get my simulated objects to spin correctly. But I’m proud of how the foundations of this project turned out, and
I wanted to highlight how expressive Rust can be. For future work, I’d like to continue to improve the visuals of the
simulator, adding a trackball and zoom interface, as well as labels and other textual information. From there, I want to
try to stress test the simulation: How many bodies can it handle at once? If I encounter performance problems, what
optimizations can I implement to speed it up? Can I leverage <a href="https://en.wikipedia.org/wiki/CUDA" title="CUDA on Wikipedia">CUDA</a> or similar high-performance computing techniques to
parallelize the force calculations? Can I develop a testing mechanism to see how accurate my simulation is over long
timeframes, and what can I do to improve that accuracy? Hopefully, this is only the beginning of my journey through
graphics programming and Rust!</p>

<!-- prettier-ignore-start -->
<!-- prettier-ignore-end -->]]></content><author><name></name></author><category term="projects" /><category term="rust" /><category term="open_source" /><summary type="html"><![CDATA[Project on Github]]></summary></entry><entry><title type="html">Discovering and Fixing an Issue with the AVRDude Utility</title><link href="https://danapplegate.com/projects/2022/10/07/avrdude-tpi-fix.html" rel="alternate" type="text/html" title="Discovering and Fixing an Issue with the AVRDude Utility" /><published>2022-10-07T00:00:00+00:00</published><updated>2022-10-07T00:00:00+00:00</updated><id>https://danapplegate.com/projects/2022/10/07/avrdude-tpi-fix</id><content type="html" xml:base="https://danapplegate.com/projects/2022/10/07/avrdude-tpi-fix.html"><![CDATA[<p><a id="github-repo-link" class="icon" href="https://github.com/avrdudes/avrdude/pull/1115" target="_blank"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 28" height="24" width="28"><path d="M12 2c6.625 0 12 5.375 12 12 0 5.297-3.437 9.797-8.203 11.391-0.609 0.109-0.828-0.266-0.828-0.578 0-0.391 0.016-1.687 0.016-3.297 0-1.125-0.375-1.844-0.812-2.219 2.672-0.297 5.484-1.313 5.484-5.922 0-1.313-0.469-2.375-1.234-3.219 0.125-0.313 0.531-1.531-0.125-3.187-1-0.313-3.297 1.234-3.297 1.234-0.953-0.266-1.984-0.406-3-0.406s-2.047 0.141-3 0.406c0 0-2.297-1.547-3.297-1.234-0.656 1.656-0.25 2.875-0.125 3.187-0.766 0.844-1.234 1.906-1.234 3.219 0 4.594 2.797 5.625 5.469 5.922-0.344 0.313-0.656 0.844-0.766 1.609-0.688 0.313-2.438 0.844-3.484-1-0.656-1.141-1.844-1.234-1.844-1.234-1.172-0.016-0.078 0.734-0.078 0.734 0.781 0.359 1.328 1.75 1.328 1.75 0.703 2.141 4.047 1.422 4.047 1.422 0 1 0.016 1.937 0.016 2.234 0 0.313-0.219 0.688-0.828 0.578-4.766-1.594-8.203-6.094-8.203-11.391 0-6.625 5.375-12 12-12zM4.547 19.234c0.031-0.063-0.016-0.141-0.109-0.187-0.094-0.031-0.172-0.016-0.203 0.031-0.031 0.063 0.016 0.141 0.109 0.187 0.078 0.047 0.172 0.031 0.203-0.031zM5.031 19.766c0.063-0.047 0.047-0.156-0.031-0.25-0.078-0.078-0.187-0.109-0.25-0.047-0.063 0.047-0.047 0.156 0.031 0.25 0.078 0.078 0.187 0.109 0.25 0.047zM5.5 20.469c0.078-0.063 0.078-0.187 0-0.297-0.063-0.109-0.187-0.156-0.266-0.094-0.078 0.047-0.078 0.172 0 0.281s0.203 0.156 0.266 0.109zM6.156 21.125c0.063-0.063 0.031-0.203-0.063-0.297-0.109-0.109-0.25-0.125-0.313-0.047-0.078 0.063-0.047 0.203 0.063 0.297 0.109 0.109 0.25 0.125 0.313 0.047zM7.047 21.516c0.031-0.094-0.063-0.203-0.203-0.25-0.125-0.031-0.266 0.016-0.297 0.109s0.063 0.203 0.203 0.234c0.125 0.047 0.266 0 0.297-0.094zM8.031 21.594c0-0.109-0.125-0.187-0.266-0.172-0.141 0-0.25 0.078-0.25 0.172 0 0.109 0.109 0.187 0.266 0.172 0.141 0 0.25-0.078 0.25-0.172zM8.937 21.438c-0.016-0.094-0.141-0.156-0.281-0.141-0.141 0.031-0.234 0.125-0.219 0.234 0.016 0.094 0.141 0.156 0.281 0.125s0.234-0.125 0.219-0.219z"></path>
</svg>
 Pull Request on Github</a></p>]]></content><author><name></name></author><category term="projects" /><category term="c" /><category term="avr" /><category term="electronics" /><category term="microcontrollers" /><category term="avrdude" /><category term="open_source" /><summary type="html"><![CDATA[Pull Request on Github]]></summary></entry></feed>