2022/04/13
That a rust if-statement can have a return type
let x: u32 = 123;
let stmt_result = if x % 2 == 0 {
Ok("even steven")
} else {
Err("odd steven")
};
assert_eq!(x, Err("odd steven"));
That a rust if-statement can have a return type
let x: u32 = 123;
let stmt_result = if x % 2 == 0 {
Ok("even steven")
} else {
Err("odd steven")
};
assert_eq!(x, Err("odd steven"));
That you can include doc-comments in macros:
macro_rules! documented {
(
$(#[$outer:meta])*
$name:ident
) => {
$(#[$outer])*
fn $name(&self) {}
};
}
documented!(
/// documented
my_function
);
my_function(); // hovering "function" now shows that the doc-comment is "documented"
That in Rust, assert! runs in both debug and release builds. For debug-only assertions, use debug_assert!. See https://doc.rust-lang.org/stable/std/macro.debug_assert.html.
That in Python, you can call isinstance(thing, (tuple, OfMany, DifferentClasses)) to check if a variable is an instance of many possible classes.
See https://docs.python.org/3/library/functions.html?highlight=isinstance#isinstance.
The string “0.1.12” is a version requirement. Although it looks like a specific version of the time crate, it actually specifies a range of versions and allows SemVer compatible updates.
– https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
Instead, in order to lock to a specific version of a crate, you need to write
= 0.1.2.
That you can destructure struct values:
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x: a, y: b } = p;
assert_eq!(0, a);
assert_eq!(7, b);
}
see https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html#destructuring-structs
By default, a closure seems to live as long as its parent function unless you use the move keyword.
fn unmoved<'a>(arg: &'a str) -> impl Fn() + 'a {
let f = || println!("unmoved: {}", arg);
f
}
fn moved<'a>(arg: &'a str) -> impl Fn() + 'a {
let f = move || println!("moved: {}", arg);
f
}
fn main() {
unmoved("a")() // does not compile
moved("b")() // works fine
}
That Option<T> costs ~1x the alignment value of T.
I also learned Vec<T>’s size and alignment don’t reflect the size and alignment of T since the Vec is tracking an owned buffer on the heap which isn’t counted in the Vec’s own size.
struct Alone8(u8); // size= 1, align=1
struct Opt8(Option<u8>); // size= 2, align=1
struct Vec8(Vec<u8>); // size=24; align=8
struct Alone64(u64); // size= 8, align=8
struct Opt64(Option<u64>); // size=16, align=8
struct Vec64(Vec<u64>); // size=24; align=8
That Firefox bundles process and task managers for performance monitoring, available at about:processes and about:tasks, respectively
https://support.mozilla.org/en-US/kb/task-manager-tabs-or-extensions-are-slowing-firefox
Turns out Rust does support Any-types and downcasting: see https://doc.rust-lang.org/std/any/index.html and https://doc.rust-lang.org/std/any/struct.TypeId.html .
That rust has built-in numeric types named like NonZero* that reserve the bit-pattern of 0 as a niche: see https://doc.rust-lang.org/core/num/index.html.
This is useful since that niche will absorb the cost of wrapping a NonZero int with Option:
use core::num::NonZeroU8;
use std::mem::size_of;
struct Struct<T>{ // has alignment 2, size 4
a: u16,
b: T,
}
fn main() {
println!(" NonZeroU8: {}", size_of::<NonZeroU8>());
println!(" Option<NonZeroU8>: {}", size_of::<Option<NonZeroU8>>());
println!(" Struct<NonZeroU8>: {}", size_of::<Struct<NonZeroU8>>());
println!("Option<Struct<NonZeroU8>: {}", size_of::<Option<Struct<NonZeroU8>>>());
}
# NonZeroU8: 1
# Option<NonZeroU8>: 1
# Struct<NonZeroU8>: 4
# Option<Struct<NonZeroU8>: 4
That you can add #![warn(missing_docs)] at the top of a lib.rs file to lint for undocumented public methods.
That you can write
fn foo<const N: usize>(arr: &[u8; N]) {
todo!()
}
to specialize a function for different array sizes, etc. You can use the following types in const generics:
See https://doc.rust-lang.org/reference/items/generics.html#const-generics See also https://blog.cocl2.com/posts/const-currying-rs/
That a go.work file can point to local “main modules” used for minimum-version selection.
go will maintain a separate go.work.sum file with the checksums of the workspace’s dependencies.
go work {init,use,edit} manages the work-files.
$GOWORK pointing to a file named like *.work can switch between multiple workspace files.
See https://go.dev/ref/mod#workspaces; the syntax of *.work files is roughly equivalent to the syntax in go.mod.
That none of the following options ensure unused debug info is not included in rust wasm output:
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
Commenting each line and rebuilding with --target=wasm32-unknown-unknown --release resulted in 0% change in output .wasm size.
In each experiment, twiggy garbage ./target/wasm*/release/my_lib.wasm reported
Bytes │ Size % │ Garbage Item
────────┼────────┼─────────────────────────────────────────
280220 ┊ 33.30% ┊ custom section '.debug_str'
181364 ┊ 21.55% ┊ custom section '.debug_info'
159353 ┊ 18.94% ┊ custom section '.debug_line'
96881 ┊ 11.51% ┊ custom section '.debug_pubnames'
87936 ┊ 10.45% ┊ custom section '.debug_ranges'
2030 ┊ 0.24% ┊ custom section '.debug_abbrev'
342 ┊ 0.04% ┊ custom section '.debug_pubtypes'
67 ┊ 0.01% ┊ custom section 'producers'
28 ┊ 0.00% ┊ custom section 'target_features'
808221 ┊ 96.05% ┊ Σ [9 Total Rows]
I cut those sections out using the 2-year-old recipe from https://github.com/Xe/x/blob/c87eb51e0afe78a958eecaffb83318f91c6f78dd/web/mastosan/README.md:
wasm-opt -oZ ...
wasm-snip \
--skip-producers-section \
--snip-rust-panicking-code \
--snip-rust-fmt-code \
...
That a cargo package can have only one library: see https://doc.rust-lang.org/cargo/reference/cargo-targets.html#library.