Macro spread

Source
spread!() { /* proc-macro */ }
Expand description

Extension of the spread/struct update syntax that allow taking fields from different type structs, as long as the listed fields have the same type in both structs.

It can be used with structs that don’t have sensible defaults for each fields by using another struct that only have the fields with sensible defaults.

Fields can be listed as follows:

  • field,: field which captures a variable of the same name
  • field: value,: field with provided value
  • { field1, field2 } in source,: fields extracted from another struct
  • ..remaining: same as in struct update syntax, can only appear last without a trailing comma

Each field name can be prefixed by a modifier allowing to perform common transformations that usually requires repeating the field name. They are placed before the field and mean the following:

  • &field: take the reference, convert a T field to &T
  • &mut field: take the mutable reference, convert a T field to &mut T
  • +field: clones the value, can be used with &source to not consume the source
  • >field: converts the value with Into
  • +>field: clones then converts the value with Into, can be used with &source to not consume the source
  • [path] field: pass the value to function at path. This path can contain module separators and turbofish. You can use this to perform custom transformations, or use more explicit alternatives to + and >. field can be prefixed with & or &mut to pass a reference to the function instead of moving/copying it.

Here is an exemple showing all the modifers:

use spread_macros::spread;

fn to_lowercase(s: impl AsRef<str>) -> String {
    s.as_ref().to_lowercase()
}

#[derive(Debug)]
struct Foo<'a> {
    name: u32,
    name_ref: &'a u32,
    name_ref_mut: &'a mut u32,
    name_into: u64,
    name_clone: u32,
    name_clone_into: u64,
    custom: String,

    value: u32,

    spread: u32,
    spread_ref: &'a u32,
    spread_ref_mut: &'a mut u32,
    spread_into: u64,
    spread_clone: u32,
    spread_clone_into: u64,
    spread_custom: String,

    other: u32,
}

#[derive(Clone, Debug, Default)]
struct Bar {
    spread: u32,
    spread_ref: u32,
    spread_ref_mut: u32,
    spread_into: u32,
    spread_clone: u32,
    spread_clone_into: u32,
    spread_custom: String,

    other: u32,
}

let mut bar = Bar::default();
let name = 42u32;
let name_ref = 42u32;
let name_into = 42u32;
let name_clone = 42u32;
let name_clone_into = 42u32;
let mut name_ref_mut = 42u32;
let custom = "HELLO WORLD";

let first = spread!(Foo {
    name,
    &name_ref,
    &mut name_ref_mut,
    >name_into,
    +name_clone,
    +>name_clone_into,
    value: 42,
    [to_lowercase] custom,
    {
        spread,
        &spread_ref,
        &mut spread_ref_mut,
        >spread_into,
        +spread_clone,
        +>spread_clone_into,
        [to_lowercase] &spread_custom,
    } in &mut bar,
    >other: 42u16,
});

let second = spread!(Foo {
    name,
    >name_into,
    +name_clone,
    +>name_clone_into,
    value: 42,
    [to_lowercase] custom,
    ..first
});