oca_ast_transformation/ast/
mod.rs1use indexmap::IndexMap;
2use serde::{
3 de::{self, MapAccess, Visitor},
4 ser::SerializeStruct,
5 Deserialize, Deserializer, Serialize, Serializer,
6};
7use std::hash::Hash;
8use std::{collections::HashMap, fmt};
9
10pub mod error;
11
12#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
13pub struct TransformationAST {
14 pub version: String,
15 pub commands: Vec<Command>,
16 pub commands_meta: IndexMap<usize, CommandMeta>,
17 pub meta: HashMap<String, String>,
18}
19
20#[derive(Debug, PartialEq, Serialize, Clone)]
21pub struct Command {
22 #[serde(rename = "type")]
23 pub kind: CommandType,
24 #[serde(flatten)]
25 pub object_kind: ObjectKind,
26}
27
28#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
29pub struct CommandMeta {
30 pub line_number: usize,
31 pub raw_line: String,
32}
33
34#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
35pub enum CommandType {
36 Rename,
37 Link,
38}
39
40#[derive(Debug, PartialEq, Clone, Eq)]
41pub enum ObjectKind {
42 Rename(RenameContent),
44 Link(LinkContent),
45}
46
47#[derive(Debug, PartialEq, Clone, Eq)]
48pub enum TransformationType {
49 Rename(RenameContent),
50 Link(LinkContent),
51}
52
53#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
54pub struct RenameContent {
55 #[serde(skip_serializing_if = "Option::is_none")]
56 pub attributes: Option<IndexMap<String, String>>,
57}
58
59#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
60pub struct LinkContent {
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub attributes: Option<IndexMap<String, String>>,
63}
64
65impl Hash for ObjectKind {
66 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
67 match self {
68 ObjectKind::Rename(content) => {
69 content.hash(state);
70 }
71 ObjectKind::Link(content) => {
72 content.hash(state);
73 }
74 }
75 }
76}
77
78impl Hash for RenameContent {
79 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
80 if let Some(attributes) = &self.attributes {
81 for (key, value) in attributes {
82 key.hash(state);
83 value.hash(state);
84 }
85 }
86 }
87}
88
89impl Hash for LinkContent {
90 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
91 if let Some(attributes) = &self.attributes {
92 for (key, value) in attributes {
93 key.hash(state);
94 value.hash(state);
95 }
96 }
97 }
98}
99
100impl Serialize for ObjectKind {
123 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
124 where
125 S: Serializer,
126 {
127 let mut state = serializer.serialize_struct("ObjectKind", 3)?;
128 match self {
129 ObjectKind::Rename(content) => {
130 state.serialize_field("object_kind", "Rename")?;
131 state.serialize_field("content", content)?;
132 }
133 ObjectKind::Link(content) => {
134 state.serialize_field("object_kind", "Link")?;
135 state.serialize_field("content", content)?;
136 }
137 }
138 state.end()
139 }
140}
141
142#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
143#[serde(untagged)]
144pub enum NestedValue {
145 Value(String),
146 Object(IndexMap<String, NestedValue>),
147 Array(Vec<NestedValue>),
148}
149impl NestedValue {
150 }
169impl<'de> Deserialize<'de> for Command {
171 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
172 where
173 D: Deserializer<'de>,
174 {
175 enum Field {
176 Kind,
177 ObjectKind,
178 }
179
180 impl<'de> Deserialize<'de> for Field {
181 fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
182 where
183 D: Deserializer<'de>,
184 {
185 struct FieldVisitor;
186
187 impl Visitor<'_> for FieldVisitor {
188 type Value = Field;
189
190 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
191 formatter.write_str("`type` or `object_kind`")
192 }
193
194 fn visit_str<E>(self, value: &str) -> Result<Field, E>
195 where
196 E: de::Error,
197 {
198 match value {
199 "type" => Ok(Field::Kind),
200 "object_kind" => Ok(Field::ObjectKind),
201 _ => Err(de::Error::unknown_field(value, FIELDS)),
202 }
203 }
204 }
205
206 deserializer.deserialize_identifier(FieldVisitor)
207 }
208 }
209
210 struct CommandVisitor;
211
212 impl<'de> Visitor<'de> for CommandVisitor {
213 type Value = Command;
214
215 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
216 formatter.write_str("struct Command")
217 }
218
219 fn visit_map<V>(self, mut map: V) -> Result<Command, V::Error>
220 where
221 V: MapAccess<'de>,
222 {
223 let mut kind = None;
224 let mut object_kind = None;
225
226 while let Some(key) = map.next_key()? {
227 match key {
228 Field::Kind => {
229 if kind.is_some() {
230 return Err(de::Error::duplicate_field("type"));
231 }
232 kind = Some(map.next_value()?);
233 }
234 Field::ObjectKind => {
235 if object_kind.is_some() {
236 return Err(de::Error::duplicate_field("object_kind"));
237 }
238 let object_kind_str: String = map.next_value()?;
239 match object_kind_str.as_str() {
240 "Rename" => {
241 let _content_key: Option<String> = map.next_key()?;
244 let content: RenameContent = map.next_value()?;
245 object_kind = Some(ObjectKind::Rename(content));
246 }
247 "Link" => {
248 let _content_key: Option<String> = map.next_key()?;
251 let content: LinkContent = map.next_value()?;
252 object_kind = Some(ObjectKind::Link(content));
253 }
254 _ => {}
255 }
256 }
257 }
258 }
259
260 let kind = kind.ok_or_else(|| de::Error::missing_field("type"))?;
261 let object_kind =
262 object_kind.ok_or_else(|| de::Error::missing_field("object_kind"))?;
263
264 Ok(Command { kind, object_kind })
265 }
266 }
267
268 const FIELDS: &[&str] = &["type", "object_kind", "content"];
269 const _VARIANTS: &[&str] = &["Rename"];
270 deserializer.deserialize_struct("Command", FIELDS, CommandVisitor)
271 }
272}
273
274impl TransformationAST {
275 pub fn new() -> Self {
276 TransformationAST {
277 version: String::from("1.0.0"),
279 commands: Vec::new(),
280 commands_meta: IndexMap::new(),
281 meta: HashMap::new(),
282 }
283 }
284}
285
286impl Default for TransformationAST {
287 fn default() -> Self {
288 Self::new()
289 }
290}
291
292impl From<u8> for ObjectKind {
309 fn from(val: u8) -> Self {
310 match val {
311 0 => ObjectKind::Rename(RenameContent { attributes: None }),
312 1 => ObjectKind::Link(LinkContent { attributes: None }),
313 _ => panic!("Unknown object type"),
314 }
315 }
316}
317
318impl From<ObjectKind> for u8 {
319 fn from(val: ObjectKind) -> Self {
320 match val {
321 ObjectKind::Rename(_) => 0,
322 ObjectKind::Link(_) => 1,
323 }
324 }
325}
326
327impl<'de> Deserialize<'de> for ObjectKind {
328 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
329 where
330 D: Deserializer<'de>,
331 {
332 let s = String::deserialize(deserializer)?;
333 match s.as_str() {
334 "Rename" => Ok(ObjectKind::Rename(RenameContent { attributes: None })),
335 "Link" => Ok(ObjectKind::Link(LinkContent { attributes: None })),
336 _ => Err(serde::de::Error::custom(format!(
337 "unknown object kind: {}",
338 s
339 ))),
340 }
341 }
342}
343
344#[cfg(test)]
345mod tests {
346 use super::*;
347
348 #[test]
349 fn test_ast_serialize() {
350 let mut attributes = IndexMap::new();
351
352 attributes.insert("digest".to_string(), "d".to_string());
353 let command = Command {
354 kind: CommandType::Rename,
355 object_kind: ObjectKind::Rename(RenameContent {
356 attributes: Some(attributes),
357 }),
358 };
359
360 let mut ast = TransformationAST::new();
361 ast.commands.push(command);
362
363 let serialized = serde_json::to_string(&ast).unwrap();
364 assert_eq!(
365 serialized,
366 r#"{"version":"1.0.0","commands":[{"type":"Rename","object_kind":"Rename","content":{"attributes":{"digest":"d"}}}],"commands_meta":{},"meta":{}}"#
367 );
368
369 let deser: TransformationAST = serde_json::from_str(&serialized).unwrap();
370 assert_eq!(ast, deser);
371 }
372}