Rust Bytes: Bevy, an open-source data-driven game engine built in Rust
Ferris the crab mascot - Image courtesy of tweedegolf.nl
Hello Rustacean! Welcome to another edition of the Rust Bytes newsletter. In this issue, we'll shine a spotlight on an amazing Rust project, present our spot-the-bug challenge, and share some incredible links of the week.
Welcome to Issue 14!
The Main Thing
Bevy is a refreshingly simple data-driven game engine built in Rust. It provides a ton of features, some of them are:
Free and Open Source: Bevy is 100% free. Forever and always open-source under the permissive MIT or Apache 2.0 licenses
Data Driven: All engine and game logic uses Bevy ECS, a custom Entity Component System that is massively parallel, cache-friendly, simple and capable.
2D and 3D Renderers: Bevy tackles both 2D and 3D rendering for your games and apps.
Cross Platform: Bevy supports all the major platforms: Windows, MacOS, Linux, Web, iOS, Android.
Hot Reloading: Bevy gives instant feedback on your changes without app restarts or recompiles.
Productive Compile Times: Game development is an iterative process and fast compilation is a must. With Bevy you can expect 0.8-3.0 seconds with the "fast compiles" configuration.
Bevy is open-source on Github.
Rust Pun
Failure is not an Option<T>, it's a Result<T,E>.
Spot the Bug
The Curious Case of the allocation.
Identify why the code fails to compile and suggest a way to fix it.
Share your solution in the comments below for a chance to be featured in our next newsletter!
Project Spotlight
TiKV
TiKV is an open-source, distributed, and transactional key-value database. Unlike other traditional NoSQL systems, TiKV not only provides classical key-value APIs, but also transactional APIs with ACID compliance.
TiKV has the following key features:
Geo-Replication: TiKV uses Raft and the Placement Driver to support Geo-Replication.
Horizontal scalability: With Placement Driver (PD), and carefully designed Raft groups, TiKV excels in horizontal scalability and can easily scale to 100+ TBs of data.
Consistent distributed transactions: Similar to Google's Spanner, TiKV supports externally-consistent distributed transactions.
Coprocessor support: Similar to HBase, TiKV implements a coprocessor framework to support distributed computing.
Cooperates with TiDB: Thanks to the internal optimization, TiKV and TiDB can work together to be a compelling database solution with high horizontal scalability, externally-consistent transactions, support for RDBMS, and NoSQL design patterns.
The project is open-source on GitHub.
Awesome links of the week
Bo Lin, Alexander Bogdanowicz, and Lukas Schulte share their experience of using Rust in building a SQL compiler, semantic analyzer, and data build system in their blog Fast Development In Rust, Part One.
Sam Van Overmeire builds a procedural macro to replace panic by using
syn’s Fold trait
. Read it here.Vitaly Bragilevsky goes beyond the basics of Rust iterators in his article.
Ever thought of splitting a Rust project in a multi-crate project? Check out Gabor Szabo’s blog on Rust multi-crate project in a monorepo.
crates.io has been growing rapidly, with download and package counts increasing 2-3x year-on-year. This growth is really inspiring but it does introduce scaling challenges because all the download requests go through the crates.io API. Read about the scaling challenge and the solution in crates.io: Download changes.
Would you like to automate your Cargo project configuration? Check out cargo-wizard that simplifies the configuration of Cargo projects for maximum runtime performance, fastest compilation time or minimal binary size.
Check out the conversation between Lizzie Holmes and Dr Caroline Morton to learn of Dr Caroline Morton’s journey from a medical doctor to a Rust developer.
Watch the implementation of the billion row challenge in Rust by Tim McNamara.
Want to build a Web Server in Rust? Check Joshua Mo’s article on Building a Simple Web Server in Rust.
Read Google’s perspective on memory safety here.
Spot The Bug: Solution
Explanation:
The Bug: Compiler error!
The enum LinkedListNode contains two variants: Empty and NonEmpty.
The enum variant NonEmpty contains: i32 and LinkedListNode as its data. Rust can allocate the enum on stack, if its size is known at compile time, else users must make the heap allocation explicit.
To calculate the size of an enum, Rust compiler goes through all the variants and identifies the maximum size needed for a variant.
With LinkedListNode, Rust compiler checks the size needed for the variant Empty. It does not contain any data, so the compiler moves ahead to calculate the size of the variant NonEmpty. The size needed for the NonEmpty variant = sizeOf(i32) + sizeOf(LinkedListNode).
The definition of the enum is recursive and Rust can not calculate its size. So, the Rust compiler gives an error: "recursive type `LinkedListNode` has infinite size, recursive without indirection".
Solution:
To solve the issue, we must change the definition of the enum to allow Rust compiler to calculate its size. As the compiler suggested, we must introduce an indirection in the enum variant NonEmpty. One way to do that is to use Box<LinkedListNode> instead of LinkedListNode.
Box<T> is pointer that uniquely owns the heap allocation of type T.
#[derive(Debug)]
enum LinkedListNode {
Empty,
NonEmpty(i32, Box<LinkedListNode>),
}
fn main() {
let node = LinkedListNode::NonEmpty(
45,
Box::new(LinkedListNode::NonEmpty(
50,
Box::new(LinkedListNode::Empty)
)),
);
println!("{:?}", node)
}
With this change, Rust compiler can now calculate the size of the enum variant NonEmpty: sizeOf(i32) + sizeOf(Box pointer), which is 4 bytes for i32 + 8 bytes for a Box pointer on a 64 bit machine + padding.
Before You Go
To support the newsletter:
❤️ Recommend the newsletter to your friends: it really helps!
💸 Sponsor the newsletter
🤳 Check us out on our socials: X, Rustaceans Publication.
📨 Contact us through rustaceanseditors@gmail.com feedback is welcome
That's all for now, Rustaceans! Until next week, have a productive week ahead.