<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[aclysma's blog]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://blog.aclysma.com/</link><image><url>https://blog.aclysma.com/favicon.png</url><title>aclysma&apos;s blog</title><link>https://blog.aclysma.com/</link></image><generator>Ghost 4.9</generator><lastBuildDate>Fri, 25 Jul 2025 11:49:58 GMT</lastBuildDate><atom:link href="https://blog.aclysma.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Rust on iOS with SDL2]]></title><description><![CDATA[A guide to setting up an iOS project using Rust and SDL2]]></description><link>https://blog.aclysma.com/rust-on-ios-with-sdl2/</link><guid isPermaLink="false">60f0b57f7c011ff4a132a454</guid><category><![CDATA[rust]]></category><category><![CDATA[gamedev]]></category><category><![CDATA[iOS]]></category><category><![CDATA[SDL2]]></category><dc:creator><![CDATA[Philip Degarmo]]></dc:creator><pubDate>Tue, 21 Jul 2020 07:42:44 GMT</pubDate><content:encoded><![CDATA[<p>Here&apos;s a guide to setting up an iOS project using Rust and SDL2.</p><p>EDIT: These instructions tend to rot over time due to changes in xcode and SDL2&apos;s project structure.</p><h2 id="initialize-a-git-repo-and-get-sdl2">Initialize a git repo and get SDL2</h2><p>Run through these commands to init a git repo and grab SDL2.</p><pre><code class="language-text">cd ~/dev/rust
mkdir ios-sdl2
cd ios-sdl2
git init
git submodule add --name SDL2 https://github.com/spurious/SDL-mirror.git SDL2
git commit -m &quot;Initial commit&quot;</code></pre><p>Now&apos;s a good time to add some things to your .gitignore</p><pre><code class="language-text">/target
Cargo.lock
xcuserdata</code></pre><p>Commit the .gitignore</p><pre><code class="language-text">git add .gitignore
git commit -m &quot;Add gitignore file&quot;</code></pre><h2 id="build-sdl2">Build SDL2</h2><p>Open SDL2&apos;s iOS xcode project</p><pre><code class="language-text">open -a xcode SDL2/Xcode/SDL/SDL.xcodeproj</code></pre><p>Set up the build scheme like this and hit play:</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-4.png" class="kg-image" alt loading="lazy"></figure><p>EDIT: The screenshot is a bit old, the correct setting is <code>Framework-iOS &gt; Any iOS Device (arm64 armv7)</code></p><p>Once this finishes, you will have a <code>libSDL2.a</code> file... somewhere. (xcode put mine somewhere in <code>~/Library/Developer/Xcode/DerivedData/HASHED_FOLDER/Build/Products/</code> - but that&apos;s fine. We&apos;ll pull it in later.</p><p>Include files are in <code>SDL2/include</code></p><h2 id="setup-the-xcode-project">Setup the xcode project</h2><p>xcode will be used to deploy your app to the device. There&apos;s an example project we can pull from SDL2 to help us get started</p><pre><code class="language-text">cp -r &quot;SDL2/Xcode-iOS/Template/SDL iOS Application&quot; xcode</code></pre><p>We need to fix up a few names from the template. There&apos;s a placeholder <code>___PROJECTNAME___</code> used as both a filename and within some files. (That&apos;s PROJECTNAME surrounded by three underscores)</p><ul><li>Rename <code>___PROJECTNAME___.xcodeproj</code></li><li>Find and replace <code>___PROJECTNAME___</code> in <code>ios-sdl2.xcodeproj/project.pbxproj</code></li></ul><p>Here&apos;s a script to do that and commit the changes</p><pre><code class="language-text">cd xcode
mv ___PROJECTNAME___.xcodeproj ios-sdl2.xcodeproj
sed -i &quot;&quot; &apos;s/___PROJECTNAME___/ios-sdl2/g&apos; ios-sdl2.xcodeproj/project.pbxproj
cd ..
git add xcode
git commit -m &quot;Add xcode project&quot;</code></pre><h2 id="link-against-sdl2">Link against SDL2</h2><p>Now launch xcode (the project is in <code>/xcode/ios-sdl2.xcodeproj</code>) and hit the play.</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-1.png" class="kg-image" alt loading="lazy"></figure><p> You should get an error like this:</p><pre><code class="language-text">SDL.h file not found</code></pre><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-2.png" class="kg-image" alt loading="lazy"></figure><p>This is because we copy/pasted a template. It has paths that need to be fixed and will not build immediately.</p><h3 id="add-sdl2-headers-to-the-include-path">Add SDL2 headers to the include path</h3><ul><li>Open the files &quot;tab&quot; (see image below)</li><li>Select the root node &quot;ios-sdl2&quot;</li><li>Select Build Settings at the top</li></ul><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-9.png" class="kg-image" alt loading="lazy"></figure><ul><li>Use the search below and to the right and find &quot;User Header Search Paths&quot;</li><li>Double click and modify the entry to &quot;../SDL2/include&quot;</li></ul><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-10.png" class="kg-image" alt loading="lazy"></figure><h3 id="fix-broken-reference-to-sdl2-library">Fix Broken Reference to SDL2 Library</h3><p>First, <strong>CLOSE ALL INSTANCES OF XCODE</strong>. We need to make absolutely sure the SDL2 project is not open. Otherwise the following steps will fail. Now reopen <code>/xcode/ios-sdl2.xcodeproj</code></p><p>We should fix up the SDL.xcodeproj reference that&apos;s in the files list. Point it at <code>SDL2/Xcode/SDL/SDL.xcodeproj</code>. </p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-7.png" class="kg-image" alt loading="lazy"></figure><p>This does a couple things:</p><ul><li>Makes SDL2 source code available in your project</li><li>Allows you to easily static link against the output of this library</li></ul><h3 id="add-sdl2-as-a-link-dependency">Add SDL2 as a Link Dependency</h3><p>We need to fix up library reference so that the project builds.</p><ul><li>Select ios-sdl2 project in the top left corner. This will bring up the project configuration if it isn&apos;t already showing</li><li>Scroll down to the Frameworks, Libraries, and Embedded Content section. You may see libSDL2.a with an empty outline</li></ul><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-3.png" class="kg-image" alt loading="lazy"></figure><ul><li>If this is the case, select it and remove it with the &quot;-&quot;.</li><li>Click &quot;+&quot; so we can add it back correctly.</li><li>Select libSDL2.a from the libSDL-iOS target and click add</li></ul><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-11.png" class="kg-image" alt loading="lazy"></figure><p>Now it should look like this...</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-13.png" class="kg-image" alt loading="lazy"></figure><h3 id="final-steps-for-running-in-simulator">Final steps for Running in Simulator</h3><p>If you try to run it now, you&apos;ll likely have a few link errors. Fix this up by going back to the Frameworks, Libraries, and Embedded Content section. Add these frameworks. (Click plus and type in the text box to quickly find it)</p><ul><li>AVFoundation.framework</li><li>Security.framework</li></ul><p><strong>EDIT: I didn&apos;t need to do this step at this point, but I needed to add Security.framework later! (Also, you&apos;ll follow this step later to add a rust static library...)</strong></p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-17.png" class="kg-image" alt loading="lazy"></figure><p>With link errors solved, we get a new error message:</p><pre><code class="language-text">The application&apos;s Info.plist does not contain CFBundleShortVersionString.
Ensure your bundle contains a CFBundleShortVersionString.</code></pre><p>Open Info.plist and add it.</p><ul><li>Open the files &quot;tab&quot; if it isn&apos;t already open</li><li>Select Info.plist</li><li>Right click Information Property List</li><li>Select &quot;Add Row&quot;</li><li>Type in CFBundleShortVersionString and hit enter. It will likely change to &quot;Bundle version string (short)&quot; - that&apos;s fine</li><li>Set the value to &quot;0.1.0&quot;</li></ul><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-6.png" class="kg-image" alt loading="lazy"></figure><p>At this point when you hit play, the simulator should come up. SDL2 should load and start drawing!</p><h3 id="deploying-to-a-device">Deploying to a device</h3><p>To follow this step, you may need an apple developer account. I&apos;m not going to cover this in detail but I&apos;ll just mention briefly a few things I set:</p><ul><li>In the project settings under General, you can pick a target version, like iOS 12.4</li><li>In the project settings under Signing &amp; Capabilities, select your team and set a bundle identifier</li><li>When I switched to iOS 12.4, I needed to add Metal.framework</li></ul><h3 id="finally-write-some-rust-">Finally, write some Rust!</h3><p>Time to get a rust project up and running! The general approach is that we will create a C library, link it, and call into it. I highly recommend checking out this repo: <a href="https://github.com/thombles/dw2019rust/blob/master/modules/01%20-%20Hello%20DevWorld.md">https://github.com/thombles/dw2019rust</a>. Most of the below steps are covered in detail there.</p><p>First thing you&apos;ll need to do is grab the rust toolchains for:</p><ul><li>Physical devices: <code>aarch64-apple-ios</code></li><li>Simulators: &#xA0;<code>x86_64-apple-ios</code></li></ul><pre><code class="language-text">rustup target add aarch64-apple-ios x86_64-apple-ios</code></pre><p>Now create a rust library</p><pre><code class="language-text">cargo new --lib game-ios</code></pre><p>Modify the .toml to create a library. I&apos;ll also add in sdl2 and a simple logging crate.</p><pre><code class="language-toml">[lib]
crate-type = [&quot;lib&quot;, &quot;staticlib&quot;]

[dependencies]
sdl2 = &quot;0.34&quot;
env_logger = &quot;0.6&quot;
log=&quot;0.4&quot;</code></pre><p>And modify lib.rs</p><pre><code class="language-rust">#[no_mangle]
pub extern &quot;C&quot; fn run_the_game() {
    env_logger::Builder::from_default_env()
        .filter_level(log::LevelFilter::Info)
        .init();

    log::info!(&quot;Started!&quot;);
}
</code></pre><p>Finally, some rust code! Rather than a standard main function, we expose a C-ABI compatible function. The main.c in our xcode project can link against the library created by rust and call into it.</p><p>For convenience, create an example. This allows building and running the library outside of xcode. I added examples/run_the_game.rs with:</p><pre><code class="language-rust">use game_ios::*;

fn main() {
    run_the_game();
}</code></pre><p>Add a workspace file (<code>Cargo.toml</code>) at the root of the project</p><pre><code class="language-toml">[workspace]
members = [
    &quot;game-ios&quot;,
]</code></pre><p>This does two things:</p><ul><li>Allows you to run <code>cargo build</code> and <code>cargo run --example run_the_game</code> in the base of the project</li><li>Puts the output folder (&quot;target&quot;) in the base of the project</li></ul><p>At this point your project structure should look like this:</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-8.png" class="kg-image" alt loading="lazy"></figure><h3 id="linking-rust-from-xcode">Linking Rust from xcode</h3><p>First, let&apos;s automate building the rust project from xcode. Here&apos;s a script that will work. For information about the &quot;lipo&quot; commands, see here: <a href="https://github.com/thombles/dw2019rust/blob/master/modules/02%20-%20Cross-compiling%20for%20Xcode.md">https://github.com/thombles/dw2019rust/blob/master/modules/02 - Cross-compiling for Xcode.md</a></p><pre><code class="language-text">set -e
RUST_PROJ=&quot;/Users/pmd/dev/rust/ios-sdl2&quot; &lt;-- EDIT TO MATCH YOUR PATH
PATH=&quot;$PATH:/Users/pmd/.cargo/bin&quot; &lt;-- EDIT TO MATCH YOUR PATH

cd &quot;$RUST_PROJ&quot;
cargo build --package game-ios --target aarch64-apple-ios --verbose
cargo build --package game-ios --target x86_64-apple-ios --verbose

lipo -create target/aarch64-apple-ios/debug/libgame_ios.a target/x86_64-apple-ios/debug/libgame_ios.a -output target/libgame_ios.a</code></pre><p>We can add this to xcode.</p><ul><li>Open the project settings and under the &quot;Build Phases&quot; section</li><li>Add a Run Script phase</li><li>Drag it up to be earlier in the build</li><li>Add the script. <strong>Be sure to update the paths!</strong></li></ul><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-20.png" class="kg-image" alt loading="lazy"></figure><p>More info on setting up build scripts here: <a href="https://github.com/thombles/dw2019rust/blob/master/modules/04%20-%20Build%20automation.md">https://github.com/thombles/dw2019rust/blob/master/modules/04 - Build automation.md</a></p><p>Errors you might see now:</p><ul><li><code>library not found for -ISystem/linking with cc failed: exit code 1</code>: I didn&apos;t use to have this problem and hopefully there&apos;s a better solution... but running cargo build manually once fixed it for me</li><li>Missing symbol <code>_run_the_game</code>: follow the steps above &quot;Final steps for Running in Simulator&quot; to add the rust static library to your project. It&apos;s in <code>target/libgame_ios.a</code></li></ul><p>This will likely fail with an error message about a missing symbol</p><p>Finally, we need to add the rust output directory to the library search path. This is in the same area we updated the include paths for SDL.</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-15.png" class="kg-image" alt loading="lazy"></figure><h3 id="starting-the-rust-code">Starting the Rust Code</h3><p>We&apos;re close! Update main.c</p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-16.png" class="kg-image" alt loading="lazy"></figure><pre><code class="language-C">// Including SDL.h is required to let SDL hook main and set up the app delegate
#include &quot;SDL.h&quot;
#include &lt;stdio.h&gt;

extern void run_the_game();

int main(int argc, char *argv[])
{
    run_the_game();
    printf(&quot;run_the_game returned&quot;);
    return 0;
}
</code></pre><p>If you get a linker error &quot;Undefined symbol: _SecRandomCopyBytes&quot;, ensure Security.framework is included. (See steps above)</p><p>Now you should see in the output:</p><pre><code class="language-text">[2020-07-21T07:08:50Z INFO  game_ios] Started!
run_the_game returned</code></pre><h3 id="one-more-build-config-setting">One More Build Config Setting</h3><p>Rust does not produce bitcode compatible with xcode LLVM. So to run on a physical device, it must be disabled. It&apos;s in the same area as where we modified header/library paths, but make sure to enable showing &quot;All&quot; settings. More info here: <a href="https://github.com/thombles/dw2019rust/blob/master/modules/02%20-%20Cross-compiling%20for%20Xcode.md#1-use-a-physical-iphone-or-ipad">https://github.com/thombles/dw2019rust/blob/master/modules/02 - Cross-compiling for Xcode.md#1-use-a-physical-iphone-or-ipad</a></p><figure class="kg-card kg-image-card"><img src="/content/images/2020/07/image-18.png" class="kg-image" alt loading="lazy"></figure><h3 id="a-more-visual-demo">A More Visual Demo</h3><p>This code will make the screen change colors and print events to the console</p><pre><code class="language-rust">
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use std::time::Duration;

#[no_mangle]
pub extern &quot;C&quot; fn run_the_game() {
    env_logger::Builder::from_default_env()
        .filter_level(log::LevelFilter::Info)
        .init();

    log::info!(&quot;Started!&quot;);

    do_run_the_game().unwrap();
}

pub fn do_run_the_game() -&gt; Result&lt;(), String&gt; {
    let sdl_context = sdl2::init()?;
    let video_subsystem = sdl_context.video()?;
    let window = video_subsystem.window(&quot;rust-sdl2 demo&quot;, 800, 600)
        .position_centered()
        .opengl()
        .build()
        .map_err(|e| e.to_string())?;
        
    let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;

    canvas.set_draw_color(Color::RGB(255, 0, 255));
    canvas.clear();
    canvas.present();
    let mut event_pump = sdl_context.event_pump()?;

    let t0 = std::time::Instant::now();
    
    &apos;running: loop {
        for event in event_pump.poll_iter() {
            println!(&quot;{:?}&quot;, event);
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } =&gt; {
                    break &apos;running
                },
                _ =&gt; {}
            }
        }
    
        let time = (std::time::Instant::now() - t0).as_secs_f32();
        let fraction = (time.sin() + 1.0) / 2.0;

        let color = (fraction * 255.0) as u8;
        canvas.set_draw_color(Color::RGB(0, 0, color)); 
        canvas.clear();
        canvas.present();
        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 30));
    }

    Ok(())
}
</code></pre><p>Commit all the changes</p><pre><code class="language-text">git add .
git commit -m &quot;Rust app works&quot;
</code></pre><p>And the output is here:</p><figure class="kg-card kg-embed-card"><iframe width="459" height="344" src="https://www.youtube.com/embed/9tU15ihoh5U?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure>]]></content:encoded></item><item><title><![CDATA[Atelier/Legion Integration Demo]]></title><description><![CDATA[<p><em>(<a href="https://community.amethyst.rs/t/atelier-legion-integration-demo/1352">Originally posted on the amethyst community forums on Mar 14, 2020</a>)</em></p><p>In late 2019/early 2020, <a href="https://twitter.com/kabergstrom">@kabergstrom</a> and I explored how <a href="https://github.com/TomGillen/legion">legion</a> and <a href="https://github.com/amethyst/atelier-assets">atelier-assets</a> could be integrated together, particularly in the context of implementing an editing workflow. Some of the goals we started with are here: <a href="https://community.amethyst.rs/t/rich-editing-experience-using-atelier-assets-and-legion/1263">Rich Editing Experience Using</a></p>]]></description><link>https://blog.aclysma.com/atelier-legion-integration-demo/</link><guid isPermaLink="false">60f0b57f7c011ff4a132a453</guid><dc:creator><![CDATA[Philip Degarmo]]></dc:creator><pubDate>Sun, 10 May 2020 05:33:12 GMT</pubDate><content:encoded><![CDATA[<p><em>(<a href="https://community.amethyst.rs/t/atelier-legion-integration-demo/1352">Originally posted on the amethyst community forums on Mar 14, 2020</a>)</em></p><p>In late 2019/early 2020, <a href="https://twitter.com/kabergstrom">@kabergstrom</a> and I explored how <a href="https://github.com/TomGillen/legion">legion</a> and <a href="https://github.com/amethyst/atelier-assets">atelier-assets</a> could be integrated together, particularly in the context of implementing an editing workflow. Some of the goals we started with are here: <a href="https://community.amethyst.rs/t/rich-editing-experience-using-atelier-assets-and-legion/1263">Rich Editing Experience Using atelier-assets and legion</a>.</p><p>After we produced a working prototype implementing interactive editing, including support for undo and redo, I reworked my own <a href="https://github.com/aclysma/minimum">engine</a> to use it.</p><p>Video: <a href="https://www.youtube.com/watch?v=9Vwi29RuQBE&amp;feature=youtu.be">https://www.youtube.com/watch?v=9Vwi29RuQBE&amp;feature=youtu.be</a></p><p>Github: <a href="https://github.com/aclysma/atelier-legion-demo.git">https://github.com/aclysma/atelier-legion-demo.git</a></p><p>This document demonstrates what using the API feels like and discusses the lessons learned during implementation.</p><p>As a quick feature run-down, the demo supports:</p><ul><li>Loading and saving the edited state as a prefab</li><li>Hot-reloading the edited state when the file changes</li><li>Undo and Redo</li><li>Creating/Deleting entities</li><li>Adding/Removing components</li><li>Multiple selection</li><li>Drag to transform, scale, and rotate</li><li>Rendering and physics components respect transform, scale, and rotate component data.</li></ul><p>In order to try the demo for yourself, you can do something like this:</p><pre><code>git clone https://github.com/aclysma/atelier-legion-demo.git
cd atelier-legion-demo
git submodule init
git submodule update
cargo run
</code></pre><h1 id="cloneable-and-non-cloneable-components">Cloneable and Non-Cloneable Components</h1><p>The demo contains components that represent position, rotation, and scaling. Additionally, it has a few components for rendering and physics.</p><p>These components can be divided into two categories - cloneable and non-cloneable.</p><figure class="kg-card kg-image-card"><img src="https://blog.aclysma.com/content/images/2021/07/b09fc98cafd254048784ffae45671c083958637a_2_624x312.jpeg" class="kg-image" alt loading="lazy" width="624" height="312" srcset="https://blog.aclysma.com/content/images/size/w600/2021/07/b09fc98cafd254048784ffae45671c083958637a_2_624x312.jpeg 600w, https://blog.aclysma.com/content/images/2021/07/b09fc98cafd254048784ffae45671c083958637a_2_624x312.jpeg 624w"></figure><p>The components in this image are examples and don&#x2019;t necessarily match the demo</p><h2 id="cloneable-components">Cloneable Components</h2><p>Cloneable components must implement a number of traits:</p><ul><li>Clone - Used for cloning edit-time data into the runtime world</li><li>Serialize/Deserialize - Used for saving/loading data in the editor</li><li>Default - Used when adding a component to an entity to determine initial state</li><li>PartialEq - Required for SerdeDiff&#x2026;</li><li>SerdeDiff - SerdeDiff lets us determine what changed in user-edited data</li><li>TypeUuid - In our implementation, we use UUIDs to identify types in a registry.</li></ul><p>If a structure implements the above traits, then it can be used to represent a component at all stages of the pipeline - editing, loading, and running.</p><p>One example of this would be a Position component. It might be defined like this:</p><pre><code class="language-rust">#[derive(
    Clone, Serialize, Deserialize, Default, 
    PartialEq, SerdeDiff, TypeUuid
)]
#[uuid = &quot;8bf67228-f96c-4649-b306-ecd107194cf0&quot;]
Struct PositionComponent {
    position: Vec3
}
</code></pre><p>The PositionComponent structure defines the format of positions at edit/load time as well as at runtime in the shipped game.</p><h2 id="non-cloneable-components">Non-Cloneable Components</h2><p>Sometimes, components at runtime won&#x2019;t be able to implement some of these traits. A common case is data within the component that is not cloneable or serializable. For example, a physics component that represents a rigid body attached to the entity might need a handle to the rigid body in a physics engine.</p><p>This clearly can&#x2019;t be serialized as it would be meaningless once deserialized. Further, the data required to describe how to create the rigid body is not the same as the data required to represent the rigid body once it has been created.</p><p>In order to support this, we have the concept of ComponentDefinitions. The ComponentDefinition is used for editing and loading and the actual Component is only used in the game world at runtime.</p><pre><code class="language-rust">// This is the edit-time representation, it must support
// a number of traits
#[derive(
    Clone, Serialize, Deserialize, Default, 
    PartialEq, SerdeDiff, TypeUuid
)]
#[uuid = &quot;8bf67228-f96c-4649-b306-ecd107194cf1&quot;]
pub struct RigidBodyBallComponentDef {
   pub radius: f32,
   pub is_static: bool,
}

// Runtime data, no derives required for this!
pub struct RigidBodyComponent {
   pub handle: DefaultBodyHandle,
   delete_body_tx: crossbeam_channel::Sender&lt;DefaultBodyHandle&gt;,
}
</code></pre><p>In this example, the handle points to a rigid body stored in an nphysics world.</p><p>It&#x2019;s important to note here, for non-cloneable components, the end-user does not edit actual component data - they edit the component definition. So from an end-user&#x2019;s perspective, they just see <code>radius</code> and <code>is_static</code>as editable fields.</p><h3 id="transforming-from-definitions-to-components">Transforming from Definitions to Components</h3><p>We support three methods for a downstream user to transform a component definition into a real components:</p><h4 id="via-into-from">Via Into/From</h4><p>If an end-user implements the standard library&#x2019;s Into or From, the components can simply be registered like this:</p><pre><code class="language-rust">registry.add_mapping_into::&lt;RigidBodyBallComponentDef, RigidBodyComponent&gt;();
</code></pre><p>The engine will do the equivalent of&#x2026;</p><pre><code class="language-rust">let component = component_definition.into();
</code></pre><p>&#x2026;to spawn the component</p><h4 id="via-spawninto-spawnfrom">Via SpawnInto/SpawnFrom</h4><p>While using Into/From is convenient and familiar to many, it does not allow us to pass extra data for the end user&#x2019;s implementation to use. In order to support this, we have parallel traits SpawnInto/SpawnFrom that mimic Into/From, but allow the end user to access other entity or system data.</p><pre><code class="language-rust">/// Trait for mapping one type into another with world.clone_from()
pub trait SpawnInto&lt;IntoT: Sized&gt;
where
   Self: Sized,
{
   fn spawn_into(
       src_world: &amp;World,
       src_component_storage: &amp;ComponentStorage,
       src_component_storage_indexes: Range&lt;ComponentIndex&gt;,
       resources: &amp;Resources,
       src_entities: &amp;[Entity],
       dst_entities: &amp;[Entity],
       from: &amp;[Self],
       into: &amp;mut [MaybeUninit&lt;IntoT&gt;],
   );
}
</code></pre><p>One expected usage would be looking up position/rotation/scaling components on the entity to properly place the rigid body into the world. Another expected usage includes looking up a system. In the case of a rigid body component, we might need write access to the physics world so that we can insert the rigid body and get a handle to it.</p><p>The SpawnInto/SpawnFrom traits operate on blocks of data at a time. For example, if a prefab contains many entities with RigidBody components, construction of those components can be batched.</p><h3 id="via-closure">Via Closure</h3><p>We also support using a closure, equivalent to the SpawnFrom/SpawnInto trait</p><pre><code class="language-rust">clone_merge_impl.add_mapping_closure::&lt;RigidBodyBoxComponentDef, RigidBodyComponent&gt;(|
   src_world,
   src_component_storage,
   src_component_storage_indexes,
   resources,
   src_entities,
   dst_entities,
   src_data,
   dst_data
| {
   // implement here
};
</code></pre><p>In practice, since the closure needs to take so many parameters, using the SpawnFrom/SpawnInto trait ends up being cleaner. However, it could be useful for cases where it&#x2019;s not possible to implement the trait due to Rust&#x2019;s orphaning rules.</p><h1 id="diffing-components">Diffing Components</h1><p>In order to implement the demo, we needed a way to detect and reproduce changes to data in a general way. We published a new crate, <a href="https://github.com/amethyst/serde-diff.git">serde-diff</a>, that allows two instances of the same struct to be compared, resulting in a Diff. The Diff is serializable/deserializable and can be re-applied to other instances of the same struct. This is used for two major features - transactions and prefabs.</p><h2 id="transactions">Transactions</h2><p>In the demo, the editing tools do not modify world data directly. Instead, when a tool needs to modify state, it creates a transaction. Any entities that will be modified are added to the transaction. This allows the transaction to copy entity data into two new legion worlds - a baseline &#x201C;before&#x201D; state that is immutable, and the mutable &#x201C;after&#x201D; state.</p><pre><code class="language-rust">// Example of creating a transaction
let tx = TransactionBuilder::new()
    .add_entity(entity_one)
    .add_entity(entity_two)
    .begin(universe, world, clone_impl);
</code></pre><p>Most of the time the transaction will just operate on whatever is selected in the editor. In the demo, we have a shorthand for this.</p><pre><code class="language-rust">// Create a transaction - this helper function adds all 
// the selected entities to the transaction
let tx = editor_ui_state.create_transaction_from_selected(
    &amp;*editor_selection,
    &amp;*universe_resource,
);
</code></pre><p>The end-user&#x2019;s code can then modify the transaction&#x2019;s world freely. This code that performs the edit doesn&#x2019;t need to be aware of the transaction - just the transaction&#x2019;s &#x201C;after&#x201D; legion world (likely passed via mutable ref).</p><pre><code class="language-rust">// Adding, deleting, and modifying entity data is supported here
tx.world_mut().delete_all();
</code></pre><p>Once the end-user&#x2019;s code runs, the transaction can be committed. The data owned by the transaction in the &#x201C;before&#x201D; and &#x201C;after&#x201D; worlds is compared to produce diffs. The diff data supports creating/destroying entities, adding/removing components, and modifying component data.</p><pre><code class="language-rust">// Now generate the necessary data to apply/revert the change
let tx_diffs = tx.create_transaction_diffs(component_registry);
</code></pre><p>The TransactionDiffs returned by create_transaction_diffs contains an &#x201C;apply&#x201D; set of diffs and a &#x201C;revert&#x201D; set of diffs.</p><p>These diffs can be used for several purposes:</p><ul><li>Applying changes to the runtime state</li><li>Sending the changes back to the atelier daemon to commit changes to disk, and possibly other connected devices</li><li>Implementing Undo/Redo</li></ul><h2 id="prefabs">Prefabs</h2><p>Because serde-diff allows us to capture and persist changes with per-field granularity, we can use it to implement prefabs. Prefabs can contain entities and references to other prefabs. The &#x201C;prefab references&#x201D; can also include diffs to be applied to components of specific entities in the referenced prefab.</p><p>Prefabs can be stored in two forms, cooked and uncooked.</p><h3 id="uncooked-prefabs">Uncooked Prefabs</h3><p>Uncooked prefabs are hierarchical and editor-friendly. In memory, an uncooked prefab contains a legion world with entity data and references to other prefabs. These prefab references also contain any diffs that would need to be applied to the referenced prefab.</p><h3 id="cooked-prefabs">Cooked Prefabs</h3><p>At runtime, we don&#x2019;t want to incur the cost of loading and tracking a prefab hierarchy or applying the diffs. To avoid the cost, we can flatten an uncooked prefab and all the other uncooked prefabs that it references into a single cooked prefab where all the data is stored in a legion world. Spawning such a prefab is straightforward - the data is simply cloned or transformed from the cooked prefab&#x2019;s legion world into the game world.</p><p>Currently, the demo is loading uncooked prefabs and cooking them &#x201C;in-game&#x201D;. In the future, the cooking process would be pulled into atelier assets and the game would only interact with cooked prefabs.</p><p>When we make this change, we can still use transaction diffs. The editor can immediately apply the diffs to in-memory cooked data, allowing for a responsive editor experience. (For example, selecting entities and dragging them to change their position.) Additionally, the editor can forward the diffs to the daemon, which can apply the diffs to the uncooked form (potentially to be saved to disk.)</p><h1 id="component-registration">Component Registration</h1><p>In order for Rust to emit the necessary code for cloning, creating diffs, applying diffs, etc., there must be a registry for all component types. Registering the component will cause rustc to emit all the necessary code to support contrustructing, transforming, and diffing components.</p><p>Additionally, this component registry can be used to implement the CloneImpl trait, required to use clone_from in legion.</p><h1 id="key-lessons-techniques-learned">Key Lessons/Techniques Learned</h1><h3 id="putting-everything-into-legion-worlds-works-well">Putting Everything into Legion Worlds Works Well</h3><p>We are using legion for storing data in uncooked prefabs, cooked prefabs, transactions, and runtime data. In order to copy and transform data between these worlds, we developed a new &#x201C;clone_from&#x201D; feature in legion.</p><p>This allows us to use a relatively small amount of code to accomplish quite a lot - and any fixes/improvements/tooling can potentially benefit all stages of the pipeline. Further, the onboarding process for using the engine is quicker since once someone has working knowledge of legion, they can comfortably interact with data across the entire pipeline.</p><h3 id="using-diffing-transactions-is-both-powerful-and-intuitive">Using Diffing/Transactions is both Powerful and Intuitive</h3><p>If someone wants to implement a new tool in the demo, they only need to know how to create a transaction and apply the change to a legion world. The lowers the barrier to contributing new features and the simplicity makes it likely that the tool will be robust from the start.</p><p>Using this API provides automatic support for undo/redo, a notoriously difficult and error prone feature to implement by hand.</p><h3 id="separating-creation-and-runtime-data-is-beneficial">Separating Creation and Runtime Data is Beneficial</h3><p>It&#x2019;s common that the data required to create a component is not the same as the data required to represent the component at runtime. Further, it&#x2019;s common for runtime data to not be cloneable, serializable, or both. (For example, any FFI type.)</p><p>Integrating a physics engine with an ECS is a common question that comes up in a community - and often the solution is awkward. But by separating the construction data and runtime data, and providing a way to see init data for other components (like position,) we produced a clean integration between nphysics and legion.</p><p>We believe that many systems with runtime handles can be made cleaner by maintaining this separation of initialization and runtime data.</p><h3 id="immediate-mode-ui-is-quick-and-easy-to-use">Immediate-Mode UI is Quick and Easy to Use</h3><p>For this project, we used imgui. We appreciated that we only needed to work in a single language to prototype UI, and that it&#x2019;s API is straightforward to use.</p><p>In addition to imgui, we have a simple immediate-mode shape drawing API that detects clicking and dragging. This made implementing interactive widgets in world space more straightforward.</p><p>Conceivably other interactive tools could be built on top of this fairly easily, and the code that implements it won&#x2019;t need to worry about coordinate systems, windowing, or input devices. It just knows that the line it asked to be drawn (using world-space coordinates) was dragged.</p><p>Generally, we believe that for an open source editor to work, it must be easy and straightforward to create tools that are efficient and reliable. New contributors need to be productive with little ramp-up time or help, and the code they produce needs to be easily readable by others. Coordinate space changes can be very tricky and removing the need to deal with this in every editor tool reduces the maintenance workload for everyone.</p><h2 id="unsolved-problems-future-work">Unsolved Problems/Future Work</h2><h3 id="editing-prefabs-by-hand">Editing Prefabs by Hand</h3><p>While the demo technically supports nested prefabs, the format they are stored with is not very human readable. Currently, the data for specifying component overrides for an entity in a referenced prefab is stored like this:</p><pre><code>component_overrides: [
   (
       component_type: &quot;f5780013-bae4-49f0-ac0e-a108ff52fec0&quot;,
       diff: r##&quot;[ Enter(Field(&quot;position&quot;)), Value(Vec2(300.0, 300.0)) ]&quot;##,
   ),
],
</code></pre><p>In this case, the component_type guid indicates that it&#x2019;s a Position component, and the diff field describes a sequence of enter/value/exit commands.</p><p>While a sequence of commands is runtime performance friendly (aside from using strings), any non-trivial example becomes painful to read and write in a text editor. When saving this data in user-readable formats like RON, we would like to explore saving it in a more familiar hierarchical form. For example, <code>[Enter(Field(&#x201C;Circle&#x201D;)), Enter(Field(&#x201C;Radius&#x201D;)), Value(5.0)]</code> could be represented as <code>{ Circle: { Radius: 5.0 } } or { &#x201C;Circle.Radius&#x201D;: 5.0 }</code></p><p>It should be possible to convert between commands and either of the other forms. So we believe this to be a very solvable problem, just a matter of putting in some time to implement it. To generalize, we want serde_diff to support both a human-readable format and a machine-readable format.</p><h3 id="editing-prefabs-with-a-ui">Editing Prefabs with a UI</h3><p>Currently, we do not support any form of prefab editing. All changes are applied directly to the opened prefab entities.</p><p>Designing a UI to work well with this is a lot of work and ended up being out of scope for this demo. Much of the groundwork to create such a UI is laid with the APIs for prefab cooking being implemented in the demo and this is an area that is ripe for experimentation and prototyping.</p><h3 id="entity-references">Entity References</h3><p>It&#x2019;s not uncommon for one entity to need to reference another entity. For example, a heat-seeking missile meant to follow a player in a game might be implemented as a missile entity and a player entity, and the missile entity might have a component that needs to reference the player entity.</p><p>Currently, when we clone merge components from one legion world to another, any Entity stored in a component is naively copied by value. It still refers to an entity in the old world. Ideally, we could detect that an entity reference exists in component data and fix the copy in the new world to point to the copied entity in the same (new) world.</p><p>We don&#x2019;t want to add complexity to legion&#x2019;s Entity type, so we are considering adding a new type, EntityHandle. We could use the same technique as we use for asset handles where we store context data in TLS. This would allow serialization/deserialization to look up what a particular Entity reference should be changed to, and we can use a custom Clone impl to patch the reference as it is cloned.</p><h3 id="sharing-editor-code">Sharing Editor Code</h3><p>Ideally we&#x2019;d like to wrap up the editing tools in this demo in a way that is reusable. (For example, dragging an entity to change the position, or just detecting that an entity has been clicked.)</p><p>As it is now, if someone wants to use the editing tools in the demo, they would need to copy the code and modify it to use their math and input libraries of choice. This will make it difficult for us as a community to share tooling improvements.</p><p>Unfortunately, the editor code needs to be aware of coordinate systems, input, and windowing code. Much of the choices for these things are opinionated and game-specific.</p><p>We haven&#x2019;t done much work on this yet, but we are hoping that we can insert a layer of abstraction using a trait object to handle this. The reusable editing tools could then delegate the opinionated and game-specific logic to a trait object provided by the user.</p><h3 id="saving-edited-data-to-disk">Saving Edited Data to Disk</h3><p>Atelier currently does not support writing modified data back to disk. While we do have a plan for implementing this (see the &#x201C;Prefabs&#x201D; section) it requires further work in atelier to support it.</p>]]></content:encoded></item><item><title><![CDATA[A Personal, Opinionated Guide to the Rust Game Development Ecosystem]]></title><description><![CDATA[<p>The <a href="https://github.com/rust-gamedev/wg">Rust Game Development Working Group</a> has been <a href="https://github.com/rust-gamedev/wg/issues/41">investigating creating an ecosystem guide</a>, in a similar vein to <a href="http://arewegameyet.com">arewegameyet.com</a>. If there is one thing we have consensus on, it&apos;s that we want it to be impartial and <em>not</em><strong> </strong>opinionated.</p><p>However, there <em>is</em> value in having opinionated guides</p>]]></description><link>https://blog.aclysma.com/personal-guide-to-rust-gamedev-ecosystem/</link><guid isPermaLink="false">60f0b57f7c011ff4a132a44e</guid><category><![CDATA[rust]]></category><category><![CDATA[gamedev]]></category><dc:creator><![CDATA[Philip Degarmo]]></dc:creator><pubDate>Sun, 11 Aug 2019 03:49:17 GMT</pubDate><content:encoded><![CDATA[<p>The <a href="https://github.com/rust-gamedev/wg">Rust Game Development Working Group</a> has been <a href="https://github.com/rust-gamedev/wg/issues/41">investigating creating an ecosystem guide</a>, in a similar vein to <a href="http://arewegameyet.com">arewegameyet.com</a>. If there is one thing we have consensus on, it&apos;s that we want it to be impartial and <em>not</em><strong> </strong>opinionated.</p><p>However, there <em>is</em> value in having opinionated guides to the ecosystem, even if the working group isn&apos;t the right place for it. It was proposed that individuals could write their own guides to fill this purpose. So here&apos;s mine!</p><p>I&apos;ve only been involved in the Rust community for a few months, so I haven&apos;t actually <em>used</em> that many of these. However, I&apos;ll list out where I would point someone if they asked.</p><h2 id="all-in-ones">All-In-Ones</h2><p>My personal preference is to find things that do one thing well and glue them together. But, if I wanted to ship something ASAP in Rust, I&apos;d probably start with <code>ggez</code>, mostly because it&apos;s based on an existing framework. Or SDL2 if you want something battle-tested and don&apos;t mind native code</p><!--kg-card-begin: markdown--><ul>
<li><code>ggez</code> - It&apos;s been around for a while, and it&apos;s based on an existing technical design (<a href="https://love2d.org">L&#xD6;VE</a>). It also has clearly defined scope. If I were looking for a single library to meet broad but basic needs, I would start here.</li>
<li><code>amethyst</code> - This is a big ambitious project, and clearly a lot of good work has gone on here. They even have some sponsors!
<ul>
<li>The scope is very ambitious, and until recently it wasn&apos;t clear if there was much practical usage to help inform the technical design. However, they recently announced two showcase games. I&apos;m hoping this will help prioritize the minimum required features for this project to see real-world usage.</li>
<li>Several reusable libraries (<code>rendy</code>, <code>sheep</code>, <code>laminar</code>) have come from this community already. This has been to the benefit of the broader ecosystem.</li>
<li>I wouldn&apos;t discourage anyone from giving this one a try.</li>
</ul>
</li>
<li><code>sdl2</code> - Putting Rust logic on top of proven, shipped C code is a legitimate strategy.</li>
<li><code>coffee</code> - Worth keeping an eye on! It&apos;s still... <em>brewing</em>.</li>
<li><code>piston</code> - Mentioned for completeness because it&apos;s been around for a long time and it has lots of downloads on crates.io. But the technical design, vision, and scope does not seem as well-defined as amethyst or ggez.</li>
</ul>
<!--kg-card-end: markdown--><h2 id="low-level-rendering">Low-Level Rendering</h2><p><a href="https://wiki.alopex.li/AGuideToRustGraphicsLibraries2019">icefoxen</a>&apos;s guide is more detailed than what I intend to do here, so I highly recommend giving that one a look. </p><p>First, you need a window to draw on. You will almost certainly use <code>winit</code> and most (all?) of the below build on that. <em>(May 2020 edit: I&apos;ve switched to using <code>sdl2</code> for window management)</em></p><p>Once you have a window, there are a few options:</p><ul><li>There are wrappers around C-APIs if you want to write DirectX, Vulkan, etc. directly. (<code>ash</code>, <code>winapi/d3d12-rs</code>, <code>gl-rs</code>, <code>metal-rs</code>)</li><li>There is a Vulkan-like API <code>gfx-hal</code> that abstracts all these that quite a few people are using. It makes no attempt to be safe. There&apos;s a good <a href="https://github.com/Lokathor/learn-gfx-hal">tutorial</a> available for this one.</li><li>The amethyst crew recently put out <code>rendy</code>. It sits on top of <code>gfx-hal</code> and takes care of a lot its boilerplate, but without hiding <code>gfx-hal</code> itself. You&apos;ll still need to write some &quot;unsafe&quot; code.</li><li>There are a couple &quot;safe&quot; (mostly) crates around OpenGL, <code>glium</code> and <code>luminance</code>. And <code>gfx</code> (before it became <code>gfx_hal</code>) attempted to be a safe API as well.</li><li><em>(July 2020 edit: I&apos;ve been working on <a href="https://github.com/aclysma/renderer_prototype">my own renderer</a>)</em></li></ul><p>I&apos;m personally using Rendy, and I think <code>gfx-hal</code> and <code>rendy</code> are likely to be broadly adopted and supported long term. <em>(May 2020 edit: I&apos;ve switched to using ash/vulkan directly)</em></p><p>For higher level rendering, you could use <code>sdl2</code>, one of the above all-in-ones, or if you just want some shapes (pong?) maybe even wrap something like <code>skia</code>. There&apos;s even some terminal rendering libraries like <code>tui-rs</code> if you want to make something truly old-school. <em>(May 2020 edit: I released <a href="https://github.com/aclysma/skulpin">Skulpin</a> last year which embeds Skia into a Vulkan-backed window. It&apos;s even getting some <a href="https://github.com/Kethku/neovide">real use</a>!)</em></p><h2 id="ecs">ECS</h2><p>If you don&apos;t know what this is, I&apos;d <a href="https://www.youtube.com/watch?v=aKLntZcp27M">watch this video</a>. ECS designs have their own merit, but aside from those benefits, specifically in Rust, they provide a good foundation that is relatively friendly to the borrow-checker.</p><ul><li><code>specs</code> is by far the most popular. It&apos;s a great place to start. There are some good ideas in <code>legion</code> too.</li><li>For a while I used <code>shred</code> - which is basically <code>specs</code> without the entities/components.</li></ul><p>I ended up doing my own thing, but it&apos;s too early to recommend it to anyone in good conscience. <em>(May 2020 edit: I&apos;ve switched to legion, highly recommended!)</em></p><h2 id="math">Math</h2><p>There was a lot of good discussion <a href="https://github.com/rust-gamedev/wg/issues/25">here</a> about the state of math libraries in Rust.</p><ul><li><code>nalgebra</code> is complete, well documented, and likely to be maintained for a long time. However, in my opinion, it is overly general for gamedev. <code>nalgebra-glm</code> is a wrapper that pairs most of that back.</li><li>If you want something lower level, look at <code>glam</code>. It&apos;s a bit more efficient too.</li><li>In my opinion, the ideal math crate for <strong>lowest-level</strong> gamedev math in Rust does not exist yet. If I were to build it myself, I would port <code>DirectXMath</code> without attempting to be Rust idiomatic. Then I&apos;d put a wrapper around it that looks more like glam. <em>(May 2020 edit: Using <code>glam</code> for now!)</em></li></ul><h2 id="physics">Physics</h2><ul><li><code>nphysics</code> is a solid default choice. I think it has a bright future ahead of it. It uses nalgebra, so using both of them together is a natural choice.</li><li>You could also go with <code>bullet</code> or <code>box2d</code>. I&apos;m not sure what the state of using this in Rust would be. Bullet has heavy integration with python, so I expect their C bindings are fairly complete. Embark very recently released some <code>physx</code> bindings as well.</li></ul><h2 id="sound">Sound</h2><p>I haven&apos;t gotten far enough along to care about audio yet. There are some audio crates (<code>cpal</code> and <code>rodio</code>), but I haven&apos;t heard glowing reviews for any of them. I&apos;d consider wrapping some C/C++ code. First places I&apos;d look are <code>sdl2</code>, SoLoud, FMOD (not open source), and OpenAL.</p><h2 id="networking">Networking</h2><p>Networking in gamedev is a really complex topic. It&apos;s actually my day job. But I haven&apos;t gotten far enough along to try anything myself in Rust yet.</p><p>I&apos;m going to consider backend systems out of scope for the time being. And with async/futures landing imminently, the state of that ecosystem is likely to change. (keep an eye on <code>tokio</code>)</p><p> For replicating simulations:</p><ul><li>Amethyst is working on <code>laminar</code> but I&apos;m not sure how far along they are.</li><li>The fastest path to ship something today is probably going to be opening a TCP socket and doing it yourself. Some kinds of games won&apos;t work well on TCP, but many will.</li><li>But if you want to use UDP, <code>enet</code> will at least get you started with a reliable UDP implementation with flow control.</li></ul><h2 id="honorable-mentions">Honorable Mentions</h2><ul><li>(May 2020 edit: <code><a href="https://github.com/amethyst/atelier-assets">atelier-assets</a></code> makes a great asset pipeline although it may be overkill for some people)</li><li><code>imgui-rs</code> is awesome. I&apos;m using it. In its current form you may need some unsafe code to make it easier to use. </li><li><code>serde</code> is a flexible serialization library</li><li><code>strum</code> for turning enums into strings, and counting the number of elements in an enum</li><li><code>named_type</code> for getting names out of types at runtime</li><li><code>quote</code> and <code>syn</code> to get compile-time reflection (this is deserving of a blog post later)</li><li><code>log</code> and <code>env_logger</code> for a basic logging framework. (but <code>tracing</code> looks promising)</li><li><code>lazy_static</code> for those times you really need a global</li><li>If you need something from C/C++ likely someone already wrapped it for you! For example, I ported some code to rust that used <code>gpc</code> - I was able to drop that into Rust and it worked immediately.</li><li><code>image</code> is the unsung hero of loading textures</li><li><code>sheep</code> for sprite sheet processing (it&apos;s pretty new!)</li></ul><h2 id="final-comment">Final Comment</h2><p>I will probably write something more about this later, but dependency management is one area where Rust shines. I expect that this will enable the community to build many small, high quality, single-purpose libraries that do one thing well. I think this will be key in the formation of a vibrant ecosystem that can support a broad variety of games and creators.</p>]]></content:encoded></item><item><title><![CDATA[My First Three Months with Rust​]]></title><description><![CDATA[I’ve used C++ professionally in games and simulations for over 10 years, and in the past few years I’ve also used C# to build distributed backend systems.

Lately, I’ve been exploring rust.]]></description><link>https://blog.aclysma.com/my-first-three-months-with-rust/</link><guid isPermaLink="false">60f0b57f7c011ff4a132a44d</guid><category><![CDATA[rust]]></category><category><![CDATA[gamedev]]></category><dc:creator><![CDATA[Philip Degarmo]]></dc:creator><pubDate>Wed, 07 Aug 2019 19:13:41 GMT</pubDate><content:encoded><![CDATA[<p>I&#x2019;ve used C++ professionally in games and simulations for over 10 years, and in the past few years I&#x2019;ve also used C# to build distributed backend systems.</p><p>Lately, I&#x2019;ve been exploring rust.</p><h2 id="why-rust">Why Rust?</h2><p>My interest in Rust grew as I became aware of these three facts:</p><ol><li>Rust has been the &#x201C;most loved&#x201D; language in the <a href="https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted">stack overflow developer survey</a> four years in a row.</li><li>Rust is a memory-safe language with <a href="https://benchmarksgame-team.pages.debian.net/benchmarksgame/which-programs-are-fastest.html">performance comparable with C++</a>! (It in fact goes through the same optimizer that clang uses, LLVM) (<a href="https://www.techempower.com/benchmarks/">See also latest techempower benchmarks</a>)</li><li>Rust carries forward two very important features of C++: &#xA0;destructors, and <code>const</code>-ness.</li></ol><h2 id="my-favorite-feature-in-c-is-back-">My Favorite Feature in C++ is Back!</h2><p>Memory, locks, file handles, database transactions, TCP sockets: Good software engineering is all about resource management.</p><p>In my opinion, the single most important feature of C++ is the destructor. <a href="https://en.cppreference.com/w/cpp/language/raii">RAII-style programming</a> leverages the destructor to ensure that cleanup code always runs. Further, it&apos;s clearly defined <strong>when</strong> it will run. For many of these resources, the timing is crucially important.</p><figure class="kg-card kg-code-card"><pre><code class="language-cpp">void write_to_db(DatabaseConnection &amp;connection)
{
    Transaction tx = connection.StartTransaction();
    Data d = get_data();
    tx.write_data(d);
    
    // * Transaction has a destructor, so we can&apos;t forget 
    //   to clean it up.
    // * Even if get_data() throws an exception, it is still 
    //   guarateed to be cleaned up!
    // * Any code that run after leaving this function can safely
    //   assume the transaction is written
}</code></pre><figcaption>C++ destructors are an invaluable tool for writing correct code! They can ensure that transactions are committed, files and sockets are closed, and memory/locks are released.</figcaption></figure><p>I&apos;m having a hard time thinking of a recent popular language that isn&apos;t garbage collected. I think garbage collection can be a good solution for managing memory in many cases, but I also believe that <strong>garbage collection is a targetted solution for memory management that ignores the general problem of resource management.</strong></p><h2 id="const-">const++</h2><p>Rust has the concept of immutability, and when I first looked at the language, I thought that the <code>mut</code> keyword was roughly equivalent to not-being-const in C++. (In Rust, dangerous features are opt-in, rather than opt-out.) But as it turns out, rust takes the concept further.</p><p>Many languages (like C++) are not particularly &#x201C;aware&#x201D; of threads. Sure, you can call an API that will make the OS spawn a new thread, executing your code. But there is no static analysis that reasons about that thread, and there are no language facilities to add helpful annotation for that analysis. <strong>Most languages make no effort to help you write correct multi-threaded code.</strong></p><figure class="kg-card kg-code-card"><pre><code class="language-rust">use std::thread;
fn main() {
    let mut numbers = vec![17, 42, 5];
    thread::spawn(move || { 
        //        ---- &lt;-- Notice the move keyword!
        numbers[0] = 2;
        println!(&quot;The first number is now {}&quot;, numbers[0]);
    });

    // A subtle problem.. this push could cause the Vec to allocate
    // a new buffer. The other thread could read/write to this buffer
    // during this time, resulting in undefined behavior!
    numbers.push(20);
}</code></pre><figcaption>This dangerous code will not compile in Rust!</figcaption></figure><p>ReadWrite locks are a common and useful synchronization primitive, and Rust somewhat bakes this into the language. Holding an immutable reference to string is a bit like holding a read lock, and having a mutable reference is a bit like holding a write lock. However, all of this happens at compile time. Rust has a powerful static analysis system (people call it the &#x201C;borrow-checker&#x201D;) that ensures the written code never violates the constraint of &quot;many readers, or one writer, but never at the same time.&quot;</p><p>The type system is even aware of &#x201C;moving&#x201D; data across threads, and can provide compile-time errors for when, for example, an OpenGL context gets shared across a thread boundary.</p><p>By the way, Rust&apos;s memory model also allows it to aggressively use <code>noalias</code> &#x2013; so it&apos;s entirely plausible for Rust to be <em>faster</em> than C++ on average, despite using the same optimizer. <a href="https://github.com/rust-lang/rust/issues/54878">(Well, if it weren&apos;t for bugs in llvm, that is.)</a></p><h2 id="free-lunch">Free Lunch?</h2><p>And here we come to the downside. Rust is not an easy language. The static analyzer must be able to understand your code, or you have to opt-out of the safety it provides. Lifetime annotation in Rust is powerful, but it is a new and complex language concept. Some designs work well with it, and some don&#x2019;t. Even some &quot;sound&quot; designs are just not practical to use in Rust.</p><p>But it&apos;s not all bad. <strong>My experience so far has been that when code is sufficiently complicated that the borrow checker cannot validate it, it&#x2019;s a code smell.</strong> But when the code can be validated, it very often works on the first try. That&apos;s a great property to have in a language! Designs that work well with the borrow checker are safe and tend to be very maintainable code.</p><h2 id="scalability">Scalability</h2><p>When I say &#x201C;scalability&#x201D; in the context of a language - what I mean is the ability of a codebase and team to change and grow in size, without diminishing returns of productivity. Requirements change, and code routinely needs to be refactored. Ideally, our tools for detecting errors in code are thorough enough that we can change our code without fear.</p><p>Dynamically-typed languages like python and javascript are not scalable. I&apos;m amazed that the linting tools for python and javascript work as well as they do, but they simply cannot match a typesafe language&apos;s ability to find silly bugs as early as possible.</p><p>While C++ is not dynamically typed, it has it&apos;s own major scalability problem. Just as renaming a variable can cause unexpected runtime errors in a dynamically typed language, so also can altered memory access patterns cause unexpected runtime errors in a C++ application. This can lead to all sorts of unpleasant surprises at runtime.</p><p>Memory usage semantics should be part of the API, both for readability, and for compile-time verification. Here&#x2019;s a C++ example to illustrate:</p><figure class="kg-card kg-code-card"><pre><code class="language-cpp">void the_function(char *buffer);
void the_function(char &amp;buffer);
void the_function(std::unique_ptr&lt;char *&gt; buffer);</code></pre><figcaption>A few different ways to pass a pointer, each with their own semantics.</figcaption></figure><p>These are all different ways to effectively pass a pointer. But an experienced C++ developer could intuit certain things from the second and third case, where the first case would be ambiguous. Rust makes these semantics explicit, and enforces them.</p><p>This is not only beneficial to teams, but also the OSS community in general. When semantics for memory handling and concurrency are part of the API, breaking upstream changes are much more likely to be caught!</p><h2 id="the-inflection-point">The Inflection Point</h2><p>It&#x2019;s easy to speak of Rust as a language, but it&#x2019;s probably more correct to consider it as an ecosystem. For-profit ventures require libraries for common functionality, tools for enhancing productivity, and a talent-pool to hire from. Deficiencies in these and other areas represent risks to a project, and every organization has its own tolerance for risk.</p><p>However, I think this ecosystem is going to be big. As long as people <em>enjoy</em> working in it (and apparently they do, <a href="https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted">for</a> <a href="https://insights.stackoverflow.com/survey/2017#most-loved-dreaded-and-wanted">four</a> <a href="https://insights.stackoverflow.com/survey/2018#most-loved-dreaded-and-wanted">years</a> <a href="https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted">running</a>!), more libraries will be written, the tooling will get better, and the talent pool will grow. I&#x2019;d like to see a bit more corporate investment, and not just from mozilla. But even in the last half year, there have been promising signs from Microsoft, Facebook and Amazon.</p><ul><li><a href="https://msrc-blog.microsoft.com/2019/07/22/why-rust-for-safe-systems-programming/">Microsoft Security Response Center endorsed Rust in a recent blog series</a> (&quot;Rust represents the best alternative to C and C++ currently available.&quot;)</li><li><a href="https://users.rust-lang.org/t/facebook-libra-is-written-in-rust/30672">Facebook&#x2019;s new cryptocurrency is implemented in Rust</a></li><li><a href="https://firecracker-microvm.github.io">Amazon is using Rust for virtualization technology</a></li></ul><p>I think Rust is in an incredible position for exponential growth. I&apos;m very excited about the ecosystem&apos;s future!</p>]]></content:encoded></item></channel></rss>