#[macro_export]
macro_rules! permissions {
($($action:expr => $resource:expr),* $(,)?) => {
vec![$(
$crate::permission::Permission::new($action, $resource)
),*]
};
}
#[macro_export]
macro_rules! role_with_permissions {
(
name: $name:expr,
description: $desc:expr,
permissions: [
$($action:expr => $resource:expr),* $(,)?
]
) => {
{
let mut role = $crate::role::Role::new($name).with_description($desc);
$(
role = role.add_permission($crate::permission::Permission::new($action, $resource));
)*
role
}
};
(
name: $name:expr,
permissions: [
$($action:expr => $resource:expr),* $(,)?
]
) => {
{
let mut role = $crate::role::Role::new($name);
$(
role = role.add_permission($crate::permission::Permission::new($action, $resource));
)*
role
}
};
}
#[macro_export]
macro_rules! subjects {
(
$(
$type:ident $id:expr => display_name: $name:expr
),* $(,)?
) => {
($(
$crate::subject::Subject::$type($id).with_display_name($name)
),*)
};
(
$(
$type:ident $id:expr
),* $(,)?
) => {
($(
$crate::subject::Subject::$type($id)
),*)
};
}
#[macro_export]
macro_rules! conditional_permission {
(
action: $action:expr,
resource: $resource:expr,
condition: $condition:expr
) => {
$crate::permission::Permission::with_condition($action, $resource, $condition)
};
}
#[macro_export]
macro_rules! define_role {
(
$role_name:ident {
$(
$resource:ident: [$($action:literal),* $(,)?]
),* $(,)?
}
) => {
{
let mut builder = $crate::role::RoleBuilder::new().name(stringify!($role_name));
$(
let resource = stringify!($resource);
let actions = vec![$($action),*];
builder = builder.allow(resource, actions);
)*
builder.build().expect("Failed to build role")
}
};
}
#[macro_export]
macro_rules! define_roles {
(
$(
$role_name:ident {
$(
$resource:ident: [$($action:literal),* $(,)?]
),* $(,)?
}
),* $(,)?
) => {
{
use std::collections::HashMap;
let mut roles = HashMap::new();
$(
let mut builder = $crate::role::RoleBuilder::new().name(stringify!($role_name));
$(
let resource = stringify!($resource);
let actions = vec![$($action),*];
builder = builder.allow(resource, actions);
)*
let role = builder.build().expect("Failed to build role");
roles.insert(stringify!($role_name).to_string(), role);
)*
roles
}
};
}
#[macro_export]
macro_rules! permission {
($resource:literal, $action:literal) => {
$crate::permission::Permission::new($action, $resource)
};
($resource:literal, [$($action:literal),* $(,)?]) => {
vec![$(
$crate::permission::Permission::new($action, $resource)
),*]
};
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
#[test]
fn test_permissions_macro() {
let perms = permissions![
"read" => "documents",
"write" => "documents",
"delete" => "documents"
];
assert_eq!(perms.len(), 3);
assert_eq!(perms[0].action(), "read");
assert_eq!(perms[0].resource_type(), "documents");
}
#[test]
fn test_role_with_permissions_macro() {
let role = role_with_permissions! {
name: "editor",
description: "Content editor role",
permissions: [
"read" => "documents",
"write" => "documents"
]
};
assert_eq!(role.name(), "editor");
assert_eq!(role.description(), Some("Content editor role"));
assert_eq!(role.permissions().permissions().len(), 2);
}
#[test]
fn test_subjects_macro() {
let (admin, service) = subjects! {
user "admin_user" => display_name: "Administrator",
service "api_service" => display_name: "API Service"
};
assert_eq!(admin.id(), "admin_user");
assert_eq!(admin.display_name(), Some("Administrator"));
assert_eq!(service.id(), "api_service");
assert_eq!(service.display_name(), Some("API Service"));
}
#[test]
fn test_conditional_permission_macro() {
let perm = conditional_permission! {
action: "access",
resource: "secure_area",
condition: |context: &HashMap<String, String>| {
context.get("clearance") == Some(&"top_secret".to_string())
}
};
assert_eq!(perm.action(), "access");
assert_eq!(perm.resource_type(), "secure_area");
let mut valid_context = HashMap::new();
valid_context.insert("clearance".to_string(), "top_secret".to_string());
assert!(perm.is_granted("access", "secure_area", &valid_context));
let invalid_context = HashMap::new();
assert!(!perm.is_granted("access", "secure_area", &invalid_context));
}
#[test]
fn test_define_role_macro() {
let role = define_role!(admin {
users: ["create", "read", "update", "delete"],
roles: ["assign", "remove"]
});
assert_eq!(role.name(), "admin");
assert_eq!(role.permissions().len(), 6); }
#[test]
fn test_permission_macro() {
let single_perm = permission!("users", "read");
assert_eq!(single_perm.action(), "read");
assert_eq!(single_perm.resource_type(), "users");
let multi_perms = permission!("posts", ["create", "update", "delete"]);
assert_eq!(multi_perms.len(), 3);
}
#[test]
fn test_define_roles_macro() {
let roles = define_roles! {
admin {
users: ["create", "read", "update", "delete"],
roles: ["assign"]
},
user {
profile: ["read", "update"],
posts: ["create"]
}
};
assert_eq!(roles.len(), 2);
assert!(roles.contains_key("admin"));
assert!(roles.contains_key("user"));
let admin_role = &roles["admin"];
assert_eq!(admin_role.name(), "admin");
assert_eq!(admin_role.permissions().len(), 5); }
}