role_system/
macros.rs

1//! Convenience macros for the role system.
2
3/// Macro for creating multiple permissions with a clean syntax.
4///
5/// # Examples
6///
7/// ```rust
8/// use role_system::permissions;
9///
10/// let perms = permissions![
11///     "read" => "documents",
12///     "write" => "documents",
13///     "delete" => "documents"
14/// ];
15/// ```
16#[macro_export]
17macro_rules! permissions {
18    ($($action:expr => $resource:expr),* $(,)?) => {
19        vec![$(
20            $crate::permission::Permission::new($action, $resource)
21        ),*]
22    };
23}
24
25/// Macro for creating a role with permissions in a single expression.
26///
27/// # Examples
28///
29/// ```rust
30/// use role_system::role_with_permissions;
31///
32/// let role = role_with_permissions! {
33///     name: "editor",
34///     description: "Content editor role",
35///     permissions: [
36///         "read" => "documents",
37///         "write" => "documents",
38///         "create" => "documents"
39///     ]
40/// };
41/// ```
42#[macro_export]
43macro_rules! role_with_permissions {
44    (
45        name: $name:expr,
46        description: $desc:expr,
47        permissions: [
48            $($action:expr => $resource:expr),* $(,)?
49        ]
50    ) => {
51        {
52            let mut role = $crate::role::Role::new($name).with_description($desc);
53            $(
54                role = role.add_permission($crate::permission::Permission::new($action, $resource));
55            )*
56            role
57        }
58    };
59    (
60        name: $name:expr,
61        permissions: [
62            $($action:expr => $resource:expr),* $(,)?
63        ]
64    ) => {
65        {
66            let mut role = $crate::role::Role::new($name);
67            $(
68                role = role.add_permission($crate::permission::Permission::new($action, $resource));
69            )*
70            role
71        }
72    };
73}
74
75/// Macro for creating subjects with different types.
76///
77/// # Examples
78///
79/// ```rust
80/// use role_system::subjects;
81///
82/// let (admin, service, device) = subjects! {
83///     user "admin" => display_name: "Administrator",
84///     service "api_service" => display_name: "API Service",
85///     device "printer_01" => display_name: "Office Printer"
86/// };
87/// ```
88#[macro_export]
89macro_rules! subjects {
90    (
91        $(
92            $type:ident $id:expr => display_name: $name:expr
93        ),* $(,)?
94    ) => {
95        ($(
96            $crate::subject::Subject::$type($id).with_display_name($name)
97        ),*)
98    };
99    (
100        $(
101            $type:ident $id:expr
102        ),* $(,)?
103    ) => {
104        ($(
105            $crate::subject::Subject::$type($id)
106        ),*)
107    };
108}
109
110/// Macro for defining conditional permissions with context requirements.
111///
112/// # Examples
113///
114/// ```rust
115/// use role_system::conditional_permission;
116///
117/// let perm = conditional_permission! {
118///     action: "access",
119///     resource: "secure_area",
120///     condition: |context| {
121///         context.get("clearance_level") == Some(&"top_secret".to_string()) &&
122///         context.get("time_of_day") == Some(&"business_hours".to_string())
123///     }
124/// };
125/// ```
126#[macro_export]
127macro_rules! conditional_permission {
128    (
129        action: $action:expr,
130        resource: $resource:expr,
131        condition: $condition:expr
132    ) => {
133        $crate::permission::Permission::with_condition($action, $resource, $condition)
134    };
135}
136
137#[cfg(test)]
138mod tests {
139    use std::collections::HashMap;
140
141    #[test]
142    fn test_permissions_macro() {
143        let perms = permissions![
144            "read" => "documents",
145            "write" => "documents",
146            "delete" => "documents"
147        ];
148
149        assert_eq!(perms.len(), 3);
150        assert_eq!(perms[0].action(), "read");
151        assert_eq!(perms[0].resource_type(), "documents");
152    }
153
154    #[test]
155    fn test_role_with_permissions_macro() {
156        let role = role_with_permissions! {
157            name: "editor",
158            description: "Content editor role",
159            permissions: [
160                "read" => "documents",
161                "write" => "documents"
162            ]
163        };
164
165        assert_eq!(role.name(), "editor");
166        assert_eq!(role.description(), Some("Content editor role"));
167        assert_eq!(role.permissions().permissions().len(), 2);
168    }
169
170    #[test]
171    fn test_subjects_macro() {
172        let (admin, service) = subjects! {
173            user "admin_user" => display_name: "Administrator",
174            service "api_service" => display_name: "API Service"
175        };
176
177        assert_eq!(admin.id(), "admin_user");
178        assert_eq!(admin.display_name(), Some("Administrator"));
179        assert_eq!(service.id(), "api_service");
180        assert_eq!(service.display_name(), Some("API Service"));
181    }
182
183    #[test]
184    fn test_conditional_permission_macro() {
185        let perm = conditional_permission! {
186            action: "access",
187            resource: "secure_area",
188            condition: |context: &HashMap<String, String>| {
189                context.get("clearance") == Some(&"top_secret".to_string())
190            }
191        };
192
193        assert_eq!(perm.action(), "access");
194        assert_eq!(perm.resource_type(), "secure_area");
195
196        let mut valid_context = HashMap::new();
197        valid_context.insert("clearance".to_string(), "top_secret".to_string());
198        assert!(perm.is_granted("access", "secure_area", &valid_context));
199
200        let invalid_context = HashMap::new();
201        assert!(!perm.is_granted("access", "secure_area", &invalid_context));
202    }
203}