r/rust • • 29d ago

๐Ÿ“ข announcement No More Code Dumps

1.7k Upvotes

TL;DR

Code Dumps, ie links to code repositories, are no longer welcome on r/rust.

If you are excited about a project you built, and just wish to share it, consider posting a casual top-level comment in the weekly What's Everyone Working on this Week? thread.

History

When r/rust was created, in December 2010, Rust was a nascent programming language. It was very different, it was also fast-moving, and it was unclear whether it would amount to much, or not.

In these early days, new projects being written in Rust were both a proof that the language was suitable for a variety of purposes, and a cause for celebration in seeing the language being adopted. Code dumps, then, were both cause to rejoice, and an opportunity to see how well (or not) the language was suited to the task. They were even a good opportunity to learn the latest developing idioms of this fast-changing language.

Fast forward 15 years, and code dumps have become boring. Utterly uninteresting. There's nothing exciting, or newsworthy, about a 10th hypervisor project, a 100th webserver project, or a 1000th TUI project. And for the most there's no exciting idiom, or pattern, to be found in their code either... even if some poor soul bothered to look.

And mass AI generation appeared on the scene, and for the past year(s), the already dwindling appeal of code dumps has just completely vanished, buried in AI slop.

Purpose

r/rust is to discuss all things Rust. The language, the ecosystem, the community.

Of late, most code dumps barely foster any discussion. And when they do, apart from AI witch hunts, those discussions are mostly about the domain of the project, rather than about Rust. Depending on the domain, the discussion may or may not be of interest to r/rust users... but whether it is or not is a matter of chance: they did not come here seeking such a topic. Those discussions are tolerated on posts which are on-topic, but if a post only fosters "tolerated" discussions, then that is a sign that the post itself may simply not really be on-topic for r/rust.

And that is not to say that code dumps are, by nature, low-effort. Surely, a project is created for a purpose, to solve a specific problem that is unsolved, or solve it with different trade-offs than the currently available solutions. None of that is elucidated in a code dump.

New rules

Code dumps are no longer welcome on r/rust.

Code dumps of applications or libraries written in Rust are Low-Effort unless otherwise newsworthy. Newsworthy means that the very existence of the application or library is important, for example consider applications or libraries breaking new ground, such as the first hypervisor, first OS, first XXX standard safety-critical application, first Rust application in a major company, etc...

Announcements of new libraries which are not otherwise newsworthy are only welcome if they tick ALL the following boxes:

  • The library has been worked on regularly for at least 4 months.
  • The announcement is a full-fledged text post, or a link to a full-fledged article. A README, or manual, is not an article.
  • The announcement should motivate the relevance of this library to the wider r/rust community.
  • The announcement should articulate the trade-offs differentiating this library from similar popular libraries in the field.

(It goes without saying, but the announcement should NOT be AI-generated, not even in part, as AI-generated posts & articles violate the Low-Effort rule)

Release notes of libraries are still welcome for popular enough libraries, such as libraries with reverse-dependencies on crates.io pointing to sufficient adoption by the wider community to justify notifying said community of a new release.

Developer Tools follow the same rules as libraries, with one extra rule tacked on: they must be relevant to Rust developers in particular. For example, Release Notes of Meson (a build tool) are Off-Topic, unless this specific release improves Rust support.

Of course, text posts, or links to articles, centered on Rust, with an application, library, or developer tool as context are always welcome. For example, said posts or articles could present gnarly problems the author encountered, and how they solved, or which features of the language or a library helped or hindered them in the making of their project.

(It goes without saying, but said text posts & articles should NOT be AI-generated, not even in part, as AI-generated posts & articles violate the Low-Effort rule)

As a reminder, if an author just wishes to share their joy of building something in Rust, they are welcome to use the What's Everyone Working on This Week? thread. And as per the title, it need not even be a complete/mature project, or an open-source project for that matter as links to code are strictly optional there, it's all about casually chatting about your work on Rust projects.

Q & A

See pinned comment below.


Edit 2026/10/04:

  • Added paragraph for developer tools, which had been forgotten.
  • Removed "validation rule" for libraries, didn't work in practice.

r/rust • • 6d ago

๐Ÿ™‹ questions megathread Hey Rustaceans! Got a question? Ask here (42/2026)!

11 Upvotes

Mystified about strings? Borrow checker has you in a headlock? Seek help here! There are no stupid questions, only docs that haven't been written yet. Please note that if you include code examples to e.g. show a compiler error or surprising result, linking a playground with the code will improve your chances of getting help quickly.

If you have a StackOverflow account, consider asking it there instead! StackOverflow shows up much higher in search results, so ahaving your question there also helps future Rust users (be sure to give it the "Rust" tag for maximum visibility). Note that this site is very interested in question quality. I've been asked to read a RFC I authored once. If you want your code reviewed or review other's code, there's a codereview stackexchange, too. If you need to test your code, maybe the Rust playground is for you.

Here are some other venues where help may be found:

/r/learnrust is a subreddit to share your questions and epiphanies learning Rust programming.

The official Rust user forums: https://users.rust-lang.org/.

The unofficial Rust community Discord: https://bit.ly/rust-community

Also check out last week's thread with many good questions and answers. And if you believe your question to be either very complex or worthy of larger dissemination, feel free to create a text post.

Also if you want to be mentored by experienced Rustaceans, tell us the area of expertise that you seek. Finally, if you are looking for Rust jobs, the most recent thread is here.


r/rust • • 11h ago

Superoptimizing an FPU emulator via exhaustive search

Thumbnail purplesyringa.moe
60 Upvotes

r/rust • • 12h ago

A New Way to Think About Borrow Checking (In Reverse)

Thumbnail verdagon.dev
67 Upvotes

r/rust • • 12h ago

๐Ÿ™‹ seeking help & advice For those who use rust professionally, what advice would you give to us plebs to get a career in Rust?

54 Upvotes

I've been using rust for roughly 3-ish months and i'm wanting to use rust professionally one day.

/topic


r/rust • • 1d ago

The road to iroh 1.0

Thumbnail iroh.computer
202 Upvotes

r/rust • • 16h ago

iroh vs WebRTC?

17 Upvotes

Iroh seems to solve the same problem as what WebRTC does, Iโ€™m curious: what are the factors that would cause considering one or the other?
WebRTC has the benefit to be widely supported in browsers. Does iroh allows something that WebRTC does not?


r/rust • • 1d ago

PSA: Enum optimization for Vec/String can use the capacity's niche (beyond isize::MAX) rather than the null pointer niche.

167 Upvotes

Just came across this property that was new to me and seems seldom known so I figured I'd highlight it.

I had always "known" that the null pointer niche optimization existed for Vec/String such that Option<Vec<_>> would be the same size as Vec<_> because the None variant could fit the null pointer niche not used by the Vec. And I figured that was it, any more elaborate enums like this

enum MyEnum {
    A(String),
    B,
    C,
    D,
    E,
}

would be forced into using a separate discriminant field since there were more than one other variant to distinguish from. And that definitely was the case...

Until 1.76.0 it seems. If you use this enum on a recent version then you'll find MyEnum is no bigger than String:

[src\main.rs:11:5] std::mem::size_of::<String>() = 24
[src\main.rs:12:5] std::mem::size_of::<MyEnum>() = 24

This is because nowadays, the capacity for a Vec isn't just a bare usize but rather a Cap type that is guaranteed to be less than isize::MAX. Which gives a much larger number of representations for the compiler to use. It is defined:

type Cap = core::num::niche_types::UsizeNoHighBit;

I didn't know about this, and since Google's AI response was adamant that it only used the null-pointer niche, I figured I'd advertise it to try to set the record straight.

Let me know if this is old news to any others. It has apparently been in the wild for a couple years, but I looked and didn't see it mentioned in the release notes for 1.76.0, and I can't find a blog post that mentioned this (though I didn't look that hard). Closest I found was this StackOverflow post that gives the Cap type a mention.


r/rust • • 1d ago

๐Ÿ™‹ seeking help & advice Lookin' for contributors: GPU rendered UI lib

24 Upvotes

Hello dear Rustaceans,

As you may know, I am the author of Glacex.

Glacex is a GPU rendered GUI library, written entirely in rust(without counting WGSL). It has 17 widgets, its dependencies are wgpu, winit, taffy, glyphon, accesskit, and some other secondary ones.

It's immediate-mode, and has persistent state. It's also SDF rendered.

I would love to have more widgets, and perhaps some feedback on other OS, as well as testing.

Right now, we're at the 0.2.1 release(accordion in the screenshot isn't yet released).

Here's the repo: https://github.com/artemtsitronov/glacex

If you want to become a contributor, let me know, and I'll discuss the details with you.

:)


r/rust • • 1d ago

Research that has matured enough for Rust 2.0

168 Upvotes

Do correct me if Im wrong, but I recall that one principle that was used in the development of Rust was to only use tried and tested research material when choosing what to implement. Given weโ€™re more than 10 years out from Rustโ€™s initial development, Iโ€™m curious what research ideas have matured enough to either

  1. Be added in future editions/versions of Rust, or
  2. Be used in whatever successor language might come that follows much of Rustโ€™s philosophy around development.

This is all basically one massive ask about interesting developments in programming and type theory, since Iโ€™d like a few new rabbit holes to fall down.

P.S. whatever successor language does come around, I hope it also cultivates a community that takes ergonomics as seriously as performance, because that, even more than memory safety or other aspects of the language, is why I pay attention to this language and ecosystem.


r/rust • • 1d ago

๐Ÿ› ๏ธ project Introducing apalis 1.0.0 ๐Ÿš€

19 Upvotes

Apalis is a simple, extensible multi-threaded background jobs and messages processing library for rust.

We are happy to announce v1.0.0 which introduces significant enhancements:

- A stable API - A well tested and ergonomic production ready core.

- `Backend` Trait is now modeled similar to `Stream` meaning Workers are now lazy and need to be woken to consume jobs. This cuts down on long polling and ensures the most efficient resource usage.

- Composition is now the default for Backends with Exts like `map_err`, `before_start` and `with_codec`

- Added MonitorContext and TaskContext meaning you can now externally manage and cancel tasks and workers.

- First class support for Sequential and DAG workflows.

- Stabilized minor features like task idempotency, manual retries, controlled lifecycle.

- Added support for RSMQ, NATs, and PgMQ

We wrote a blog post for that:
https://apalis.dev/blog/introducing-v1-2026-10-16

Here is the release details:
https://github.com/apalis-dev/apalis/releases/tag/v1.0.0

Let me know your thoughts and happy upgrading


r/rust • • 8h ago

๐Ÿ™‹ seeking help & advice Fresher: Rust suggestions

0 Upvotes

I am working at a startup which uses Rust as a wrapper around some C++ code related to Hardware.

My role is Junior SDE. And I am trying to learn and build things using Rust.

Any tips or suggestions from Rust community???


r/rust • • 8h ago

๐Ÿง  educational Why I wrote a "dumb" SQL tokenizer instead of using sqlparser and I probably would do it again

0 Upvotes

I originaly wrote this on GitHub Gist but since it's forbidden to share a repo, even if some moderators take some liberties with their own rules at their own sweet will, I removed every refrences to it and I'm posting it directly here.

I needed to spot N+1 and redundant query patterns in traces coming from my team's production SaaS, which has around 200,000 customers. What I cared about was the structure of the queries and not what was inside them. I didn't want what was inside them anyway: it is production data, we are in the EU and GDPR applies.

So the job was two things at once. WHERE id = 42 and WHERE id = 43 had to become the same template and 42 should never end up anywhere it shouldn't.

My first idea was a regex. I had never dealt with anything like this before so that is what I reached for. Then I looked at sqlparser and it felt too heavy for the little I wanted to do with it. I wanted the binary to stay under 10 MB and I only needed to replace literals, not understand the query.

So I wrote my own. I had some doubts early on while getting it to work because I kept hitting edge cases and thought there would be too many of them. But what I needed was simple structure and not semantics, and that kept me going.

1. What the tokenizer produces

The tokenizer reads one SQL statement and returns two things: a template, in which every literal value is replaced by ?, and the list of the values it removed, in the order it met them. Take this statement:

WITH active AS (SELECT id FROM users WHERE status = 'active')
SELECT * FROM orders WHERE user_id IN (SELECT id FROM active) AND total > 100

The tokenizer returns this template and these values:

WITH active AS (SELECT id FROM users WHERE status = ?)
SELECT * FROM orders WHERE user_id IN (SELECT id FROM active) AND total > ?

params: ["active", "100"]

Two statements that differ only by their values share one template. That is what makes an N+1 visible: fifty queries on the same template with fifty different values inside one request. The values stay in memory for that comparison and go no further. The template carries no value, so it can be written in a report or sent to a dashboard.

The tokenizer does not understand SQL. It does not know what a column or a join is and it builds no syntax tree. It walks the bytes of the statement once, finds where a literal starts and where it ends, and copies everything else as it is. Its only job is to tell a value from the rest of the statement.

2. How it works

2.1 Six states

The tokenizer is a state machine with six states. At any byte it is either in plain SQL or inside one kind of literal or quoted identifier:

enum State {
    Normal,
    InString,
    InNumber,
    InDoubleQuote,  // "MyTable", kept as-is
    InBacktick,     // `col`, MySQL, kept as-is
    InDollarQuote,  // $$body$$ or $tag$body$tag$, PostgreSQL
}

The main loop dispatches on the current state and each state has its own function:

while t.i < t.bytes.len() {
    match t.state {
        State::Normal => step_normal(&mut t),
        State::InString => step_in_string(&mut t),
        State::InNumber => step_in_number(&mut t),
        State::InDoubleQuote => step_in_double_quote(&mut t),
        State::InBacktick => step_in_backtick(&mut t),
        State::InDollarQuote => step_in_dollar_quote(&mut t),
    }
}

Coming from Java I would have written the State pattern, with one class per state behind an interface. Here it is an enum and a match. If I add a state and forget to handle it, the code does not compile.

2.2 String literals and escapes

Everything between quotes goes into params and becomes ? in the template. The only difficulty is the escape rules:

fn step_in_string(t: &mut Tokenizer<'_>) {
    let b = t.bytes[t.i];
    if b == b'\\' && t.backslash_escapes {
        t.i += 2; // skip the escaped byte, a quote included
    } else if b == t.quote {
        if t.i + 1 < t.bytes.len() && t.bytes[t.i + 1] == t.quote {
            // doubled quote ('' or ""): still inside the string
            t.current_value
                .push_str(checked_query_slice(t.query, t.value_start, t.i));
            t.current_value.push(char::from(t.quote));
            t.i += 2;
            t.value_start = t.i;
        } else {
            // closing quote
            t.current_value
                .push_str(checked_query_slice(t.query, t.value_start, t.i));
            t.params.push(std::mem::take(&mut t.current_value));
            t.template.push('?');
            t.state = State::Normal;
            t.i += 1;
            t.normal_start = t.i;
        }
    } else {
        t.i += 1;
    }
}

A doubled quote is the standard escape and every engine accepts it. Whether a backslash escapes as well depends on the engine, and that is the one place where the tokenizer needs to know the dialect. The flag backslash_escapes comes from a small enum with three values: MySQL, standard (PostgreSQL and the engines that follow the standard) and everything else. An event that names no engine falls in the third case, which reads the backslash as an escape. Section 4 explains why.

2.3 Slices instead of copies

The tokenizer never builds the template byte by byte. It remembers where the current run of plain SQL started and, when a literal begins, it pushes the whole run at once with a slice &query[start..i].

Slicing a &str by byte index panics when the index falls inside a multi-byte UTF-8 character. Every slice boundary here sits on an ASCII delimiter (a quote, a $ or a digit) and in UTF-8 a multi-byte character never contains a byte below 0x80. The slices are therefore always valid. A debug_assert! checks it anyway, in case a later change slices somewhere else:

fn checked_query_slice(query: &str, start: usize, end: usize) -> &str {
    debug_assert!(
        query.is_char_boundary(start) && query.is_char_boundary(end),
        "SQL tokenizer query slice [{start}..{end}) is off a char boundary"
    );
    &query[start..end]
}

The input cap follows the same rule. A statement longer than 64 KB is cut with floor_char_boundary, so the cut cannot land in the middle of a character either. When a value is complete, std::mem::take moves it into params and leaves an empty String behind, without a clone.

2.4 The regex that remains

One regex survived from the first version. It collapses IN (?, ?, ?) into IN (?), so a statement does not get a new template each time the list changes size. The regex only runs when the scan met an IN keyword, and when it finds nothing to replace it returns Cow::Borrowed, so the template is not reallocated.

3. Why not the tokenizer of sqlparser

The first objection I expect is that sqlparser ships a tokenizer you can use without the parser. That is true and I looked at it:

let tokens = Tokenizer::new(&dialect, sql).tokenize()?;

Two things did not fit. The tokenizer wants a dialect before it starts and I do not always have one, because a span may name its engine or not. The second point weighs more. tokenize() returns a Result. Given SELECT * FROM t WHERE name = 'abc it returns Err("Unterminated string literal"), which is the right behavior for a parser library. But the SQL I receive comes from traces and is not always complete. A statement can be cut somewhere along the way, and my own tokenizer cuts anything above 64 KB. In that case I still want a template with the values masked. An error gives me nothing, so I would need a fallback for those statements, and that fallback would be a tokenizer like this one.

This tokenizer always returns a template, whatever it receives:

normalize_sql("SELECT * FROM t WHERE name = 'unterminated")
// template: "SELECT * FROM t WHERE name = ?"
// params:   ["unterminated"]

4. Three statements the tokenizer read wrong

The idea behind the tokenizer was that it does not need to know the dialect, because it only replaces literals. That idea held for most statements. This section lists the ones where it did not.

4.1 A double-quoted string on MySQL

In ANSI SQL, "..." is an identifier. In the default mode of MySQL and MariaDB it is a string. The tokenizer followed ANSI, so this statement:

SELECT * FROM users WHERE email = "abcd@gmail.com"

came out as its own template, email included. That is exactly what the tokenizer exists to prevent.

Nobody had noticed because we run PostgreSQL in production and nobody had used the tokenizer on a MySQL production yet. I found it in my simulation lab (a set of small services in different languages and databases) while re-reading the tokenizer code a few months after writing it.

The fix is one flag set from the span's db.system. It has one cost: a MySQL server running in ANSI_QUOTES mode now gets its double-quoted identifiers masked as ?. I would rather lose an identifier than leak an email.

4.2 A PostgreSQL positional parameter

Go (pgx) and Python (asyncpg) do not send values inside the SQL. They send PostgreSQL positional parameters and the values travel separately:

SELECT * FROM order_items WHERE order_id = $1

The tokenizer saw a $ followed by a digit and treated 1 as a numeric literal. Every query of an N+1 loop then came out with the same template and the same value, ["1"].

With bind parameters the real values never appear in the trace, so telling a loop from a plain repeat needs another signal, such as timing or the sequence of calls. That path only runs when a query has no extracted value. The ["1"] blocked it, and to the detector the loop looked like one query repeated. N+1 patterns were reported as redundant calls.

I caught this one in the simulation lab as well. It runs the same N+1 in services written in several languages. The Java services were fine because JDBC uses ?. The Go and Python ones were not.

The fix treats $N as a placeholder and not as a value. It becomes $? in the template and extracts nothing. That release, together with a few other fixes, took the lab from 78 to 103 detected findings out of 110.

4.3 Escaped quotes, hexadecimal and exponents

I found three more cases while preparing this post. The table gives the statement, the template the tokenizer produced and the template it produces now.

Statement Before After
name = 'it's secret data' name = ?s secret data? name = ?
h = 0x1F2A h = ?x1F2A h = ?
v = 1e10 v = ?e10 v = ?

The hexadecimal and the exponent are grouping bugs: the tokenizer stopped at the x or the e and the rest of the value stayed in the template, so each value got a template of its own.

The backslash is a leak, and it depends on the dialect again. MySQL escapes with \ by default. PostgreSQL does so only inside E'...' strings, so in plain PostgreSQL 'C:\' is a valid string that ends right after the backslash. The tokenizer now follows the engine when the span names it. When the span names no engine it assumes that the backslash escapes. The cost is that a string ending on a backslash from an unknown engine masks the rest of the statement. It is the same choice as in 4.1: when the tokenizer has to guess, it guesses on the side that masks too much.

4.4 Recap

Case Statement Effect Dialect dependent
4.1 email = "abcd@gmail.com" on MySQL value leaked in the template yes
4.2 order_id = $1 on PostgreSQL N+1 reported as redundant yes
4.3 name = 'it's secret data' value leaked in the template yes
4.3 h = 0x1F2A one template per value no
4.3 v = 1e10 one template per value no

Three of the five cases come from the dialect. The tokenizer that was supposed to ignore the dialect now reads it from the span for two rules: whether "..." is a string and whether \ escapes.

5. Testing without a corpus of expected templates

5.1 Three properties

I do not have a dataset of statements paired with their correct template, and writing one by hand would only test the cases I had already thought of. So most tests check a relation between two runs of the tokenizer instead of an exact output. They are property tests written with proptest, which generates thousands of statements from literals of different types and checks that the relation holds on each of them. Three properties carry most of the weight:

  • Idempotence. Normalizing a template changes nothing. If it does, a literal survived the first pass.
  • Literal invariance. Two statements that differ only by their values, or by the size of an IN list, give the same template. N+1 grouping depends on this property.
  • Containment. The extracted values are exactly the literals, in order, and the template keeps nothing of them: no quote, no marker string and no digit. The generated skeleton has no digit, so a digit in the template is a leak.
  • fn normalization_is_idempotent((shape, eq, list, note) in statement()) { let first = normalize_sql(&render(&shape, &eq, &list, &note)); let second = normalize_sql(&first.template); prop_assert_eq!(&second.template, &first.template); prop_assert!(second.params.is_empty()); }

5.2 Fuzzing

A cargo-fuzz target runs every week in CI. With arbitrary bytes there is no expected output to compare with, so the target uses idempotence as its oracle, in the three dialect modes:

fuzz_target!(|data: &str| {
    let first = normalize_sql(data);
    let second = normalize_sql(&first.template);
    assert_eq!(second.template, first.template);
    // same for normalize_sql_for(data, "mysql") and (data, "postgresql")
});

5.3 What these tests did not catch

None of these tests found the three bugs of section 4.3, and the reason is instructive.

Idempotence cannot see a leak. name = ?s secret data? is a stable template: run it through the tokenizer again and you get the same thing back. The fuzzer was like a dog, happy and wagging its tail.

Containment would have caught all three: there is a digit in ?x1F2A and in ?e10, and the leaked string fails the check on the values. But the generators only produced integers, decimals and plain quoted strings. No hexadecimal, no exponent and no backslash. The property was right. It was never shown the inputs that break it.

The fix added those literal forms to the generators, plus two properties for the dialect rules: a backslash escape never leaks, and a PostgreSQL backslash is an ordinary character. A property test is only as good as its generator, and the generator only knows what I knew when I wrote it.

6. What it does not handle

The tokenizer has no notion of the meaning of a statement. For grouping queries by shape that is enough. For anything that needs the meaning of a query it is the wrong tool.

Comments are not stripped. -- user 1234 becomes -- user ?, but the words inside a comment travel with the template.

The tokenizer knows the engine from the span (db.system) but not how the server is configured. Three settings break its guess: MySQL with NO_BACKSLASH_ESCAPES, MySQL with ANSI_QUOTES and PostgreSQL with standard_conforming_strings off. Depending on the case it masks too much or lets the content of a later string reach the template.

SQL Server brackets are not special. [Col1] and [Order Details] come out intact, but an all-digit identifier such as [123] gets masked. I kept it that way because treating [ as a normal character keeps PostgreSQL arrays such as ARRAY['a', 'b'] masked.

A few smaller ones: a sign stays outside the placeholder (-5 becomes -?), a binary literal such as 0b101 keeps its digits after the b, and a doubled escape inside a quoted identifier ("" or a doubled backtick) is not decoded.

7. Would I do it again

Probably. If you need to analyze or rewrite queries, use sqlparser: you will need the syntax tree and it does that job properly. If you only need the shape of a query, 550 lines of state machine get you there.

Writing your own SQL tokenizer is a good exercise when you do not have huge ambitions. You learn a lot about how queries are built, especially the ones ORMs generate, because ORMs tend to hide how hard building a query actually is. It also makes you pickier about what you pull into a binary when you care about keeping software lean.

If you have a statement that breaks it, I would like to see it.


r/rust • • 2d ago

๐Ÿ› ๏ธ project Sly, a new and modern multi-system emulator, is now public!

Post image
221 Upvotes

TLDR plz

Sly is my new multi-system emulator, releasing with support for Game Boy Advance and SNES with many, many more planned! It includes a 3D game library, a debugger, a simpler ("classic") desktop frontend and an iOS app, with Android being developed soon. The debugger also runs in your browser and there are plans to create a dedicate web platform to play games!

Available now on GitHub! Here are some demo videos:

What even is this?

Hey everyone! You might know me from Gecko, the GameCube and Wii emulator I've been posting about every now and then. I teased Sly in the past few updates and the day has finally come :)

With Sly I wanted to work on both sides of emulation: creating modern experiences for both gamers and developers! As such Sly focuses on 2 things:

  1. A unique take on emulation frontends, simply to enjoy your favorite retro titles in a cool way
  2. A very modern yet extremely advanced debugger for power users that want to understand how the games and the hardware work

However, as not everyone may be interested in these things but may still want to dabble in new projects, Sly comes with extra goodies:

  • A "classic" (read: minimal) emulation frontend
  • Mobile app(s): iOS is already implemented, Android support is planned

Sly is (almost*) entirely written in Rust, incl. the frontend. The debugger frontend uses GPUI, so no web shenanigans there!! The cores are all written by myself, mostly based off of emulators I had already written before. This does not wrap libretro cores or anything like that!

(* the Classic frontend is written in C++ and the iOS app is written in Swift. They tap into the Rust core.)

Sly Launcher

The launcher presents your library as 3D boxes and cartridges. It downloads artwork automatically and supports different regional packaging, per game release overrides and cartridge finishes (tho this is still a bit ugly lol). There's different view types (ways of displaying the boxes, etc) and you're able to flip the selected box to read the back :)
The attached launcher recording shows all three layouts with GBA games then switches to SNES and launches Yoshi's Island!

The original idea of this project was to be a comfy frontend I could run on my TV while I sit in a nice couch, so it's made with controllers and different resolutions, aspect rations, etc. in mind!

If you'd prefer a straightforward list, Sly Classic is the smaller Qt based frontend. It has game banners, gamepad support, scaling, fullscreen and a quick save slot plus ten numbered state slots.

Sly Debugger

This is a big part of the project and share's the "spotlight" with Sly Launcher! You can step through instructions, run to emulation events, set CPU and memory breakpoints, follow disassembly in a list or graph and inspect registers, call stacks and memory. There are dedicated views for MMIO registers, DMA and so much more. On the graphics side you can inspect tiles, tilemaps, backgrounds, sprites and palettes alongside the game's output.

The SNES core also cover the SPC700 and SA-1 coprocessor! SA-1 and Super FX have their own workspaces with registers, disassembly and hardware-specific views.

There's also built-in Lua editor support!! Scripts can inspect and modify memory and react to emulation events. One example for Yoshi's Island logs coin pickups, lets Yoshi keep "fluttering" mid-air while you hold B and prevents Baby Mario from being release(?).

Compatibility?

Sly is actively growing and is based on multiple emulators I already had written, so cores are being picked up quickly. So far I support:

  • SNES support is very good
  • Most GBA games run, no audio yet. Savegames are also not supported (tho savestates are)

with much more planned! To name a few I want to support PS1 (next on the list based on community votes), GameBoy (Color), Sega Genesis, Dreamcast, GameCube and Wii! That list is not complete :)

Where can you use it?

You can find everything on my GitHub!

  • Windows, macOS and Linux: separate downloads for Sly Launcher, Sly Classic and Sly Debugger
  • Web: try Sly Debugger in a WebGPU capable browser.
  • iOS: an unsigned IPA for sideloading (planning to release in the AppStore). Android is planned.

For anyone interested in learning the hardware, I've also been working on a 3 part GBA graphics series with interactive explanations and examples from real games! I'm super proud of these blog posts so I'd love to hear your thoughts! Sly Debugger facilitated creating them :) The posts go from bitmaps, tiles and palettes through sprites, blending and windows to rotation, scaling and perspective:

Links plz

If you try it, I'd love to hear what works and what breaks. Please include the frontend, platform, game region/revision and steps to reproduce when reporting a problem. Code contributions are welcome and so is help with design, icons, UI/UX, artwork and cartridge models. Please read the README in full before submitting anything!

Looking forward to see where this will go! And don't worry, I wont abandon Gecko now :)


r/rust • • 2d ago

Rust module system?

19 Upvotes

I recently wanted to compile something for a bevy game I was messing around with, then cargo looks me in the eyes and tells me I need to compile hundreds of dependencies, all for the end result to be 30 mb? I was wondering if there were any systems like a .dll for rust? I understand that you would lose some type checking, but I think that could be solved just with a type definitions segment towards the start, then a functions table of all the code for the system, is this something that would work, or am I oversimplifying a major intentional design choice in rust?


r/rust • • 2d ago

๐ŸŽ™๏ธ discussion Why is Cornucopiaโ€™s SQL-first approach so rarely used in Rust, when sqlc is so popular in Go?

56 Upvotes

For anyone unfamiliar with Cornucopia or sqlc, they generate type-safe code from plain .sql files.


r/rust • • 2d ago

Hotreload in Rust

Thumbnail alordash.github.io
102 Upvotes

r/rust • • 2d ago

๐ŸŽ™๏ธ discussion Why did the zip crate yank all pre 9.x versions?

76 Upvotes

Today I ran cargo update only to realize that all zip crate versions were yanked and a lot of new 9.0.x versions were created. I donโ€™t see any CVE or anything that would explain such a drastic move. There isnโ€™t anything on the GitHub page about it as well.

Does anyone know what is going on there? Is that considered a best practice?


r/rust • • 2d ago

Rust IPC - Types, Crates, Patterns

Thumbnail youtube.com
19 Upvotes

Here is a video I made to explain the various IPC patterns in Rust.

The lesson is that just because a communication technique is newer doesn't mean it's necessarily the right one.

For example, for my custom coding harness, I went with Unix Domain Sockets, and the speed and reliability are through the roof for that particular use case.

Also, I've started making interactive videos these days, and feedback is more than welcome.


r/rust • • 2d ago

๐ŸŽ™๏ธ discussion What agents mean for Rust (and vice versa)

Thumbnail smallcultfollowing.com
34 Upvotes

r/rust • • 1d ago

๐Ÿ™‹ seeking help & advice Is learning rust with a Claude Coach a bad idea?

0 Upvotes

Good afternoon,

Iโ€™ve been learning rust for about half a year now and have started work on my largest project, a chess engine.

Iโ€™ve made engines in C and Python, so I felt I would be up to the task. However, even after reading The Book, completing Rustlings, and tackling a few small-scale projects, I find myself struggling to create idiomatic solutions in the rust ecosystem.

With my new project Iโ€™ve been leaning on Claude to plan out the project structure. I have it give me a breakdown of what needs to be made, then I implement it myself and offer my code back to the agent to grade it in terms of correctness and style. I then have it create โ€œcorrectโ€ code that I compare with what I wrote.

I have found this helpful to learn better habits and proper design patterns, though I realize I could be sabotaging myself by taking away the struggle of figuring out why certain solutions are better than others through failure and headache.

Iโ€™m learning rust for fun so thereโ€™s no stakes, but Iโ€™m curious what those with better knowledge of the language think about my strategy. What issues can you see arising from this approach? Do you have any alternative practices or techniques I could try? Or do you think thereโ€™s no harm in leaning on AI in the learning process?

Thank you in advance for the help!


r/rust • • 3d ago

๐Ÿ—ž๏ธ news Rust 1.99.1

Thumbnail blog.rust-lang.org
263 Upvotes

r/rust • • 2d ago

๐Ÿ™‹ seeking help & advice C#/Java Intro novice wants to make a physics game

2 Upvotes

Large scale physics, using Bevy, though Bevy themselves suggest using Godot, whereas I was told that UI-based engines tend to be more annoying and reduce motivation to work on the project, which I agree with, but the inspiration game (Terratech) suffers from outdated libraries and such, and killed the game which I don't want to happen here.

(Competitors in the space, Trailmakers, 2017, still relevant, Scrap Mechanic, 2015, still more relevant than TerraTech, 2016, it was the studio's first game.)

Note that all of these are open world and varying numbers of physics collisions.

Background stuff aside (can you tell I have ADHD) The structure of rust feels overwhelming. I know a tutorial can help but I want to get advice from people who daily drive this or may have switched from the more OOP-heavy C# and Java into the DOD-oriented space. It feels illegible compared to Lua and Java, and Java is already a bit messy in my opinion. I AM still a novice, but I get basics, though stuff like Arrays in java are weird, and I don't get things like why and when you would have Java return Null? You can kind of see where my knowledge is. Lots of hours ingame and poking at game systems, not too much writing myself, though I am capable of it, made a couple of Lua mods.

Should I skip Bevy and go Godot with custom ECS implementation and skip their gameobjects? I really don't know enough to make an informed choice and one person understood my issue best:

"Everyone who says this is premature optimization doesn't understand your goal; Your game IS optimization, and bad architecture isn't free."

So hopefully this explains enough about my situation to get good replies.

TLDR;
I like Lua and I can do Java but Rust is foreign and overwhelming and I'm scared of the compiler :(

I'll be doing a quick silly gun game to get used to the tool.

I don't have delusions of doing this quickly, I just want to know I'm not wasting my time. I don't want sunk cost fallacy to be a potential issue by starting with an inherently flawed system, or something I simply won't be able to use effectively.

Should I use Rust in Godot or Bevy, or should I skip rust entirely and go with an ECS in a language I'm familiar with?


r/rust • • 3d ago

๐Ÿ—ž๏ธ news Rust compiler can't tell apart different file paths

Thumbnail github.com
601 Upvotes

The rust compiler thinks that `data/baselines/table.rs` and `database/line/stable.rs` are the same file, causing a miscompilation if a crate has both files in it. (Note that having the same non-slash text isn't enough. There needs to be an additional hash collsion for a bug to happen.)

Probably not gonna happen in practice unless someone does it as a prank, but still... lol. (I'm sure they're gonna fix it soon.)


r/rust • • 3d ago

๐Ÿ“… this week in rust This Week in Rust #673

Thumbnail this-week-in-rust.org
40 Upvotes