13 releases

0.1.1 Nov 7, 2024
0.1.0 Oct 19, 2024
0.1.0-alpha.11 Aug 20, 2024
0.1.0-alpha.8 Jul 20, 2024

#902 in Rust patterns

Download history 231/week @ 2024-08-16 14/week @ 2024-08-23 17/week @ 2024-09-13 4/week @ 2024-09-20 12/week @ 2024-09-27 1/week @ 2024-10-04 172/week @ 2024-10-18 6/week @ 2024-10-25 54/week @ 2024-11-01 60/week @ 2024-11-08 6/week @ 2024-11-15 3/week @ 2024-11-22 2/week @ 2024-11-29

125 downloads per month

MIT/Apache

11KB

relax

Derive 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>,
}

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>,
}

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

~100KB