1use crate::error::RightsRoutingError;
6use fidl_fuchsia_io as fio;
7use moniker::ExtendedMoniker;
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
10use std::fmt;
11
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
14pub struct Rights(fio::Operations);
15
16impl Rights {
17 pub fn validate_next(
21 &self,
22 next_rights: &Self,
23 moniker: ExtendedMoniker,
24 ) -> Result<(), RightsRoutingError> {
25 if next_rights.0.contains(self.0) {
26 Ok(())
27 } else {
28 Err(RightsRoutingError::Invalid { moniker, requested: *self, provided: *next_rights })
29 }
30 }
31}
32
33impl From<fio::Operations> for Rights {
35 fn from(rights: fio::Operations) -> Self {
36 Rights(rights)
37 }
38}
39
40impl From<Rights> for fio::Flags {
41 fn from(rights: Rights) -> Self {
42 fio::Flags::from_bits_retain(rights.0.bits())
43 }
44}
45
46impl Into<u64> for Rights {
47 fn into(self) -> u64 {
48 self.0.bits()
49 }
50}
51
52impl Into<fio::Operations> for Rights {
53 fn into(self) -> fio::Operations {
54 let Self(ops) = self;
55 ops
56 }
57}
58
59impl From<fio::Flags> for Rights {
60 fn from(flags: fio::Flags) -> Self {
61 Self(
62 fio::Operations::from_bits(flags.bits())
63 .expect("operations is bit-compatible with flags"),
64 )
65 }
66}
67
68impl fmt::Display for Rights {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 let Self(rights) = &self;
71 match *rights {
72 fio::R_STAR_DIR => write!(f, "r*"),
73 fio::W_STAR_DIR => write!(f, "w*"),
74 fio::X_STAR_DIR => write!(f, "x*"),
75 fio::RW_STAR_DIR => write!(f, "rw*"),
76 fio::RX_STAR_DIR => write!(f, "rx*"),
77 ops => write!(f, "{:?}", ops),
78 }
79 }
80}
81
82#[cfg(feature = "serde")]
83impl Serialize for Rights {
84 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85 where
86 S: Serializer,
87 {
88 let Self(rights) = self;
89 rights.bits().serialize(serializer)
90 }
91}
92
93#[cfg(feature = "serde")]
94impl<'de> Deserialize<'de> for Rights {
95 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
96 where
97 D: Deserializer<'de>,
98 {
99 let bits: u64 = Deserialize::deserialize(deserializer)?;
100 let rights = fio::Operations::from_bits(bits)
101 .ok_or_else(|| serde::de::Error::custom("invalid value for fuchsia.io/Operations"))?;
102 Ok(Self(rights))
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use assert_matches::assert_matches;
110
111 #[test]
112 fn validate_next() {
113 assert_matches!(
114 Rights(fio::Operations::empty())
115 .validate_next(&Rights(fio::R_STAR_DIR,), ExtendedMoniker::ComponentManager),
116 Ok(())
117 );
118 assert_matches!(
119 Rights(fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES,)
120 .validate_next(&Rights(fio::R_STAR_DIR), ExtendedMoniker::ComponentManager),
121 Ok(())
122 );
123 let provided = fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES;
124 assert_eq!(
125 Rights(fio::R_STAR_DIR)
126 .validate_next(&Rights(provided), ExtendedMoniker::ComponentManager),
127 Err(RightsRoutingError::Invalid {
128 moniker: ExtendedMoniker::ComponentManager,
129 requested: Rights::from(fio::R_STAR_DIR),
130 provided: Rights::from(provided),
131 })
132 );
133 let provided = fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES;
134 assert_eq!(
135 Rights(fio::Operations::WRITE_BYTES)
136 .validate_next(&Rights(provided), ExtendedMoniker::ComponentManager),
137 Err(RightsRoutingError::Invalid {
138 moniker: ExtendedMoniker::ComponentManager,
139 requested: Rights::from(fio::Operations::WRITE_BYTES),
140 provided: Rights::from(provided),
141 })
142 );
143 }
144}