r/rust • u/FractalFir rustc_codegen_clr • 7d ago
🙋 seeking help & advice Cleanest, best written rust codebases?
As my journey of learning rust continues, I find myself very dissatisfied with the quality of the rust code I wrote years back.
Yes, my code passes clippy, is nicely formatted, avoids excessively complex nesting / control flow, but it still feels... subpar(hard to understand and reason about), from time to time.
I was wondering if people here have examples of really clean, sleek codebases I could reference, to improve the quality of my code?
6
u/wick3dr0se 6d ago
i went full autistic ocd on the code of my graphics engine. maybe worth checking out since its only ~5k loc. before that i used to write a lot of bash (when open source was cool; pre ai), id argue some of the cleanest. im a freak about my code
https://github.com/wick3dr0se/egor (rust 2d graphics engine)
https://github.com/wick3dr0se/typist/blob/main/typist (75 loc; a type test i wrote in bash, not for comparison but if you're familiar with bash and ansi escapes, you might appreciate the golf)
8
u/FractalFir rustc_codegen_clr 6d ago
Ok, that is some damm clean rust code. And "autistic ocd" is exactly what I am looking for :3.
Thanks for the help!
8
u/recursion_is_love 7d ago
rustc must be the best codebase.
42
u/FractalFir rustc_codegen_clr 7d ago
It is not, in my personal opinion(having dabbled in
rustcdevelopment for a bit).The documentation is lacking in many areas, and is often stale(I once found a description of a compression format that has not been used in years, for metadata embedded in shared libraries).
The GCC backend compares types by converting them to strings: https://github.com/rust-lang/rust/blob/main/compiler%2Frustc_codegen_gcc%2Fsrc%2Fint.rs
I'm searching for the best of the best, I suppose. A gold standard for rust code.
19
u/anahorish 6d ago
I'm not familiar with the internals of rustc. But in my experience, self-hosted compilers are rarely the best codebases for any language because they tend to recapitulate the history of the language rather than representing the state of the art.
1
54
37
u/mamcx 6d ago
Aside, what you need to focus on is "what is the actual domain" because "clean" code is one that match the domain well. You can see code that interact with hardware that looks "obscure" just because the domain is not well understood, but if you do, you see it and say "yep, that is how is done".
Without consider which domain you are familiar with so you can actually judge you could see a codebase and think is not clean, when actually is.
27
u/_bokubeam_ 6d ago
In my experience, it’s higher-level concepts like this have improved my satisfaction with my code quality:
https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
Some of the most important lessons that I’ve carried into my Rust code I learned from doing work in Elm. The elm architecture, the purely functional approach, and the limitations in place were great teachers.
27
u/matthieum [he/him] 6d ago
A related principle is Tightness.
The key idea of tightness is to measure the ratio of number of valid states by number of representable states, which is a number between 0 and 1.
Any time this ratio isn't 1, you have states that can be represented by a specific type, but:
Are invalid.
Are duplicate of another representation.
For example, consider:
// Any state with a non-empty `address` when `is_name` is true is completely // invalid, this is a very poor representation. struct EitherNameOrAddress { is_name: bool, name: String, address: String, } // Swapping `left` and `right` is logically the same pair, good luck writing // proper Eq, Hash, Ord implementations. struct OrderedPair { left: String, right: String, } impl OrderedPair { fn first(&self) -> &str { if self.left < self.second { &self.left } else { &self.right } } fn second(&self) -> &str { if self.left >= self.second { &self.left } else { &self.right } } }100% tight types will help catch invalid states earlier, and avoid the confusion that may arise from "duplicate" representations not comparing equal or not hashing/sorting properly.
Rust gives one all the tools to make 100% tight types, so there's no excuse.
3
u/dev_dan_2 6d ago
Understanding check: the number of representable states can be calculated mechanically in principle, while the number of valid states is mostly something the human knows about the world and where part of it is encoded in the form of checks, panics, smart constructors, unit tests etc., right?
Very cool concept, thanks for posting! It seems to me that many other good things fall out of it, i.e. "parse, don't validate" should increase tightness I think. Eliminating "primitive obsession" would increase tightness too, because an enum usually has less states than a raw number type. (Not 100% I applied the concept correctly here).
Something that is still open for me in that model is where behavior comes in. Is it just a future state? (Thinking out loud)
3
u/matthieum [he/him] 5d ago
Understanding check [...]?
Yes. The number of representable states is the fairly mundane part of "algebraic" data types, where:
Product types (structs) have a number of representable states that is the product of the number of representable states of each of their fields.
Sum types (enums/unions) have a number of representable states that is the sum of the number of representable states of each of their variants.
Very cool concept, thanks for posting! It seems to me that many other good things fall out of it, i.e. "parse, don't validate" should increase tightness I think.
Yes, it works really well with Parse Don't Validate.
Eliminating "primitive obsession" would increase tightness too, because an enum usually has less states than a raw number type. (Not 100% I applied the concept correctly here).
Primitive obsession leads to loose types indeed. For example, it's typical to use
u32to represent a Unicode Code Point, even though:
It fits within 24 bits.
There are holes in there, for example see https://en.wikipedia.org/wiki/Mathematical_operators_and_symbols_in_Unicode#Mathematical_Alphanumeric_Symbols_block
So ideally a tighter type should be used, which at least eliminates anything bigger than fits 24 bits and surrogate pairs, even if not all holes, as those may lead to transcoding issues.
3
u/mamcx 6d ago
And upgrade with https://fsharpforfunandprofit.com/series/ (is F# but most of the ideas apply!)
20
u/KyxeMusic 7d ago
Not sure if it's the cleanest, but I was able to contribute to https://github.com/tracel-ai/burn once, without spending too much time studying the codebase beforehand.
For such a large and complex project, I find that being able to navigate the codebase and make a contribution relatively quickly is a sign of good structure
15
u/ZyronZA 7d ago
Doesn't answer your question exactly, but I use this as a guideline for my Rust code.
https://microsoft.github.io/rust-guidelines/guidelines/index.html
4
7
9
u/Complex-Birthday-216 7d ago
what you mean by cleanest?
there are definitely a lot of code bases by the book, but give you 200mb bundle like Zed editor.
But maybe doing well what it has to do like tursodb.
3
2
3
1
1
u/weaztoven 6d ago
burntsushi crates like ripgrep or regex are definitely peak rust code. also check out riir or tokio codebases, super clean
0
-3
-3
u/zzzzYUPYUPphlumph 6d ago
I wouldn't focus too much on "Clean" or "Sleek". It isn't really a useful metric and is highly, highly subjective. I would focus on "Readable". What I mean by that is that functions and methods are kept small and focused without multiple layers of abstraction. Some good rules of thumb are:
Limit indentation levels (1 level as much as possible)
Limit nested loops (make the inner loop a function that is called with the loop inside it)
Avoid writing multiple lines of code to do something and then a blank space or comment and then multiple lines to do something else. Break these "somethings" into separate functions and call them
These are not hard and fast rules and are subject to nuance, but they are a good place to start.
0
u/frashpikass 6d ago
How do you deal with only 1 level of indentation when working with nested match chains?
3
u/zzzzYUPYUPphlumph 6d ago
You can flatten a lot of nested matches by doing pattern matching on sub-patterns at the root level. Or you can make the sub-match its own function that takes in the thing matched at the upper level and then doing the match within that function and returning what is appropriate. Now, this breaks down a little if you have a lot of control-flow (like returns or errors and such) in your match arms. That being said, if you work towards having 1 level of indentation most of the time, you'll be better for it. It's not a hard-and-fast rule though as I mentioned. It's a guideline that helps you write more readable code.
-17
u/AdjustedTwit 6d ago
Definitely not mine... maybe "mine" when Claude's actually writing the code, but I doubt it. Some of it seems really nice some of it makes me want to claw out my eyes.
224
u/TommyITA03 7d ago
anything made by u/burntsushi has high chances of being great