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 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}