Generate random numbers without the rand crate
You should use the rand crate for random numbers generally.
But if for some reason you need random numbers,
can't use rand, but can use std,
then you can pull cryptographically-secure random u64s
from the standard Hasher:
Run cargo clean-all to free up large amounts of disk space
Everyone finds out eventually: the Rust compiler stores
a large amount of data in your target/ directories,
and doesn't clean up after itself.
The cargo clean-all plugin finds these directories
and helps you delete them, interactively by default.
cargo install cargo-clean-all
cargo clean-all
The Ok::<(), WhateverError>(()) block tail
Sometimes you have a block of code that uses ?
but otherwise doesn't return a value,
and it won't typecheck without a hint.
Usually the prettiest solution is to
write out the full Ok constructor,
using the [turbofish],
in thi block's tail expression.
block_on?;
Assert Send / Sync
);
const _ASSERT_SEND_SYNC: = ;
const
Also in rustmax::extras::assert_send_sync.
Copy a directory recursively
There's no standard way to recursively copy a dir!
Here take this:
It's also at rustmax::extras::copy_dir_recursive.
Now doing it in a way that is mindful of the infinite curveballs
different OSes will throw at you via the filesystem …
well that's probably why std doesn't try.
There's an Either hiding in the futures crate!
The Either type, most known from Haskell, is a useful
reusable abstraction for the common need to create a lightweight type
that is a named union of two other types, typically looks like:
Rust doesn't provide this type because it instead provides Result,
which is the most common use-case for the pattern, and the remaining
use-cases seem marginal for such a simple type - official guidelines
encouraging writing your own Either type for specific uses, with more
specific names.
Sometimes you want one though!
There's one in the futures crate: futures::future::Either.
Although Either is a Future and provided for awaiting pairs of futures,
its definition is exactly as above.
Import traits with as _
Most of the time we need traits to call a method, and for this we need the trait to be in scope, but it doesn't need to be namable.
use ;
let hash = read_hash?;
reader.seek?;
Set up the mold linker
Linking is one of the most time-consuming stages of a Rust build, and it has to be redone every time you test your program.
On Linux the mold linker is faster than
the the default linker.
Setting it up manually is not difficult,
but just hard enough that I have to look it up
every time.
The Rustmax CLI tool can do it instead:
rustmax install-tool mold
Use rustfmt::skip
Sometimes exact formatting is important to make code beautiful.
Don't be afraid annotate with #[rustfmt::skip].
Use Option with ?
The ? operator works with Option to early-return on None,
making option-heavy code much cleaner.
An alternative to match or if let statements, ? lets you chain
operations that might fail, automatically propagating None up the call stack.
Put common development commands in a justfile
Almost every project has a handful of commands the developer(s)
uses frequently. Put these in a justfile so the menu of
commands for this project is always obvious, which
can be extra helpful after years away from a project.
cargo install just
just runs commands listed in a file named justfile.
The justfile lives your project's root directory,
and is configured with a make-like syntax:
default:
just --list
install-tools:
cargo install mdbook
cargo install mdbook-yapp
clean: doc-clean
cargo clean
doc-clean:
rm -rf out
It's a simple idea, but suprisingly useful. And don't worry that it looks like
a Makefile — it is much more fun and sensible in use than make.
When you come back to a project and see there's a justfile you
know to run just --list and you'll immediately see what
was on the previous maintainer's mind.
$ just --list
Available recipes:
build
check
clean
default
doc-book
doc-build
doc-clean
doc-crates
install-tools
lint
maint-audit
maint-duplicates
maint-lock-minimum-versions # useful prior to running `cargo audit`
maint-outdated
maint-upgrade
prebuild
publish
publish-dry
replace-version old new
test
test-min-version-build
Merge message streams with futures::stream::select
An async event loop often needs to receive messages from multiple sources.
Use futures::stream::select to merge two streams of the same type into one.
A common pattern: an event loop that handles both external messages and internally-generated events (like async task completions):
use mpsc;
use StreamExt;
async