Today I Learned

tags


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"));

2022/12/10

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"

h/t https://stackoverflow.com/a/33999625/6571327


2023/02/08

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.


2023/03/04

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.


2023/05/24

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


2023/06/18

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
}

playground link


2023/06/19

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


2023/12/23

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 .


2024/02/12

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

playground link


2024/03/10

That you can add #![warn(missing_docs)] at the top of a lib.rs file to lint for undocumented public methods.


2024/04/13

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/


2024/05/04

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 \
  ...

2024/06/23

That a cargo package can have only one library: see https://doc.rust-lang.org/cargo/reference/cargo-targets.html#library.