opendal_core/layers/
capability_override.rs1use std::fmt;
19use std::sync::Arc;
20
21use serde_json::Map;
22use serde_json::Number;
23use serde_json::Value;
24
25use crate::raw::*;
26use crate::*;
27
28#[derive(Clone)]
56pub struct CapabilityOverrideLayer {
57 apply: Arc<dyn Fn(Capability) -> Capability + Send + Sync>,
58}
59
60impl fmt::Debug for CapabilityOverrideLayer {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.debug_struct("CapabilityOverrideLayer")
63 .finish_non_exhaustive()
64 }
65}
66
67impl CapabilityOverrideLayer {
68 pub fn new(apply: impl Fn(Capability) -> Capability + Send + Sync + 'static) -> Self {
70 Self {
71 apply: Arc::new(apply),
72 }
73 }
74
75 pub fn from_overrides(input: &str) -> Result<Self> {
84 let overrides = CapabilityOverrides::parse(input)?;
85 Ok(Self::new(move |cap| overrides.apply(cap)))
86 }
87}
88
89impl<A: Access> Layer<A> for CapabilityOverrideLayer {
90 type LayeredAccess = A;
91
92 fn layer(&self, inner: A) -> Self::LayeredAccess {
93 let info = inner.info();
94 let apply = self.apply.clone();
95 info.update_full_capability(|cap| apply(cap));
96 inner
97 }
98}
99
100#[derive(Clone, Debug, Default)]
101struct CapabilityOverrides {
102 values: Map<String, Value>,
103}
104
105impl CapabilityOverrides {
106 fn parse(input: &str) -> Result<Self> {
107 let mut overrides = Self::default();
108
109 for token in input.split(',').map(str::trim).filter(|v| !v.is_empty()) {
110 let (name, value) = parse_capability_override(token)?;
111 overrides.values.insert(name.to_string(), value);
112 overrides.try_apply(Capability::default()).map_err(|err| {
113 invalid_capability_override(token, &format!("failed to apply override: {err}"))
114 })?;
115 }
116
117 Ok(overrides)
118 }
119
120 fn apply(&self, cap: Capability) -> Capability {
121 self.try_apply(cap)
122 .expect("capability overrides must be validated before applying")
123 }
124
125 fn try_apply(&self, cap: Capability) -> Result<Capability> {
126 let mut value = serde_json::to_value(cap).map_err(|err| {
127 Error::new(
128 ErrorKind::Unexpected,
129 format!("failed to serialize capability: {err}"),
130 )
131 })?;
132 let object = value.as_object_mut().ok_or_else(|| {
133 Error::new(
134 ErrorKind::Unexpected,
135 "serialized capability must be a JSON object",
136 )
137 })?;
138 object.extend(self.values.clone());
139
140 serde_json::from_value(value).map_err(|err| {
141 Error::new(
142 ErrorKind::ConfigInvalid,
143 format!("failed to deserialize capability overrides: {err}"),
144 )
145 })
146 }
147}
148
149fn parse_capability_override(token: &str) -> Result<(&str, Value)> {
150 let Some((name, value)) = token.split_once('=') else {
151 return Err(invalid_capability_override(
152 token,
153 "expected `capability=value`",
154 ));
155 };
156
157 Ok((
158 name.trim(),
159 parse_capability_value(value.trim())
160 .map_err(|err| invalid_capability_override(token, &err.to_string()))?,
161 ))
162}
163
164fn invalid_capability_override(token: &str, reason: &str) -> Error {
165 Error::new(
166 ErrorKind::ConfigInvalid,
167 format!("invalid capability override entry `{token}`: {reason}"),
168 )
169}
170
171fn parse_capability_value(value: &str) -> Result<Value> {
172 match value {
173 "true" | "on" | "yes" => Ok(Value::Bool(true)),
174 "false" | "off" | "no" => Ok(Value::Bool(false)),
175 "none" | "null" | "unset" => Ok(Value::Null),
176 _ => value
177 .parse::<usize>()
178 .map(|v| Value::Number(Number::from(v)))
179 .map_err(|_| {
180 Error::new(
181 ErrorKind::ConfigInvalid,
182 "expected a boolean, non-negative integer, or `none`",
183 )
184 }),
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use crate::Operator;
192 use crate::services;
193
194 #[test]
195 fn capability_override_updates_full_capability_only() -> Result<()> {
196 let op = Operator::new(services::Memory::default())?
197 .layer(CapabilityOverrideLayer::new(|mut cap| {
198 cap.read = false;
199 cap.delete_max_size = Some(7);
200 cap
201 }))
202 .finish();
203
204 assert!(!op.info().full_capability().read);
205 assert_eq!(op.info().full_capability().delete_max_size, Some(7));
206
207 assert!(op.info().native_capability().read);
208 assert_ne!(
209 op.info().native_capability().delete_max_size,
210 op.info().full_capability().delete_max_size
211 );
212
213 Ok(())
214 }
215
216 #[test]
217 fn parse_capability_overrides() -> Result<()> {
218 let layer = CapabilityOverrideLayer::from_overrides(
219 "read=false,write_can_append=true,delete_max_size=7",
220 )?;
221 let op = Operator::new(services::Memory::default())?
222 .layer(layer)
223 .finish();
224
225 assert!(!op.info().full_capability().read);
226 assert!(op.info().full_capability().write_can_append);
227 assert_eq!(op.info().full_capability().delete_max_size, Some(7));
228
229 Ok(())
230 }
231
232 #[test]
233 fn parse_bool_assignments_and_unset_sizes() -> Result<()> {
234 let layer =
235 CapabilityOverrideLayer::from_overrides("read=false,write=true,delete_max_size=none")?;
236 let op = Operator::new(services::Memory::default())?
237 .layer(layer)
238 .finish();
239
240 assert!(!op.info().full_capability().read);
241 assert!(op.info().full_capability().write);
242 assert_eq!(op.info().full_capability().delete_max_size, None);
243
244 Ok(())
245 }
246
247 #[test]
248 fn reject_unknown_capability() {
249 let err = CapabilityOverrideLayer::from_overrides("not_a_capability=false").unwrap_err();
250 assert_eq!(err.kind(), ErrorKind::ConfigInvalid);
251 }
252
253 #[test]
254 fn reject_capability_shorthand() {
255 let err = CapabilityOverrideLayer::from_overrides("-read").unwrap_err();
256 assert_eq!(err.kind(), ErrorKind::ConfigInvalid);
257 }
258
259 #[test]
260 fn reject_invalid_capability_type() {
261 let err = CapabilityOverrideLayer::from_overrides("read=1").unwrap_err();
262 assert_eq!(err.kind(), ErrorKind::ConfigInvalid);
263 }
264}