3 releases

0.1.2 Oct 28, 2023
0.1.1 Oct 28, 2023
0.1.0 Oct 28, 2023

#1705 in Procedural macros

MIT/Apache

17KB
107 lines

Behavior

crates.io docs.rs

A macro checks like "behavior" in elixir language.

Example

The "behavior" is defined as a trait whose methods are all static methods. And behavior::behavior macro checks if all given modules implement behavior trait.

use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct User {
    name: String,
    age: u8,
}

#[behavior::behavior(modules(original, fake))] // check behaviors
#[async_trait::async_trait]
trait MyBehavior {
    async fn get<T: DeserializeOwned>(url: String) -> T;
    fn post_user<'a>(url: String, user: &'a User) -> u16;
}

mod original {
    use super::User;

    pub async fn get<T: serde::de::DeserializeOwned>(url: String) -> T {
        let res = reqwest::Client::new().get(&url).send().await.unwrap();

        res.json().await.unwrap()
    }
    pub fn post_user(url: String, user: &User) -> u16 {
        reqwest::blocking::Client::new()
            .post(&url)
            .json(user)
            .send()
            .unwrap()
            .status()
            .as_u16()
    }
}

mod fake {
    use super::User;

    pub async fn get<T: serde::de::DeserializeOwned>(_url: String) -> T {
        serde_json::from_str("{}").unwrap()
    }

    pub fn post_user(_url: String, _user: &User) -> u16 {
        200
    }
}

It is useful to guarantee the APIs when using feature flag.

#[cfg(feature = "fake")]
pub use fake::*;
#[cfg(not(feature = "fake"))]
pub use original::*;

Because the macro generates a type which implement behavior trait for each module (in the example, FakeModuleMyBehavior and OriginalModuleMyBehavior), you can use behavior as normal trait. But it is not recommended.

Dependencies

~0.6–1MB
~23K SLoC