bucky_objects/
access_string.rs

1use crate::*;
2use intbits::Bits;
3use std::convert::TryInto;
4use std::fmt::{Formatter};
5use std::str::FromStr;
6use itertools::Itertools;
7use serde::{Serialize, Deserialize, Serializer, Deserializer};
8use serde::de::{Error, SeqAccess, Visitor};
9
10const ACCESS_GROUP_MASK: u32 = 0b111 << 29;
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub enum RequestOpType {
14    Read,
15    Write,
16    Call,
17}
18
19impl Into<AccessPermissions> for RequestOpType {
20    fn into(self) -> AccessPermissions {
21        match self {
22            Self::Read => AccessPermissions::ReadOnly,
23            Self::Write => AccessPermissions::WriteOnly,
24            Self::Call => AccessPermissions::CallOnly,
25        }
26    }
27}
28
29impl Into<AccessPermission> for RequestOpType {
30    fn into(self) -> AccessPermission {
31        match self {
32            Self::Read => AccessPermission::Read,
33            Self::Write => AccessPermission::Write,
34            Self::Call => AccessPermission::Call,
35        }
36    }
37}
38
39#[repr(u8)]
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub enum AccessPermission {
42    Call = 0b001,
43    Write = 0b010,
44    Read = 0b100,
45}
46
47impl AccessPermission {
48    pub fn bit(&self) -> u8 {
49        match *self {
50            Self::Call => 0,
51            Self::Write => 1,
52            Self::Read => 2,
53        }
54    }
55
56    pub fn test(&self, access: u8) -> bool {
57        let b = *self as u8;
58        access & b == b
59    }
60}
61
62#[repr(u8)]
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64pub enum AccessPermissions {
65    None = 0,
66    CallOnly = 0b001,
67    WriteOnly = 0b010,
68    WriteAndCall = 0b011,
69    ReadOnly = 0b100,
70    ReadAndCall = 0b101,
71    ReadAndWrite = 0b110,
72    Full = 0b111,
73}
74
75impl AccessPermissions {
76    pub fn as_str(&self) -> &'static str {
77        match &self {
78            Self::None => "---",
79            Self::CallOnly => "--x",
80            Self::WriteOnly => "-w-",
81            Self::WriteAndCall => "-wx",
82            Self::ReadOnly => "r--",
83            Self::ReadAndCall => "r-x",
84            Self::ReadAndWrite => "rw-",
85            Self::Full => "rwx",
86        }
87    }
88
89    pub fn format_u8(v: u8) -> std::borrow::Cow<'static, str> {
90        match TryInto::<AccessPermissions>::try_into(v) {
91            Ok(v) => std::borrow::Cow::Borrowed(v.as_str()),
92            Err(_) => {
93                let s = format!("{:o}", v);
94                std::borrow::Cow::Owned(s)
95            }
96        }
97    }
98
99    pub fn test_op(&self, op_type: RequestOpType) -> bool {
100        let access = Into::<AccessPermission>::into(op_type);
101        access.test(*self as u8)
102    }
103}
104
105impl TryFrom<u8> for AccessPermissions {
106    type Error = BuckyError;
107    fn try_from(v: u8) -> BuckyResult<Self> {
108        if v > AccessPermissions::Full as u8 {
109            let msg = format!("invalid AccessPermissions value: {}", v);
110            error!("{}", msg);
111            return Err(BuckyError::new(BuckyErrorCode::InvalidParam, msg));
112        }
113
114        let ret: Self = unsafe { ::std::mem::transmute(v) };
115        Ok(ret)
116    }
117}
118
119impl FromStr for AccessPermissions {
120    type Err = BuckyError;
121    fn from_str(value: &str) -> BuckyResult<Self> {
122        match value {
123            "---" => Ok(AccessPermissions::None),
124            "--x" => Ok(AccessPermissions::CallOnly),
125            "-w-" => Ok(AccessPermissions::WriteOnly),
126            "-wx" => Ok(AccessPermissions::WriteAndCall),
127            "r--" => Ok(AccessPermissions::ReadOnly),
128            "r-x" => Ok(AccessPermissions::ReadAndCall),
129            "rw-" => Ok(AccessPermissions::ReadAndWrite),
130            "rwx" => Ok(AccessPermissions::Full),
131            v @ _ => {
132                Err(BuckyError::new(BuckyErrorCode::InvalidFormat, format!("invalid access permissions {}", v)))
133            }
134        }
135    }
136}
137
138impl std::fmt::Display for AccessPermissions {
139    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140        write!(f, "{}", self.as_str())
141    }
142}
143
144impl Serialize for AccessPermissions {
145    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
146        serializer.serialize_str(self.as_str())
147    }
148}
149
150struct AccessPermissionsVisitor;
151
152impl<'de> Visitor<'de> for AccessPermissionsVisitor {
153    type Value = AccessPermissions;
154
155    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
156        formatter.write_str("a string represent access permissions")
157    }
158
159    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: Error {
160        AccessPermissions::from_str(v).map_err(Error::custom)
161    }
162}
163
164impl<'de> Deserialize<'de> for AccessPermissions {
165    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
166        deserializer.deserialize_string(AccessPermissionsVisitor)
167    }
168}
169
170#[repr(u32)]
171#[derive(Clone, Copy, Debug, Eq, PartialEq)]
172pub enum AccessGroup {
173    CurrentDevice = 0,
174    CurrentZone = 3,
175    FriendZone = 6,
176    OthersZone = 9,
177
178    OwnerDec = 12,
179    OthersDec = 15,
180}
181
182pub const ACCESS_GROUP_LIST: &[AccessGroup; 6] = &[
183    AccessGroup::CurrentDevice,
184    AccessGroup::CurrentZone,
185    AccessGroup::FriendZone,
186    AccessGroup::OthersZone,
187    AccessGroup::OwnerDec,
188    AccessGroup::OthersDec,
189];
190
191impl AccessGroup {
192    pub fn range(&self) -> std::ops::Range<u32> {
193        let index = *self as u32;
194        // println!("index={}, {:?}", index, self);
195        index..index + 3
196    }
197
198    pub fn bit(&self, permission: AccessPermission) -> u32 {
199        let index = *self as u32;
200        index + permission.bit() as u32
201    }
202}
203
204impl TryFrom<&str> for AccessGroup {
205    type Error = BuckyError;
206
207    fn try_from(value: &str) -> BuckyResult<Self> {
208        match value {
209            "CurrentDevice" => Ok(AccessGroup::CurrentDevice),
210            "CurrentZone" => Ok(AccessGroup::CurrentZone),
211            "FriendZone" => Ok(AccessGroup::FriendZone),
212            "OthersZone" => Ok(AccessGroup::OthersZone),
213            "OwnerDec" => Ok(AccessGroup::OwnerDec),
214            "OthersDec" => Ok(AccessGroup::OthersDec),
215            v @ _ => Err(BuckyError::new(BuckyErrorCode::InvalidParam, format!("invalid access group {}", v)))
216        }
217    }
218}
219
220pub struct AccessPair {
221    group: AccessGroup,
222    permissions: AccessPermissions,
223}
224
225#[derive(Clone, Eq, PartialEq)]
226pub struct AccessString(u32);
227
228impl std::fmt::Debug for AccessString {
229    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
230        write!(f, "{}", self.to_string())
231    }
232}
233
234impl AccessString {
235    pub const fn new(bits: u32) -> Self {
236        Self(bits)
237    }
238
239    pub const fn value(&self) -> u32 {
240        self.0
241    }
242
243    pub fn make(list: &[AccessPair]) -> Self {
244        let mut ret = Self(0);
245        list.iter()
246            .for_each(|p| ret.set_group_permissions(p.group, p.permissions));
247        ret
248    }
249
250    pub fn is_accessable(&self, group: AccessGroup, permission: AccessPermission) -> bool {
251        self.0.bit(group.bit(permission))
252    }
253
254    pub fn set_group_permission(&mut self, group: AccessGroup, permission: AccessPermission) {
255        self.0.set_bit(group.bit(permission), true);
256    }
257
258    pub fn clear_group_permission(&mut self, group: AccessGroup, permission: AccessPermission) {
259        self.0.set_bit(group.bit(permission), false);
260    }
261
262    pub fn get_group_permissions(&self, group: AccessGroup) -> AccessPermissions {
263        (self.0.bits(group.range()) as u8).try_into().unwrap()
264    }
265
266    pub fn set_group_permissions(&mut self, group: AccessGroup, permissions: AccessPermissions) {
267        self.0.set_bits(group.range(), permissions as u32);
268    }
269
270    pub fn clear_group_permissions(&mut self, group: AccessGroup) {
271        self.0.set_bits(group.range(), 0);
272    }
273
274    pub fn full_except_write() -> Self {
275        static D: once_cell::sync::OnceCell<AccessString> = once_cell::sync::OnceCell::new();
276        D.get_or_init(|| {
277            Self::make(&[
278                AccessPair {
279                    group: AccessGroup::CurrentDevice,
280                    permissions: AccessPermissions::Full,
281                },
282                AccessPair {
283                    group: AccessGroup::CurrentZone,
284                    permissions: AccessPermissions::Full,
285                },
286                AccessPair {
287                    group: AccessGroup::FriendZone,
288                    permissions: AccessPermissions::Full,
289                },
290                AccessPair {
291                    group: AccessGroup::OthersZone,
292                    permissions: AccessPermissions::ReadAndCall,
293                },
294                AccessPair {
295                    group: AccessGroup::OwnerDec,
296                    permissions: AccessPermissions::Full,
297                },
298                AccessPair {
299                    group: AccessGroup::OthersDec,
300                    permissions: AccessPermissions::ReadAndCall,
301                },
302            ])
303        })
304        .to_owned()
305    }
306
307    pub fn full() -> Self {
308        static D: once_cell::sync::OnceCell<AccessString> = once_cell::sync::OnceCell::new();
309        D.get_or_init(|| {
310            Self::make(&[
311                AccessPair {
312                    group: AccessGroup::CurrentDevice,
313                    permissions: AccessPermissions::Full,
314                },
315                AccessPair {
316                    group: AccessGroup::CurrentZone,
317                    permissions: AccessPermissions::Full,
318                },
319                AccessPair {
320                    group: AccessGroup::FriendZone,
321                    permissions: AccessPermissions::Full,
322                },
323                AccessPair {
324                    group: AccessGroup::OthersZone,
325                    permissions: AccessPermissions::Full,
326                },
327                AccessPair {
328                    group: AccessGroup::OwnerDec,
329                    permissions: AccessPermissions::Full,
330                },
331                AccessPair {
332                    group: AccessGroup::OthersDec,
333                    permissions: AccessPermissions::Full,
334                },
335            ])
336        })
337        .to_owned()
338    }
339
340    pub fn dec_default() -> Self {
341        Self::make(&[
342            AccessPair {
343                group: AccessGroup::CurrentDevice,
344                permissions: AccessPermissions::Full,
345            },
346            AccessPair {
347                group: AccessGroup::CurrentZone,
348                permissions: AccessPermissions::Full,
349            },
350            AccessPair {
351                group: AccessGroup::FriendZone,
352                permissions: AccessPermissions::Full,
353            },
354            AccessPair {
355                group: AccessGroup::OwnerDec,
356                permissions: AccessPermissions::Full,
357            },
358            AccessPair {
359                group: AccessGroup::OthersDec,
360                permissions: AccessPermissions::Full,
361            },
362        ])
363    }
364
365    fn to_string(&self) -> String {
366        ACCESS_GROUP_LIST
367            .iter()
368            .map(|v| self.get_group_permissions(*v).as_str())
369            .collect()
370    }
371}
372
373impl TryFrom<&str> for AccessString {
374    type Error = BuckyError;
375
376    fn try_from(value: &str) -> BuckyResult<Self> {
377        Self::from_str(value)
378    }
379}
380
381impl FromStr for AccessString {
382    type Err = BuckyError;
383
384    fn from_str(value: &str) -> BuckyResult<Self> {
385        let mut access = AccessString::new(0);
386        for (mut chunk, group) in value.chars().filter(|c|c != &'_' && c != &' ').chunks(3).into_iter().zip(ACCESS_GROUP_LIST) {
387            access.set_group_permissions(*group, AccessPermissions::from_str(chunk.join("").as_str())?);
388        }
389
390        Ok(access)
391    }
392}
393
394impl Default for AccessString {
395    fn default() -> Self {
396        static D: once_cell::sync::OnceCell<AccessString> = once_cell::sync::OnceCell::new();
397        D.get_or_init(|| Self::dec_default()).to_owned()
398    }
399}
400
401impl std::fmt::Display for AccessString {
402    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
403        write!(f, "{}", Self::to_string(&self))
404    }
405}
406
407impl Serialize for AccessString {
408    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
409        S: Serializer,
410    {
411        serializer.serialize_str(self.to_string().as_str())
412    }
413}
414
415#[derive(Serialize, Deserialize)]
416struct AccessGroupStruct {
417    group: String,
418    access: String
419}
420
421struct AccessStringVisitor;
422
423impl<'de> Visitor<'de> for AccessStringVisitor {
424    type Value = AccessString;
425
426    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
427        formatter.write_str("a string represent access string")
428    }
429
430    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: Error {
431        AccessString::try_from(v).map_err(Error::custom)
432    }
433
434    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: SeqAccess<'de> {
435        let mut ret = AccessString::default();
436        while let Some(value) = seq.next_element::<AccessGroupStruct>()? {
437            ret.set_group_permissions(AccessGroup::try_from(value.group.as_str()).map_err(Error::custom)?,
438                                      AccessPermissions::from_str(value.access.as_str()).map_err(Error::custom)?);
439        }
440
441        Ok(ret)
442    }
443}
444
445impl<'de> Deserialize<'de> for AccessString {
446    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
447        deserializer.deserialize_any(AccessStringVisitor)
448    }
449}
450
451#[cfg(test)]
452mod test {
453    use super::*;
454
455    #[test]
456    fn test_access_permissons() {
457        let perm = AccessPermissions::ReadAndCall;
458        assert!(perm.test_op(RequestOpType::Read));
459        assert!(perm.test_op(RequestOpType::Call));
460        assert!(!perm.test_op(RequestOpType::Write));
461
462        let perm = AccessPermissions::None;
463        assert!(!perm.test_op(RequestOpType::Read));
464        assert!(!perm.test_op(RequestOpType::Call));
465        assert!(!perm.test_op(RequestOpType::Write));
466
467        let perm = AccessPermissions::Full;
468        assert!(perm.test_op(RequestOpType::Read));
469        assert!(perm.test_op(RequestOpType::Call));
470        assert!(perm.test_op(RequestOpType::Write));
471    }
472
473    #[test]
474    fn main() {
475
476        let s = "rwxrwxrwx---rwxrwx";
477        let v = AccessString::from_str(s).unwrap();
478        assert_eq!(v.to_string(), s);
479        
480        let mut access_string = AccessString::default();
481        println!("default={}", access_string);
482
483        let ret = access_string.is_accessable(AccessGroup::CurrentDevice, AccessPermission::Read);
484        assert!(ret);
485
486        let ret = access_string.is_accessable(AccessGroup::CurrentDevice, AccessPermission::Call);
487        assert!(ret);
488        let ret = access_string.is_accessable(AccessGroup::CurrentDevice, AccessPermission::Read);
489        assert!(ret);
490        let ret = access_string.is_accessable(AccessGroup::CurrentDevice, AccessPermission::Write);
491        assert!(ret);
492
493        let ret = access_string.is_accessable(AccessGroup::OthersDec, AccessPermission::Call);
494        assert!(ret);
495        let ret = access_string.is_accessable(AccessGroup::OthersDec, AccessPermission::Read);
496        assert!(ret);
497        let ret = access_string.is_accessable(AccessGroup::OthersDec, AccessPermission::Write);
498        assert!(ret);
499
500        access_string.clear_group_permission(AccessGroup::OthersDec, AccessPermission::Read);
501        let ret = access_string.is_accessable(AccessGroup::OthersDec, AccessPermission::Read);
502        assert!(!ret);
503
504        access_string.clear_group_permission(AccessGroup::OthersDec, AccessPermission::Call);
505        let ret = access_string.is_accessable(AccessGroup::OthersDec, AccessPermission::Call);
506        assert!(!ret);
507
508        let c = access_string.get_group_permissions(AccessGroup::CurrentZone);
509        assert_eq!(c, AccessPermissions::Full);
510
511        println!("{}", c);
512
513        access_string.clear_group_permissions(AccessGroup::CurrentZone);
514        let c = access_string.get_group_permissions(AccessGroup::CurrentZone);
515        assert_eq!(c, AccessPermissions::None);
516
517        access_string.set_group_permission(AccessGroup::CurrentZone, AccessPermission::Call);
518        access_string.set_group_permission(AccessGroup::CurrentZone, AccessPermission::Read);
519
520        access_string.set_group_permissions(AccessGroup::CurrentZone, AccessPermissions::ReadAndCall);
521        
522        println!("{}", access_string);
523
524        let access_string2 = AccessString::try_from(access_string.to_string().as_str());
525        assert!(access_string2.is_ok());
526        assert_eq!(access_string.value(), access_string2.unwrap().value());
527
528        let c = access_string.get_group_permissions(AccessGroup::CurrentZone);
529        assert_eq!(c, AccessPermissions::ReadAndCall);
530        println!("{}", c);
531    }
532}