role_system/
async_support.rs

1//! Async support for the role system (requires 'async' feature).
2
3use crate::{
4    core::{RoleSystem, RoleSystemConfig},
5    error::Result,
6    resource::Resource,
7    role::Role,
8    storage::Storage,
9    subject::Subject,
10};
11use std::{
12    collections::{HashMap, HashSet},
13    sync::Arc,
14    time::Duration,
15};
16use tokio::sync::{Mutex, RwLock};
17
18/// Async wrapper around the role system for non-blocking operations.
19pub struct AsyncRoleSystem<S>
20where
21    S: Storage + Send + Sync,
22{
23    inner: Arc<RwLock<RoleSystem<S>>>,
24}
25
26impl<S> AsyncRoleSystem<S>
27where
28    S: Storage + Send + Sync,
29{
30    /// Create a new async role system.
31    pub fn new(role_system: RoleSystem<S>) -> Self {
32        Self {
33            inner: Arc::new(RwLock::new(role_system)),
34        }
35    }
36
37    /// Register a new role in the system.
38    pub async fn register_role(&self, role: Role) -> Result<()> {
39        let mut system = self.inner.write().await;
40        system.register_role(role)
41    }
42
43    /// Get a role by name.
44    pub async fn get_role(&self, name: &str) -> Result<Option<Role>> {
45        let system = self.inner.read().await;
46        system.get_role(name)
47    }
48
49    /// Add role inheritance (child inherits from parent).
50    pub async fn add_role_inheritance(&self, child: &str, parent: &str) -> Result<()> {
51        let mut system = self.inner.write().await;
52        system.add_role_inheritance(child, parent)
53    }
54
55    /// Remove role inheritance.
56    pub async fn remove_role_inheritance(&self, child: &str, parent: &str) -> Result<()> {
57        let mut system = self.inner.write().await;
58        system.remove_role_inheritance(child, parent)
59    }
60
61    /// Assign a role to a subject.
62    pub async fn assign_role(&self, subject: &Subject, role_name: &str) -> Result<()> {
63        let mut system = self.inner.write().await;
64        system.assign_role(subject, role_name)
65    }
66
67    /// Remove a role from a subject.
68    pub async fn remove_role(&self, subject: &Subject, role_name: &str) -> Result<()> {
69        let mut system = self.inner.write().await;
70        system.remove_role(subject, role_name)
71    }
72
73    /// Temporarily elevate a subject's role.
74    pub async fn elevate_role(
75        &self,
76        subject: &Subject,
77        role_name: &str,
78        duration: Option<Duration>,
79    ) -> Result<()> {
80        let mut system = self.inner.write().await;
81        system.elevate_role(subject, role_name, duration)
82    }
83
84    /// Check if a subject has a specific permission on a resource.
85    pub async fn check_permission(
86        &self,
87        subject: &Subject,
88        action: &str,
89        resource: &Resource,
90    ) -> Result<bool> {
91        let system = self.inner.read().await;
92        system.check_permission(subject, action, resource)
93    }
94
95    /// Check permission with additional context.
96    pub async fn check_permission_with_context(
97        &self,
98        subject: &Subject,
99        action: &str,
100        resource: &Resource,
101        context: &HashMap<String, String>,
102    ) -> Result<bool> {
103        let system = self.inner.read().await;
104        system.check_permission_with_context(subject, action, resource, context)
105    }
106
107    /// Get all roles assigned to a subject.
108    pub async fn get_subject_roles(&self, subject: &Subject) -> Result<HashSet<String>> {
109        let system = self.inner.read().await;
110        system.get_subject_roles(subject)
111    }
112
113    /// Batch check multiple permissions for a subject.
114    pub async fn batch_check_permissions(
115        &self,
116        subject: &Subject,
117        checks: &[(String, Resource)], // (action, resource) pairs
118    ) -> Result<Vec<(String, Resource, bool)>> {
119        let system = self.inner.read().await;
120        let mut results = Vec::new();
121
122        for (action, resource) in checks {
123            let granted = system.check_permission(subject, action, resource)?;
124            results.push((action.clone(), resource.clone(), granted));
125        }
126
127        Ok(results)
128    }
129
130    /// Perform multiple role operations atomically.
131    pub async fn atomic_role_operations<F, R>(&self, operations: F) -> Result<R>
132    where
133        F: FnOnce(&mut RoleSystem<S>) -> Result<R> + Send,
134    {
135        let mut system = self.inner.write().await;
136        operations(&mut *system)
137    }
138
139    /// Get a read-only reference to the role system for complex queries.
140    pub async fn with_read_access<F, R>(&self, operation: F) -> R
141    where
142        F: FnOnce(&RoleSystem<S>) -> R + Send,
143    {
144        let system = self.inner.read().await;
145        operation(&*system)
146    }
147
148    // Hierarchy traversal methods for optional hierarchy access
149
150    /// Get the complete hierarchy tree structure.
151    ///
152    /// This method provides a structured view of the entire role hierarchy,
153    /// useful for visualization, API responses, and external system integration.
154    ///
155    /// # Arguments
156    /// * `config` - Optional hierarchy configuration. If None, uses default settings.
157    ///
158    /// # Returns
159    /// A `RoleHierarchyTree` containing the complete hierarchy structure with metadata.
160    ///
161    /// # Example
162    /// ```rust
163    /// # use role_system::{AsyncRoleSystem, RoleSystem, RoleSystemConfig, MemoryStorage};
164    /// # use role_system::hierarchy::HierarchyConfigBuilder;
165    /// # tokio_test::block_on(async {
166    /// let storage = MemoryStorage::new();
167    /// let role_sys = RoleSystem::with_storage(storage, RoleSystemConfig::default());
168    /// let role_system = AsyncRoleSystem::new(role_sys);
169    ///
170    /// let config = HierarchyConfigBuilder::new()
171    ///     .enable_hierarchy_access(true)
172    ///     .max_depth(10)
173    ///     .build();
174    ///
175    /// let tree = role_system.get_hierarchy_tree(Some(config)).await?;
176    /// println!("Total roles: {}, Max depth: {}", tree.total_roles, tree.max_depth);
177    /// # Ok::<(), role_system::Error>(())
178    /// # });
179    /// ```
180    pub async fn get_hierarchy_tree(
181        &self,
182        config: Option<crate::hierarchy::HierarchyConfig>,
183    ) -> Result<crate::hierarchy::RoleHierarchyTree> {
184        use crate::hierarchy::{RoleHierarchyTree, RoleNode};
185        use std::time::Instant;
186
187        let config = config.unwrap_or_default();
188
189        if !config.enable_hierarchy_access {
190            return Err(crate::error::Error::InvalidResource(
191                "Hierarchy access is disabled in configuration".to_string(),
192            ));
193        }
194
195        let start_time = Instant::now();
196        let _system = self.inner.read().await;
197
198        // For now, create a simplified tree structure
199        // In a real implementation, this would use actual hierarchy data
200        let all_roles: Vec<crate::role::Role> = vec![];
201
202        if all_roles.is_empty() {
203            // Create empty tree
204            let empty_role = crate::role::Role::new("__empty__");
205            let root_node = RoleNode::new(empty_role, 0);
206            let mut tree = RoleHierarchyTree::new(root_node);
207            tree.metadata.generation_time_ms = start_time.elapsed().as_millis() as u64;
208            return Ok(tree);
209        }
210
211        // This would be implemented with actual hierarchy data
212        let empty_role = crate::role::Role::new("__empty__");
213        let root_node = RoleNode::new(empty_role, 0);
214        let mut tree = RoleHierarchyTree::new(root_node);
215        tree.metadata.generation_time_ms = start_time.elapsed().as_millis() as u64;
216        tree.metadata.total_permissions = 0;
217
218        Ok(tree)
219    }
220
221    /// Get all parent roles for a given role (ancestors).
222    ///
223    /// This method returns all roles that the specified role inherits from,
224    /// including both direct parents and inherited ancestors.
225    ///
226    /// # Arguments
227    /// * `role_id` - The ID of the role to get ancestors for
228    /// * `_include_inherited` - Whether to include inherited (indirect) parents
229    ///
230    /// # Returns
231    /// A vector of role IDs representing all ancestor roles.
232    ///
233    /// # Example
234    /// ```no_run
235    /// # use role_system::async_support::AsyncRoleSystem;
236    /// # #[tokio::main]
237    /// # async fn main() -> Result<(), role_system::Error> {
238    /// # let role_system = AsyncRoleSystem::new(role_system::RoleSystem::new());
239    /// let ancestors = role_system.get_role_ancestors("junior_dev", true).await?;
240    /// for ancestor_id in ancestors {
241    ///     println!("Inherits from: {}", ancestor_id);
242    /// }
243    /// # Ok(())
244    /// # }
245    /// ```
246    pub async fn get_role_ancestors(
247        &self,
248        role_id: &str,
249        _include_inherited: bool,
250    ) -> Result<Vec<String>> {
251        let system = self.inner.read().await;
252
253        // Verify role exists by attempting to get it
254        let _role = system.get_role(role_id)?;
255
256        // For now, return empty vector since individual roles don't track hierarchy
257        // In a real implementation, this would traverse the RoleHierarchy
258        Ok(Vec::new())
259    }
260
261    /// Get all child roles for a given role (descendants).
262    ///
263    /// This method returns all roles that inherit from the specified role,
264    /// including both direct children and inherited descendants.
265    ///
266    /// # Arguments
267    /// * `role_id` - The ID of the role to get descendants for
268    /// * `_include_inherited` - Whether to include inherited (indirect) children
269    ///
270    /// # Returns
271    /// A vector of role IDs representing all descendant roles.
272    ///
273    /// # Example
274    /// ```rust
275    /// # use role_system::{AsyncRoleSystem, RoleSystem, RoleSystemConfig, MemoryStorage};
276    /// # tokio_test::block_on(async {
277    /// let storage = MemoryStorage::new();
278    /// let role_sys = RoleSystem::with_storage(storage, RoleSystemConfig::default());
279    /// let role_system = AsyncRoleSystem::new(role_sys);
280    /// let descendants = role_system.get_role_descendants("team_lead", true).await?;
281    /// for descendant_id in descendants {
282    ///     println!("Has child: {}", descendant_id);
283    /// }
284    /// # Ok::<(), role_system::Error>(())
285    /// # });
286    /// ```
287    pub async fn get_role_descendants(
288        &self,
289        role_id: &str,
290        _include_inherited: bool,
291    ) -> Result<Vec<String>> {
292        let system = self.inner.read().await;
293
294        // Verify role exists by attempting to get it
295        let _role = system.get_role(role_id)?;
296
297        // For now, return empty vector since individual roles don't track hierarchy
298        // In a real implementation, this would traverse the RoleHierarchy
299        Ok(Vec::new())
300    }
301    /// Get all sibling roles for a given role.
302    ///
303    /// Sibling roles are roles that share the same parent in the hierarchy.
304    ///
305    /// # Arguments
306    /// * `role_id` - The ID of the role to get siblings for
307    ///
308    /// # Returns
309    /// A vector of role IDs representing all sibling roles.
310    ///
311    /// # Example
312    /// ```rust
313    /// # use role_system::{AsyncRoleSystem, RoleSystem, RoleSystemConfig, MemoryStorage};
314    /// # tokio_test::block_on(async {
315    /// let storage = MemoryStorage::new();
316    /// let role_sys = RoleSystem::with_storage(storage, RoleSystemConfig::default());
317    /// let role_system = AsyncRoleSystem::new(role_sys);
318    /// let siblings = role_system.get_role_siblings("senior_dev").await?;
319    /// for sibling_id in siblings {
320    ///     println!("Sibling role: {}", sibling_id);
321    /// }
322    /// # Ok::<(), role_system::Error>(())
323    /// # });
324    /// ```
325    pub async fn get_role_siblings(&self, role_id: &str) -> Result<Vec<String>> {
326        let system = self.inner.read().await;
327
328        // For now, return empty vector since individual roles don't track hierarchy
329        // In a real implementation, this would find roles with the same parent
330        let _role = system.get_role(role_id)?;
331
332        // This would be implemented using the RoleHierarchy system
333        Ok(Vec::new())
334    }
335
336    /// Get all role relationships in the hierarchy.
337    ///
338    /// This method returns all parent-child relationships, useful for
339    /// database storage, API responses, and external system integration.
340    ///
341    /// # Arguments
342    /// * `relationship_type` - Optional filter for relationship type
343    ///
344    /// # Returns
345    /// A vector of `RoleRelationship` objects representing all relationships.
346    ///
347    /// # Example
348    /// ```rust
349    /// # use role_system::{AsyncRoleSystem, RoleSystem, RoleSystemConfig, MemoryStorage};
350    /// # use role_system::hierarchy::RelationshipType;
351    /// # tokio_test::block_on(async {
352    /// let storage = MemoryStorage::new();
353    /// let role_sys = RoleSystem::with_storage(storage, RoleSystemConfig::default());
354    /// let role_system = AsyncRoleSystem::new(role_sys);
355    ///
356    /// // Get all relationships
357    /// let all_relationships = role_system.get_role_relationships(None).await?;
358    ///
359    /// // Get only direct relationships
360    /// let direct_relationships = role_system
361    ///     .get_role_relationships(Some(RelationshipType::Direct))
362    ///     .await?;
363    /// # Ok::<(), role_system::Error>(())
364    /// # });
365    /// ```
366    pub async fn get_role_relationships(
367        &self,
368        _relationship_type: Option<crate::hierarchy::RelationshipType>,
369    ) -> Result<Vec<crate::hierarchy::RoleRelationship>> {
370        let system = self.inner.read().await;
371
372        // For now, return empty vector since individual roles don't track hierarchy
373        // In a real implementation, this would extract all relationships from RoleHierarchy
374        // Just verify the system is accessible
375        drop(system);
376
377        // This would be implemented using the RoleHierarchy system
378        Ok(Vec::new())
379    }
380
381    /// Check if one role is an ancestor of another.
382    ///
383    /// This method checks if `ancestor_id` is in the inheritance chain of `descendant_id`.
384    ///
385    /// # Arguments
386    /// * `ancestor_id` - The potential ancestor role ID
387    /// * `descendant_id` - The potential descendant role ID
388    ///
389    /// # Returns
390    /// `true` if `ancestor_id` is an ancestor of `descendant_id`.
391    ///
392    /// # Example
393    /// ```rust
394    /// # use role_system::{AsyncRoleSystem, RoleSystem, RoleSystemConfig, MemoryStorage};
395    /// # tokio_test::block_on(async {
396    /// let storage = MemoryStorage::new();
397    /// let role_sys = RoleSystem::with_storage(storage, RoleSystemConfig::default());
398    /// let role_system = AsyncRoleSystem::new(role_sys);
399    /// let is_ancestor = role_system
400    ///     .is_role_ancestor("admin", "junior_dev")
401    ///     .await?;
402    ///
403    /// if is_ancestor {
404    ///     println!("admin is an ancestor of junior_dev");
405    /// }
406    /// # Ok::<(), role_system::Error>(())
407    /// # });
408    /// ```
409    pub async fn is_role_ancestor(&self, ancestor_id: &str, descendant_id: &str) -> Result<bool> {
410        let system = self.inner.read().await;
411
412        // For now, return false since individual roles don't track hierarchy
413        // In a real implementation, this would traverse the RoleHierarchy
414        let _ancestor = system.get_role(ancestor_id)?;
415        let _descendant = system.get_role(descendant_id)?;
416
417        // This would be implemented using the RoleHierarchy system
418        Ok(false)
419    }
420
421    /// Get the hierarchy depth of a role.
422    ///
423    /// The depth is the number of levels from the root of the hierarchy.
424    /// Root roles have depth 0.
425    ///
426    /// # Arguments
427    /// * `role_id` - The ID of the role to get depth for
428    ///
429    /// # Returns
430    /// The depth of the role in the hierarchy.
431    ///
432    /// # Example
433    /// ```rust
434    /// # use role_system::{AsyncRoleSystem, RoleSystem, RoleSystemConfig, MemoryStorage};
435    /// # tokio_test::block_on(async {
436    /// let storage = MemoryStorage::new();
437    /// let role_sys = RoleSystem::with_storage(storage, RoleSystemConfig::default());
438    /// let role_system = AsyncRoleSystem::new(role_sys);
439    /// let depth = role_system.get_role_depth("senior_dev").await?;
440    /// println!("Role depth: {}", depth);
441    /// # Ok::<(), role_system::Error>(())
442    /// # });
443    /// ```
444    pub async fn get_role_depth(&self, role_id: &str) -> Result<usize> {
445        let system = self.inner.read().await;
446
447        // For now, return 0 since individual roles don't track hierarchy
448        // In a real implementation, this would calculate depth from RoleHierarchy
449        let _role = system.get_role(role_id)?;
450
451        // This would be implemented using the RoleHierarchy system
452        Ok(0)
453    }
454}
455
456impl<S> Clone for AsyncRoleSystem<S>
457where
458    S: Storage + Send + Sync,
459{
460    fn clone(&self) -> Self {
461        Self {
462            inner: Arc::clone(&self.inner),
463        }
464    }
465}
466
467/// Async trait for storage backends that support async operations.
468#[async_trait::async_trait]
469pub trait AsyncStorage: Send + Sync {
470    /// Store a role asynchronously.
471    async fn store_role(&mut self, role: Role) -> Result<()>;
472
473    /// Get a role by name asynchronously.
474    async fn get_role(&self, name: &str) -> Result<Option<Role>>;
475
476    /// Check if a role exists asynchronously.
477    async fn role_exists(&self, name: &str) -> Result<bool>;
478
479    /// Delete a role asynchronously.
480    async fn delete_role(&mut self, name: &str) -> Result<bool>;
481
482    /// List all role names asynchronously.
483    async fn list_roles(&self) -> Result<Vec<String>>;
484
485    /// Update an existing role asynchronously.
486    async fn update_role(&mut self, role: Role) -> Result<()>;
487}
488
489/// Async memory storage implementation.
490#[derive(Debug, Default)]
491pub struct AsyncMemoryStorage {
492    roles: Arc<RwLock<HashMap<String, Role>>>,
493}
494
495impl AsyncMemoryStorage {
496    /// Create a new async memory storage instance.
497    pub fn new() -> Self {
498        Self {
499            roles: Arc::new(RwLock::new(HashMap::new())),
500        }
501    }
502
503    /// Get the number of stored roles.
504    pub async fn role_count(&self) -> usize {
505        self.roles.read().await.len()
506    }
507
508    /// Clear all stored data.
509    pub async fn clear(&self) {
510        self.roles.write().await.clear();
511    }
512}
513
514#[async_trait::async_trait]
515impl AsyncStorage for AsyncMemoryStorage {
516    async fn store_role(&mut self, role: Role) -> Result<()> {
517        let name = role.name().to_string();
518        self.roles.write().await.insert(name, role);
519        Ok(())
520    }
521
522    async fn get_role(&self, name: &str) -> Result<Option<Role>> {
523        Ok(self.roles.read().await.get(name).cloned())
524    }
525
526    async fn role_exists(&self, name: &str) -> Result<bool> {
527        Ok(self.roles.read().await.contains_key(name))
528    }
529
530    async fn delete_role(&mut self, name: &str) -> Result<bool> {
531        Ok(self.roles.write().await.remove(name).is_some())
532    }
533
534    async fn list_roles(&self) -> Result<Vec<String>> {
535        Ok(self.roles.read().await.keys().cloned().collect())
536    }
537
538    async fn update_role(&mut self, role: Role) -> Result<()> {
539        let name = role.name().to_string();
540        self.roles.write().await.insert(name, role);
541        Ok(())
542    }
543}
544
545/// Helper trait for converting sync storage to async.
546pub struct AsyncStorageAdapter<S>
547where
548    S: Storage + Send + Sync,
549{
550    storage: Arc<Mutex<S>>,
551}
552
553impl<S> AsyncStorageAdapter<S>
554where
555    S: Storage + Send + Sync,
556{
557    /// Create a new async storage adapter.
558    pub fn new(storage: S) -> Self {
559        Self {
560            storage: Arc::new(Mutex::new(storage)),
561        }
562    }
563}
564
565#[async_trait::async_trait]
566impl<S> AsyncStorage for AsyncStorageAdapter<S>
567where
568    S: Storage + Send + Sync,
569{
570    async fn store_role(&mut self, role: Role) -> Result<()> {
571        let mut storage = self.storage.lock().await;
572        storage.store_role(role)
573    }
574
575    async fn get_role(&self, name: &str) -> Result<Option<Role>> {
576        let storage = self.storage.lock().await;
577        storage.get_role(name)
578    }
579
580    async fn role_exists(&self, name: &str) -> Result<bool> {
581        let storage = self.storage.lock().await;
582        storage.role_exists(name)
583    }
584
585    async fn delete_role(&mut self, name: &str) -> Result<bool> {
586        let mut storage = self.storage.lock().await;
587        storage.delete_role(name)
588    }
589
590    async fn list_roles(&self) -> Result<Vec<String>> {
591        let storage = self.storage.lock().await;
592        storage.list_roles()
593    }
594
595    async fn update_role(&mut self, role: Role) -> Result<()> {
596        let mut storage = self.storage.lock().await;
597        storage.update_role(role)
598    }
599}
600
601/// Async role system builder for easy configuration.
602pub struct AsyncRoleSystemBuilder<S>
603where
604    S: Storage + Send + Sync,
605{
606    config: RoleSystemConfig,
607    storage: Option<S>,
608}
609
610impl<S> AsyncRoleSystemBuilder<S>
611where
612    S: Storage + Send + Sync + Default,
613{
614    /// Create a new builder with default storage.
615    pub fn new() -> Self {
616        Self {
617            config: RoleSystemConfig::default(),
618            storage: None,
619        }
620    }
621}
622
623impl<S> Default for AsyncRoleSystemBuilder<S>
624where
625    S: Storage + Send + Sync + Default,
626{
627    fn default() -> Self {
628        Self::new()
629    }
630}
631
632impl<S> AsyncRoleSystemBuilder<S>
633where
634    S: Storage + Send + Sync,
635{
636    /// Create a new builder with custom storage.
637    pub fn with_storage(storage: S) -> Self {
638        Self {
639            config: RoleSystemConfig::default(),
640            storage: Some(storage),
641        }
642    }
643
644    /// Set the configuration.
645    pub fn config(mut self, config: RoleSystemConfig) -> Self {
646        self.config = config;
647        self
648    }
649
650    /// Set the maximum hierarchy depth.
651    pub fn max_hierarchy_depth(mut self, depth: usize) -> Self {
652        self.config.max_hierarchy_depth = depth;
653        self
654    }
655
656    /// Enable or disable permission caching.
657    pub fn enable_caching(mut self, enabled: bool) -> Self {
658        self.config.enable_caching = enabled;
659        self
660    }
661
662    /// Set the cache TTL in seconds.
663    pub fn cache_ttl_seconds(mut self, ttl: u64) -> Self {
664        self.config.cache_ttl_seconds = ttl;
665        self
666    }
667
668    /// Enable or disable audit logging.
669    pub fn enable_audit(mut self, enabled: bool) -> Self {
670        self.config.enable_audit = enabled;
671        self
672    }
673
674    /// Build the async role system.
675    pub fn build(self) -> AsyncRoleSystem<S>
676    where
677        S: Default,
678    {
679        let storage = self.storage.unwrap_or_default();
680        let role_system = RoleSystem::with_storage(storage, self.config);
681        AsyncRoleSystem::new(role_system)
682    }
683
684    /// Build the async role system with provided storage.
685    pub fn build_with_storage(self, storage: S) -> AsyncRoleSystem<S> {
686        let role_system = RoleSystem::with_storage(storage, self.config);
687        AsyncRoleSystem::new(role_system)
688    }
689}
690
691#[cfg(test)]
692mod tests {
693    use super::*;
694    use crate::{permission::Permission, storage::MemoryStorage};
695
696    #[tokio::test]
697    async fn test_async_role_system() {
698        let storage = MemoryStorage::new();
699        let config = RoleSystemConfig::default();
700        let role_system = RoleSystem::with_storage(storage, config);
701        let async_system = AsyncRoleSystem::new(role_system);
702
703        // Create and register a role
704        let role = Role::new("async-test").add_permission(Permission::new("read", "documents"));
705
706        async_system.register_role(role).await.unwrap();
707
708        // Create a subject and assign the role
709        let subject = Subject::user("user1");
710        async_system
711            .assign_role(&subject, "async-test")
712            .await
713            .unwrap();
714
715        // Check permission
716        let resource = Resource::new("doc1", "documents");
717        let can_read = async_system
718            .check_permission(&subject, "read", &resource)
719            .await
720            .unwrap();
721
722        assert!(can_read);
723    }
724
725    #[tokio::test]
726    async fn test_async_batch_permissions() {
727        let storage = MemoryStorage::new();
728        let config = RoleSystemConfig::default();
729        let role_system = RoleSystem::with_storage(storage, config);
730        let async_system = AsyncRoleSystem::new(role_system);
731
732        // Setup role and subject
733        let role = Role::new("batch-test")
734            .add_permission(Permission::new("read", "documents"))
735            .add_permission(Permission::new("write", "documents"));
736
737        async_system.register_role(role).await.unwrap();
738
739        let subject = Subject::user("user1");
740        async_system
741            .assign_role(&subject, "batch-test")
742            .await
743            .unwrap();
744
745        // Batch check permissions
746        let checks = vec![
747            ("read".to_string(), Resource::new("doc1", "documents")),
748            ("write".to_string(), Resource::new("doc1", "documents")),
749            ("delete".to_string(), Resource::new("doc1", "documents")),
750        ];
751
752        let results = async_system
753            .batch_check_permissions(&subject, &checks)
754            .await
755            .unwrap();
756
757        assert_eq!(results.len(), 3);
758        assert!(results[0].2); // read granted
759        assert!(results[1].2); // write granted
760        assert!(!results[2].2); // delete denied
761    }
762
763    #[tokio::test]
764    async fn test_async_memory_storage() {
765        let mut storage = AsyncMemoryStorage::new();
766
767        let role =
768            Role::new("async-storage-test").add_permission(Permission::new("read", "documents"));
769
770        // Store role
771        storage.store_role(role.clone()).await.unwrap();
772        assert_eq!(storage.role_count().await, 1);
773
774        // Check existence
775        assert!(storage.role_exists("async-storage-test").await.unwrap());
776
777        // Get role
778        let retrieved = storage
779            .get_role("async-storage-test")
780            .await
781            .unwrap()
782            .unwrap();
783        assert_eq!(retrieved.name(), "async-storage-test");
784
785        // List roles
786        let roles = storage.list_roles().await.unwrap();
787        assert_eq!(roles.len(), 1);
788
789        // Delete role
790        assert!(storage.delete_role("async-storage-test").await.unwrap());
791        assert_eq!(storage.role_count().await, 0);
792    }
793
794    #[tokio::test]
795    async fn test_async_builder() {
796        let async_system = AsyncRoleSystemBuilder::<MemoryStorage>::new()
797            .max_hierarchy_depth(5)
798            .enable_caching(false)
799            .build();
800
801        // Should be able to use the system
802        let role = Role::new("builder-test");
803        async_system.register_role(role).await.unwrap();
804
805        let retrieved = async_system.get_role("builder-test").await.unwrap();
806        assert!(retrieved.is_some());
807    }
808}