Rust
My Standard Library
[dependencies]
# COMMAND LINE PARSING
clap = { version = "4.5.53", features = ["derive"] }
# ERGONOMIC DATETIMES
chrono = "0.4.42"
# SIMPLE PRETTY ERROR HANDLING
color-eyre = "0.6.5"
# BENCHMARKING
criterion = "0.8.1"
# SUPERPOWERED ITERATORS
itertools = "0.14.0"
# PARALELL ITERATORS
rayon = "1.11.0"
# SERIALISATION / DESERIALISATION
serde = { version = "*", features = ["derive"] }
And I dig running tests with https://nexte.st/
Strict Lints
These lints do two things:
- Teach you rust
- Stop panics at runtime
Run them withbacon clippy.
If you're wondering how to prototype code quickly using.unwrap()and friends - put them in unit tests, clippy ignores those!
[lints.clippy]
# UM, ACTUALLY
pedantic = { level = "deny", priority = -1 }
# DEVELOPING LINTS
nursery = { level = "deny", priority = -1 }
# DENY PANICS
unwrap_used = "deny"
expect_used = "deny"
indexing_slicing = "deny"
arithmetic_side_effects = "deny"
unreachable = "deny"
unimplemented = "deny"
unchecked_time_subtraction = "deny"
todo = "deny"
string_slice = "deny"
panic_in_result_fn = "deny"
panic = "deny"
exit = "deny"
as_conversions = "deny"
But allow these in tests, in your clippy.toml:
allow-unwrap-in-tests = true
allow-expect-in-tests = true
allow-panic-in-tests = true
allow-indexing-slicing-in-tests = true
Also here's an 80% of the above as a one-liner:
cargo clippy -- -D clippy::pedantic -D clippy::nursery
I also dig what is written here: https://emschwartz.me/your-clippy-config-should-be-stricter/
Rust Devenv
Here's a reasonable devenv.nix
{ pkgs, lib, config, ... }:
{
languages.rust = {
enable = true;
channel = "nightly";
components = [ "rustc" "cargo" "clippy" "rustfmt" "rust-analyzer" ];
};
packages = with pkgs; [
bacon
cargo-seek
cargo-nextest
cargo-generate
];
scripts.watcher = {
exec = ''
watchexec -c -e rs \
"cargo clippy && cargo test && cargo run"
'';
packages = [ pkgs.watchexec ];
description = "Rebuilds and runs app with supressed warnings";
};
#
# C LIBRARIES
#
env.LD_LIBRARY_PATH = lib.makeLibraryPath [
pkgs.openssl
];
}
Then add oxalica's rust-overlay with:
devenv inputs add rust-overlay github:oxalica/rust-overlay --follows nixpkgs
Typestate Pattern
The typestate pattern is an API design pattern that encodes information about an object's run-time state in its compile-time type.
I maintain the best example of this pattern I could find here: https://github.com/0atman/typestate-template
//NOTE: This is psudocode, read the repo for working code
// States
struct Red;
struct Yellow;
struct Green;
// a trait for all valid states
trait SignalState {}
impl SignalState for Red {}
impl SignalState for Yellow {}
impl SignalState for Green {}
// Core state struct
struct TrafficSignal<S: SignalState> {
_marker: PhantomData<S>,
data: String,
}
// Methods only available in the Red state
impl TrafficSignal<Red> {
pub fn next(self) -> TrafficSignal<Green> {
TrafficSignal::transition(self)
}
}
Rust Function Signatures
Are complex, but they can be understood through thorougher thought though.
From nom::combinator
pub fn cut<I, E: ParseError<I>, F>(parser: F)
-> impl Parser<I, Output = <F as Parser<I>>::Output, Error = E>
where
F: Parser<I, Error = E>,
{
Cut { parser }
}
fn walk_pet<W: Walk>(pet: &mut W) {
pet.walk();
}
is equivalant to
fn walk_pet<W>(pet: &mut W)
where W: Walk {
pet.walk();
}
Good stuff here: https://github.com/pretzelhammer/rust-blog/blob/master/posts/tour-of-rusts-standard-library-traits.md#scope