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 fmt::Display for Rights {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 let Self(rights) = &self;
62 match *rights {
63 fio::R_STAR_DIR => write!(f, "r*"),
64 fio::W_STAR_DIR => write!(f, "w*"),
65 fio::X_STAR_DIR => write!(f, "x*"),
66 fio::RW_STAR_DIR => write!(f, "rw*"),
67 fio::RX_STAR_DIR => write!(f, "rx*"),
68 ops => write!(f, "{:?}", ops),
69 }
70 }
71}
72
73#[cfg(feature = "serde")]
74impl Serialize for Rights {
75 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76 where
77 S: Serializer,
78 {
79 let Self(rights) = self;
80 rights.bits().serialize(serializer)
81 }
82}
83
84#[cfg(feature = "serde")]
85impl<'de> Deserialize<'de> for Rights {
86 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
87 where
88 D: Deserializer<'de>,
89 {
90 let bits: u64 = Deserialize::deserialize(deserializer)?;
91 let rights = fio::Operations::from_bits(bits)
92 .ok_or_else(|| serde::de::Error::custom("invalid value for fuchsia.io/Operations"))?;
93 Ok(Self(rights))
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use assert_matches::assert_matches;
101
102 #[test]
103 fn validate_next() {
104 assert_matches!(
105 Rights(fio::Operations::empty())
106 .validate_next(&Rights(fio::R_STAR_DIR,), ExtendedMoniker::ComponentManager),
107 Ok(())
108 );
109 assert_matches!(
110 Rights(fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES,)
111 .validate_next(&Rights(fio::R_STAR_DIR), ExtendedMoniker::ComponentManager),
112 Ok(())
113 );
114 let provided = fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES;
115 assert_eq!(
116 Rights(fio::R_STAR_DIR)
117 .validate_next(&Rights(provided), ExtendedMoniker::ComponentManager),
118 Err(RightsRoutingError::Invalid {
119 moniker: ExtendedMoniker::ComponentManager,
120 requested: Rights::from(fio::R_STAR_DIR),
121 provided: Rights::from(provided),
122 })
123 );
124 let provided = fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES;
125 assert_eq!(
126 Rights(fio::Operations::WRITE_BYTES)
127 .validate_next(&Rights(provided), ExtendedMoniker::ComponentManager),
128 Err(RightsRoutingError::Invalid {
129 moniker: ExtendedMoniker::ComponentManager,
130 requested: Rights::from(fio::Operations::WRITE_BYTES),
131 provided: Rights::from(provided),
132 })
133 );
134 }
135}