drogue_client/
translator.rs1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3
4pub trait Translator {
34 fn spec(&self) -> &Map<String, Value>;
35 fn status(&self) -> &Map<String, Value>;
36
37 fn spec_mut(&mut self) -> &mut Map<String, Value>;
38 fn status_mut(&mut self) -> &mut Map<String, Value>;
39
40 fn section<D>(&self) -> Option<Result<D, serde_json::Error>>
41 where
42 D: for<'de> Deserialize<'de> + Dialect,
43 {
44 match D::section() {
45 Section::Spec => self.spec_for(D::key()),
46 Section::Status => self.status_for(D::key()),
47 }
48 }
49
50 fn set_section<D>(&mut self, d: D) -> Result<(), serde_json::Error>
51 where
52 D: Serialize + Dialect,
53 {
54 let v = serde_json::to_value(d)?;
55
56 match D::section() {
57 Section::Spec => self.spec_mut().insert(D::key().to_string(), v),
58 Section::Status => self.status_mut().insert(D::key().to_string(), v),
59 };
60
61 Ok(())
62 }
63
64 fn update_section<D, F>(&mut self, f: F) -> Result<(), serde_json::Error>
65 where
66 D: Serialize + for<'de> Deserialize<'de> + Dialect + Default,
67 F: FnOnce(D) -> D,
68 {
69 let s = match self.section::<D>() {
70 Some(Ok(s)) => f(s),
71 None => {
72 let s = D::default();
73 f(s)
74 }
75 Some(Err(err)) => return Err(err),
76 };
77
78 self.set_section(s)
79 }
80
81 fn clear_section<D>(&mut self)
82 where
83 D: Serialize + Dialect,
84 {
85 match D::section() {
86 Section::Spec => self.spec_mut().remove(D::key()),
87 Section::Status => self.status_mut().remove(D::key()),
88 };
89 }
90
91 fn spec_for<T, S>(&self, key: S) -> Option<Result<T, serde_json::Error>>
92 where
93 T: for<'de> Deserialize<'de>,
94 S: AsRef<str>,
95 {
96 let result = self
97 .spec()
98 .get(key.as_ref())
99 .map(|value| serde_json::from_value(value.clone()));
100
101 result
102 }
103
104 fn status_for<T, S>(&self, key: S) -> Option<Result<T, serde_json::Error>>
105 where
106 T: for<'de> Deserialize<'de>,
107 S: AsRef<str>,
108 {
109 let result = self
110 .status()
111 .get(key.as_ref())
112 .map(|value| serde_json::from_value(value.clone()));
113
114 result
115 }
116
117 fn attribute<A>(&self) -> A::Output
118 where
119 A: Attribute,
120 {
121 A::extract(self.section::<A::Dialect>())
122 }
123}
124
125#[derive(Eq, PartialEq, Clone, Copy, Debug)]
127pub enum Section {
128 Spec,
130 Status,
132}
133
134pub trait Dialect {
136 fn key() -> &'static str;
138 fn section() -> Section;
140}
141
142#[macro_export]
153macro_rules! dialect {
154 ($dialect:ty [ $section:expr => $key:literal ]) => {
155 impl $crate::Dialect for $dialect {
156 fn key() -> &'static str {
157 $key
158 }
159
160 fn section() -> $crate::Section {
161 $section
162 }
163 }
164 };
165}
166
167pub trait Attribute {
169 type Dialect: for<'de> Deserialize<'de> + Dialect;
170 type Output;
171
172 fn extract(dialect: Option<Result<Self::Dialect, serde_json::Error>>) -> Self::Output;
173}
174
175#[macro_export]
177macro_rules! attribute {
178 ($v:vis $dialect:ty [$name:ident : $output:ty] => | $value:ident | $($code:tt)* ) => {
179 $v struct $name;
180
181 impl $crate::Attribute for $name {
182 type Dialect = $dialect;
183 type Output = $output;
184
185 fn extract(dialect: Option<Result<Self::Dialect, serde_json::Error>>) -> Self::Output {
186 let $value = dialect;
187 $($code)*
188 }
189 }
190 };
191}
192
193#[macro_export]
197macro_rules! translator {
198 ($name:ty) => {
199 impl Translator for $name {
200 fn spec(&self) -> &Map<String, Value> {
201 &self.spec
202 }
203
204 fn status(&self) -> &Map<String, Value> {
205 &self.status
206 }
207
208 fn spec_mut(&mut self) -> &mut Map<String, Value> {
209 &mut self.spec
210 }
211
212 fn status_mut(&mut self) -> &mut Map<String, Value> {
213 &mut self.status
214 }
215 }
216 };
217}
218
219#[cfg(test)]
220mod test {
221
222 use super::*;
223 use serde_json::Error;
224
225 #[derive(Deserialize, Debug, Clone, Default)]
226 pub struct Foo {
227 pub spec: Map<String, Value>,
228 pub status: Map<String, Value>,
229 }
230
231 translator!(Foo);
232
233 #[derive(Deserialize, Debug, Clone, Default)]
234 pub struct Bar {
235 pub name: String,
236 }
237
238 impl Dialect for Bar {
239 fn key() -> &'static str {
240 "bar"
241 }
242
243 fn section() -> Section {
244 Section::Spec
245 }
246 }
247
248 pub struct Name {}
249
250 impl Attribute for Name {
251 type Dialect = Bar;
252 type Output = String;
253
254 fn extract(dialect: Option<Result<Self::Dialect, Error>>) -> Self::Output {
255 dialect
256 .and_then(|d| d.map(|d| d.name).ok())
257 .unwrap_or_default()
258 }
259 }
260
261 #[test]
262 fn test1() {
263 let i = Foo::default();
264 let _: Option<Result<Bar, _>> = i.section::<Bar>();
265 }
266
267 #[test]
268 fn test_attr() {
269 let i = Foo::default();
270 let name: String = i.attribute::<Name>();
271 assert_eq!(name, "");
272 }
273}