1use super::path::GlobalStatePathHelper;
2use crate::base::*;
3use cyfs_base::*;
4
5use serde::{Deserialize, Serialize};
6use std::cmp::Ordering;
7use std::borrow::Cow;
8
9#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
10pub struct GlobalStatePathSpecifiedGroup {
11 pub zone: Option<ObjectId>,
13
14 pub zone_category: Option<DeviceZoneCategory>,
16
17 pub dec: Option<ObjectId>,
19
20 pub access: u8, }
22
23impl GlobalStatePathSpecifiedGroup {
24 pub fn is_empty(&self) -> bool {
25 self.zone.is_none() && self.zone_category.is_none() && self.dec.is_none()
26 }
27
28 fn compare_opt_item(left: &Option<ObjectId>, right: &Option<ObjectId>) -> Option<Ordering> {
29 match left {
30 Some(left) => match right {
31 Some(right) => left.partial_cmp(right),
32 None => Some(Ordering::Less),
33 },
34 None => match right {
35 Some(_) => Some(Ordering::Greater),
36 None => Some(Ordering::Equal),
37 },
38 }
39 }
40
41 pub fn compare(&self, source: &RequestSourceInfo) -> bool {
42 let mut is_empty = true;
43 if let Some(zone_category) = &self.zone_category {
44 if !source.compare_zone_category(*zone_category) {
45 return false;
46 }
47 is_empty = false;
48 }
49
50 if let Some(zone) = &self.zone {
52 if !source.compare_zone(&zone) {
53 return false;
54 }
55 is_empty = false;
56 }
57
58 if let Some(dec) = &self.dec {
59 if !source.compare_dec(dec) {
60 return false;
61 }
62 is_empty = false;
63 }
64
65 if is_empty {
67 warn!("access specified group is empty!");
68 return false;
69 }
70
71 true
72 }
73}
74
75impl PartialOrd for GlobalStatePathSpecifiedGroup {
76 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
77 let ret = self.zone_category.partial_cmp(&other.zone_category);
78 if ret.is_some() && ret != Some(Ordering::Equal) {
79 return ret;
80 }
81
82 let ret = Self::compare_opt_item(&self.zone, &other.zone);
83 if ret.is_some() && ret != Some(Ordering::Equal) {
84 return ret;
85 }
86
87 Self::compare_opt_item(&self.dec, &other.dec)
88 }
89}
90
91#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
92pub enum GlobalStatePathGroupAccess {
93 Specified(GlobalStatePathSpecifiedGroup),
94 Default(u32 ),
95}
96
97impl PartialOrd for GlobalStatePathGroupAccess {
98 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
99 match &self {
100 Self::Specified(left) => match other {
101 Self::Specified(right) => left.partial_cmp(&right),
102 Self::Default(_) => Some(Ordering::Less),
103 },
104 Self::Default(_left) => match other {
105 Self::Specified(_) => Some(Ordering::Greater),
106 Self::Default(_right) => Some(Ordering::Equal),
107 },
108 }
109 }
110}
111
112impl Ord for GlobalStatePathGroupAccess {
113 fn cmp(&self, other: &Self) -> Ordering {
114 self.partial_cmp(other).unwrap()
115 }
116}
117
118impl std::fmt::Display for GlobalStatePathGroupAccess {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 match &self {
121 Self::Default(p) => {
122 write!(f, "{}", AccessString::new(*p))
123 }
124 Self::Specified(s) => {
125 write!(
126 f,
127 "zone={:?}, zone_category={:?} dec={:?}, {}",
128 s.zone,
129 s.zone_category,
130 s.dec.as_ref().map(|id| cyfs_core::dec_id_to_string(id)),
131 AccessPermissions::format_u8(s.access),
132 )
133 }
134 }
135 }
136}
137
138impl GlobalStatePathGroupAccess {
139 pub fn check_valid(&self) -> bool {
140 match &self {
141 Self::Default(_) => {}
142 Self::Specified(v) => {
143 if v.is_empty() {
144 return false;
145 }
146 }
147 }
148
149 true
150 }
151}
152
153#[derive(Clone, Serialize, Deserialize, Eq, PartialEq)]
154pub struct GlobalStatePathAccessItem {
155 pub path: String,
157
158 pub access: GlobalStatePathGroupAccess,
160}
161
162impl GlobalStatePathAccessItem {
163 pub fn check_valid(&self) -> bool {
164 self.access.check_valid()
165 }
166
167 pub fn new(path: &str, access: u32) -> Self {
168 let path = GlobalStatePathHelper::fix_path(path).to_string();
169
170 Self {
171 path,
172 access: GlobalStatePathGroupAccess::Default(access),
173 }
174 }
175
176 pub fn new_group(
177 path: &str,
178 zone: Option<ObjectId>,
179 zone_category: Option<DeviceZoneCategory>,
180 dec: Option<ObjectId>,
181 access: u8,
182 ) -> Self {
183 assert!(zone.is_some() || dec.is_some());
184
185 let path = GlobalStatePathHelper::fix_path(path).to_string();
186
187 Self {
188 path,
189 access: GlobalStatePathGroupAccess::Specified(GlobalStatePathSpecifiedGroup {
190 zone,
191 zone_category,
192 dec,
193 access,
194 }),
195 }
196 }
197
198 pub fn try_fix_path(&mut self) {
199 self.path = GlobalStatePathHelper::fix_path(&self.path).to_string();
200 }
201}
202
203impl std::fmt::Display for GlobalStatePathAccessItem {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 write!(f, "({}, {})", self.path, self.access)
206 }
207}
208
209impl std::fmt::Debug for GlobalStatePathAccessItem {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 std::fmt::Display::fmt(&self, f)
212 }
213}
214
215impl PartialOrd for GlobalStatePathAccessItem {
216 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
217 match GlobalStatePathHelper::compare_path(&self.path, &other.path) {
218 Some(Ordering::Equal) | None => self.access.partial_cmp(&other.access),
219 ret @ _ => ret,
220 }
221 }
222}
223
224impl Ord for GlobalStatePathAccessItem {
225 fn cmp(&self, other: &Self) -> Ordering {
226 self.partial_cmp(other).unwrap()
227 }
228}
229
230pub struct GlobalStateAccessRequest<'d, 'a, 'b> {
231 pub dec: Cow<'d, ObjectId>,
232 pub path: Cow<'a, str>,
233 pub source: Cow<'b, RequestSourceInfo>,
234 pub permissions: AccessPermissions,
235}
236
237impl<'d, 'a, 'b> std::fmt::Display for GlobalStateAccessRequest<'d, 'a, 'b> {
238 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239 write!(
240 f,
241 "path={}, {}, permissions={}",
242 self.path,
243 self.source,
244 self.permissions.as_str()
245 )
246 }
247}
248
249
250#[cfg(test)]
251mod test {
252 use super::*;
253 use cyfs_core::*;
254
255 use serde::{Deserialize, Serialize};
256
257 #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
258 struct Temp {
259 zone: Option<GlobalStatePathSpecifiedGroup>,
260 }
261
262 #[test]
263 fn test() {
264 let t = GlobalStatePathSpecifiedGroup {
265 zone: None,
266 zone_category: Some(DeviceZoneCategory::CurrentZone),
267 dec: Some(get_system_dec_app().clone()),
268 access: 5,
269 };
270
271 let s = serde_json::to_string(&t).unwrap();
272 print!("{}", s);
273 }
274}