born 0.0.0

Reuse fields from Struct and Enum definition with functional macros.
Documentation

Reuse(Struct, Enum)

Build Status Image Crate Image Doc Dependency Status

It provides functional macros to reuse fields from Struct and Enum definition.

[dependencies]
born = "0.0.0"

Examples

Struct

Say you build a demo web server to send private messages.

use born::{
    nested_macro,
    public_struct,
};

// Define your base public struct here.
public_struct!(
    // pub is required here before struct
    pub struct MessageBase {
        pub text: String
        // pub text: String // , is not required for the struct definition.
    }
);

MessageBase!(
    #[derive(Debug, Clone, PartialEq)]
    pub struct Message {
        pub read: bool,
        // read: bool, // pub is optional.
    }
);

impl Message {
    fn update_text(&mut self, new_message: String) {
        self.text = new_message
    }
    fn read(&mut self) {
        if self.read == false {
            self.read = true;
        }
    }
}

MessageBase!(
    #[derive(Debug, Clone, PartialEq)]
    pub struct MessageCreateRequest
);

MessageBase!(
    // #[derive(Debug, Clone, PartialEq)]
    pub struct MessageUpdateRequest
);

fn main() {
    let message_create_request = MessageCreateRequest {
        text: "I am Steadylearner and 'born' is the crate name.".into(),
    };

    let mut message = Message {
        text: message_create_request.text,
        read: false,
    };
    println!("{:#?}", &message);

    assert_eq!(message, message.clone());

    let message_update_request = MessageUpdateRequest {
        text: "Reuse fields with macros from 'born'.".into(),
    };

    message.update_text(message_update_request.text);
    println!("{:#?}", &message);

    message.read();
    println!("{:#?}", &message);
}

Enum

Compare it with the code example from the Rust documenation for Enum.

use born::{
    nested_macro,
    private_enum,
};

// Define your base private enum here.
private_enum!(
    enum WebEventBase {
        PageLoad,
        PageUnload, // , here is required if you want to extend it.
    }
);

WebEventBase!(
    // #[derive(Debug, Clone, PartialEq)]
    enum WebEvent {
        KeyPress(char),
        Click { x: i64, y: i64 },
        Paste(String),
    }
);

fn inspect(event: WebEvent) {
    match event {
        WebEvent::PageLoad => println!("page loaded"),
        WebEvent::PageUnload => println!("page unloaded"),
        WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
        WebEvent::Paste(s) => println!("pasted \"{}\".", s),
        WebEvent::Click { x, y } => {
            println!("clicked at x={}, y={}.", x, y);
        },
    }
}

fn main() {
    let pressed = WebEvent::KeyPress('x');
    let pasted  = WebEvent::Paste("my text".to_owned());
    let click   = WebEvent::Click { x: 20, y: 80 };
    let load    = WebEvent::PageLoad;
    let unload  = WebEvent::PageUnload;

    inspect(pressed);
    inspect(pasted);
    inspect(click);
    inspect(load);
    inspect(unload);
}

Rename

You can rename the struct and reuse the same fields. You can do the same with enum.

use born::{
    nested_macro,
    public_struct,
};

public_struct!(
    pub struct UserBase {
        pub first_name: String,
        pub last_name: String,
        pub email: String,
        pub password: String,
    }
);

UserBase!(
    pub struct User {
        pub id: i64,
    }
);

UserBase!(
    pub struct NewUser
);

// It is equal to code it manually.

// pub struct User {
//     pub id: i64,
//     pub first_name: String,
//     pub last_name: String,
//     pub email: String,
//     pub password: String,
// }

// pub struct NewUser {
//     pub first_name: String,
//     pub last_name: String,
//     pub email: String,
//     pub password: String,
// }

Details

  • Each struct and enum created from the macros are completely unrelevant to each other except they have the same fields you define.

  • When you use private_struct! and private_enum!, you can't use pub keyword in it and others use them. It wouldn't be logical if a private struct or private enum can have public fields.

  • nested_macro! is required to use the other macros from this crate. It is used to make a macro that creates other macros.

macro_rules! nested_macro {
    ($($body:tt)*) => {
        macro_rules! __nested_macro { $($body)+ }
        __nested_macro!($);
    }
}

Comparison with attribute macro

How to test it

$git clone git@github.com:steadylearner/born.git && cargo test pass
  1. $cargo test pass to run passing tests.
  2. $cargo test fail to run failing tests. You need to install trybuild first.

If you want to see how the macros from this package expand, use $cargo test macros. You need to install rustfmt and cargo-expand to use it before.

$rustup component add rustfmt && cargo install cargo-expand

macrotest is based on trybuild. They are not that compatible to test with a single command and take long time.

They make cargo to redownload the dependendencies and recompile everytime. For that reason, there are commands to test them separately.

License