cyfs_lib/rmeta/def/
access.rs

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    // device/device's owner(as zone id), None for any zone
12    pub zone: Option<ObjectId>,
13
14    // Choose one between zone and zone_category
15    pub zone_category: Option<DeviceZoneCategory>,
16
17    // specified dec, None for any dec
18    pub dec: Option<ObjectId>,
19
20    pub access: u8, /*AccessPermissions*/
21}
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        // FIXME if zone_category exists already, then should try to compare zone field is still exists?
51        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        // should not been empty!
66        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 /*AccessString*/),
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    // GlobalState path, must end with /
156    pub path: String,
157
158    // Access value
159    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}