1use std::fmt;
7
8#[derive(Debug)]
10pub enum PolicyError<R, P> {
11 Policy(P),
13 Repository(R)
15}
16
17impl<R, P> PolicyError<R, P> {
18 pub const fn is_policy(&self) -> bool {
20 matches!(self, Self::Policy(_))
21 }
22
23 pub const fn is_repository(&self) -> bool {
25 matches!(self, Self::Repository(_))
26 }
27}
28
29impl<R: fmt::Display, P: fmt::Display> fmt::Display for PolicyError<R, P> {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self {
32 Self::Policy(e) => write!(f, "authorization denied: {}", e),
33 Self::Repository(e) => write!(f, "repository error: {}", e)
34 }
35 }
36}
37
38impl<R: std::error::Error + 'static, P: std::error::Error + 'static> std::error::Error
39 for PolicyError<R, P>
40{
41 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
42 match self {
43 Self::Policy(e) => Some(e),
44 Self::Repository(e) => Some(e)
45 }
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub enum PolicyOperation {
52 Create,
54 Read,
56 Update,
58 Delete,
60 List,
62 Command
64}
65
66impl PolicyOperation {
67 pub const fn is_read_only(&self) -> bool {
69 matches!(self, Self::Read | Self::List)
70 }
71
72 pub const fn is_mutation(&self) -> bool {
74 !self.is_read_only()
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use std::error::Error;
81
82 use super::*;
83
84 #[derive(Debug)]
85 struct TestError(&'static str);
86
87 impl fmt::Display for TestError {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 write!(f, "{}", self.0)
90 }
91 }
92
93 impl std::error::Error for TestError {}
94
95 #[test]
96 fn policy_error_is_policy() {
97 let err: PolicyError<TestError, TestError> = PolicyError::Policy(TestError("denied"));
98 assert!(err.is_policy());
99 assert!(!err.is_repository());
100 }
101
102 #[test]
103 fn policy_error_is_repository() {
104 let err: PolicyError<TestError, TestError> = PolicyError::Repository(TestError("db"));
105 assert!(err.is_repository());
106 assert!(!err.is_policy());
107 }
108
109 #[test]
110 fn policy_error_display() {
111 let policy: PolicyError<TestError, TestError> = PolicyError::Policy(TestError("denied"));
112 assert_eq!(format!("{}", policy), "authorization denied: denied");
113
114 let repo: PolicyError<TestError, TestError> = PolicyError::Repository(TestError("db"));
115 assert_eq!(format!("{}", repo), "repository error: db");
116 }
117
118 #[test]
119 fn policy_error_source() {
120 let policy: PolicyError<TestError, TestError> = PolicyError::Policy(TestError("denied"));
121 assert!(policy.source().is_some());
122
123 let repo: PolicyError<TestError, TestError> = PolicyError::Repository(TestError("db"));
124 assert!(repo.source().is_some());
125 }
126
127 #[test]
128 fn policy_operation_is_read_only() {
129 assert!(PolicyOperation::Read.is_read_only());
130 assert!(PolicyOperation::List.is_read_only());
131 assert!(!PolicyOperation::Create.is_read_only());
132 assert!(!PolicyOperation::Update.is_read_only());
133 assert!(!PolicyOperation::Delete.is_read_only());
134 assert!(!PolicyOperation::Command.is_read_only());
135 }
136
137 #[test]
138 fn policy_operation_is_mutation() {
139 assert!(!PolicyOperation::Read.is_mutation());
140 assert!(!PolicyOperation::List.is_mutation());
141 assert!(PolicyOperation::Create.is_mutation());
142 assert!(PolicyOperation::Update.is_mutation());
143 assert!(PolicyOperation::Delete.is_mutation());
144 assert!(PolicyOperation::Command.is_mutation());
145 }
146}