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