#partial #traits #instance #relaxed #struct #derive #type

relax

Traits for TypeScript-like partial (“relaxed”) types

11 releases

0.1.0-alpha.11 Aug 20, 2024
0.1.0-alpha.10 Aug 16, 2024
0.1.0-alpha.8 Jul 20, 2024

#1005 in Rust patterns

34 downloads per month

MIT/Apache

6KB

relax

Traits for TypeScript-like partial (“relaxed”) types

Usage

Generate “relaxed” types

use relax::Relax;

#[derive(Relax)]
#[relax(PartialData)]
pub(crate) struct Data {
    id: u16,
    pub name: String,
    pub favorite: Option<String>,
}

yields the following partial (“relaxed”) struct:

pub(crate) struct PartialData {
    id: Option<u16>,
    pub name: Option<String>,
    pub favorite: Option<String>,
}

Nesting is also supported:

use relax::Relax;

#[derive(Relax)]
#[relax(PartialFoo)]
struct Foo {
    id: u16,
    #[relax]
    bar: Bar,
    #[relax]
    bar2: Option<Bar>,
}

#[derive(Relax)]
#[relax(PartialBar)]
struct Bar {
    name: String,
    favorite: Option<String>,
}

yields

struct PatrialFoo {
    id: Option<u16>,
    bar: Option<PartialBar>,
    bar2: Option<PartialBar>,
}

struct PartialBar {
    name: Option<String>,
    favorite: Option<String>,
}

You can also add attributes to generated structs:

use relax::Relax;
use serde::{Serialize, Deserialize};

#[derive(Relax)]
#[relax(PartialData, derive(Serialize, Deserialize), serde(rename_all = "UPPERCASE"))]
pub(crate) struct Data {
    id: u16,
    pub name: String,
    pub favorite: Option<String>,
}

yields

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub(crate) struct PartialData {
    id: Option<u16>,
    pub name: Option<String>,
    pub favorite: Option<String>,
}

Create empty “relaxed” instances

Relaxed structs derive Relaxed trait, which has new associated function.

use relax::{Relax, Relaxed};

#[derive(Relax)]
#[relax(PartialData, derive(Debug, PartialEq))]
pub(crate) struct Data {
    id: u16,
    pub name: String,
    pub favorite: Option<String>,
}

# fn main() {
let empty = PartialData {
    id: None,
    name: None,
    favorite: None,
};

assert_eq!(PartialData::new(), empty);
# }

Combine multiple “relaxed” instances

Relaxed trait also has merge function. The behavior is similar to Option::or, except that this function is applied for each struct field.

use relax::{Relax, Relaxed};

#[derive(Relax)]
#[relax(PartialData, derive(Debug, PartialEq))]
pub(crate) struct Data {
    id: u16,
    pub name: String,
    pub favorite: Option<String>,
}

# fn main() {

let partial_data_1 = PartialData {
    id: None,
    name: Some("John".to_owned()),
    favorite: None,
};

let partial_data_2 = PartialData {
    id: None,
    name: None,
    favorite: Some("Rust".to_owned()),
};

let merged = partial_data_1.merge(partial_data_2);

let expected = PartialData {
    id: None,
    name: Some("John".to_owned()),
    favorite: Some("Rust".to_owned()),
};

assert_eq!(merged, expected);

# }

Create an original struct instance from a relaxed instance

If all the required fields of the original struct are set in a relaxed struct instance, you can use try_into() to convert it to the original struct.

use relax::{Relax, Relaxed};

let partial_data_1: PartialData = read_data(file_1);
let partial_data_2: PartialData = read_data(file_2);
let partial_data_3: PartialData = read_data(file_3);

let data: Data = partial_data_1
                    .merge(partial_data_2)
                    .merge(partial_data_3)
                    .try_into()?;

Dependencies

~105KB