#named #named-arguments #arguments #proc-macro #rust-patterns

macro named-ctor

proc-macro to generate constructor functions with syntaxt similar to named params

1 unstable release

0.1.1 Sep 30, 2023
0.1.0 Sep 30, 2023

#1613 in Procedural macros

MIT license

11KB
142 lines

named-ctor

Procedural macro to generate an alternative of named parameters with native Rust.

Named parameters alternative

Rust don't has support for named parameters, but is possible to use a simulation with data structures. This alternative is special easy to implement in Rust tanks to From trait.

For example:

pub struct User {
    id: u8,
    name: String,
    email: String,
    password: String,
    is_active: bool,
    is_admin: bool,
}

impl User {
    // ...
}

pub struct UserValues {
    id: u8,
    name: String,
    email: String,
    password: String,
    is_active: bool,
    is_admin: bool,
}

impl From<UserValues> for User {
    fn from(aux: UserValues) -> Self {
        Self {
            id: aux.id,
            name: aux.name,
            email: aux.email,
            password: aux.password,
            is_active: aux.is_active,
            is_admin: aux.is_admin,
        }
    }
}

pub fn main() {
    let user: User = User::from(UserValues {
        id: 0,
        email: "john@doe.com".to_string(),
        name: "John Doe".to_string(),
        is_active: true,
        password: "1234".to_string(),
        is_admin: false,
    });
}

Whats the problem? First, too boilerplate. Second, its not easy to maintain, if User is modified, is absolutely necessary modify UserValues.

Using NamedCtor macro

The behavior is the same as last example, but now the macro is the responsable to create both aux struct (_User) and From implementation.

use named_ctor::NamedCtor;

#[derive(NamedCtor)]
pub struct User {
    id: u8,
    name: String,
    email: String,
    password: String,
    is_active: bool,
    is_admin: bool,
}

impl User {
    // ...
}

pub fn main() {
    let user: User = User::from(_User {
        id: 0,
        email: "john@doe.com".to_string(),
        name: "John Doe".to_string(),
        is_active: true,
        password: "1234".to_string(),
        is_admin: false,
    });
}

Macro attributes

Is possible to use a custom name for the axiliar struct, and change the constructor function:

use named_ctor::NamedCtor;
use core::fmt::Display;
#[derive(NamedCtor)]
#[named_ctor(name = "TaskInitValues", constructor = "new")]
pub struct Task<'a, T>
where
    T: Display
{
    id: T,
    name: &'a str,
}
let user: Task<&str> = Task::new(TaskInitValues {
    id: "example.id",
    name: "Example",
});

WARNING: Generics support only via where clause

Dependencies

~1.5MB
~37K SLoC