1use crate::{Error, Permission, Resource, Role, RoleSystem, Subject};
4
5#[derive(Debug, Clone)]
7pub struct BatchResult<T> {
8 pub successes: Vec<(usize, T)>,
10 pub failures: Vec<(usize, Error)>,
12}
13
14impl<T> BatchResult<T> {
15 pub fn new() -> Self {
17 Self {
18 successes: Vec::new(),
19 failures: Vec::new(),
20 }
21 }
22
23 pub fn add_success(&mut self, index: usize, result: T) {
25 self.successes.push((index, result));
26 }
27
28 pub fn add_failure(&mut self, index: usize, error: Error) {
30 self.failures.push((index, error));
31 }
32
33 pub fn success_rate(&self) -> f64 {
35 let total = self.successes.len() + self.failures.len();
36 if total == 0 {
37 return 0.0;
38 }
39 (self.successes.len() as f64 / total as f64) * 100.0
40 }
41
42 pub fn all_succeeded(&self) -> bool {
44 self.failures.is_empty()
45 }
46
47 pub fn total_operations(&self) -> usize {
49 self.successes.len() + self.failures.len()
50 }
51}
52
53impl<T> Default for BatchResult<T> {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59#[derive(Debug, Clone)]
61pub struct BatchPermissionCheck {
62 pub subject: Subject,
63 pub permission: Permission,
64 pub resource: Resource,
65}
66
67impl BatchPermissionCheck {
68 pub fn new(subject: Subject, permission: Permission, resource: Resource) -> Self {
70 Self {
71 subject,
72 permission,
73 resource,
74 }
75 }
76}
77
78#[derive(Debug, Clone)]
80pub struct BatchRoleAssignment {
81 pub subject: Subject,
82 pub role: Role,
83 pub assign: bool, }
85
86impl BatchRoleAssignment {
87 pub fn new_assignment(subject: Subject, role: Role) -> Self {
89 Self {
90 subject,
91 role,
92 assign: true,
93 }
94 }
95
96 pub fn new_revocation(subject: Subject, role: Role) -> Self {
98 Self {
99 subject,
100 role,
101 assign: false,
102 }
103 }
104}
105
106#[derive(Debug, Clone)]
108pub struct BatchConfig {
109 pub max_concurrency: usize,
111 pub fail_fast: bool,
113 pub timeout_ms: Option<u64>,
115}
116
117impl Default for BatchConfig {
118 fn default() -> Self {
119 Self {
120 max_concurrency: num_cpus::get().max(1),
121 fail_fast: false,
122 timeout_ms: None,
123 }
124 }
125}
126
127pub trait BatchOperations {
129 fn batch_check_permissions(
131 &self,
132 checks: Vec<BatchPermissionCheck>,
133 ) -> Result<BatchResult<bool>, Error>;
134
135 fn batch_role_operations(
137 &mut self,
138 operations: Vec<BatchRoleAssignment>,
139 ) -> Result<BatchResult<()>, Error>;
140}
141
142impl BatchOperations for RoleSystem {
143 fn batch_check_permissions(
144 &self,
145 checks: Vec<BatchPermissionCheck>,
146 ) -> Result<BatchResult<bool>, Error> {
147 let mut result = BatchResult::new();
148
149 for (i, check) in checks.iter().enumerate() {
150 match self.check_permission(&check.subject, check.permission.action(), &check.resource)
151 {
152 Ok(allowed) => result.add_success(i, allowed),
153 Err(error) => result.add_failure(i, error),
154 }
155 }
156
157 Ok(result)
158 }
159
160 fn batch_role_operations(
161 &mut self,
162 operations: Vec<BatchRoleAssignment>,
163 ) -> Result<BatchResult<()>, Error> {
164 let mut result = BatchResult::new();
165
166 for (i, operation) in operations.iter().enumerate() {
167 let op_result = if operation.assign {
168 self.assign_role(&operation.subject, operation.role.name())
169 } else {
170 self.remove_role(&operation.subject, operation.role.name())
171 };
172
173 match op_result {
174 Ok(()) => result.add_success(i, ()),
175 Err(error) => result.add_failure(i, error),
176 }
177 }
178
179 Ok(result)
180 }
181}