atelier_json/
writer.rs

1use crate::syntax::*;
2use crate::FILE_EXTENSION;
3use atelier_core::error::{ErrorKind, Result as ModelResult, ResultExt};
4use atelier_core::io::ModelWriter;
5use atelier_core::model::shapes::{
6    AppliedTraits, HasTraits, MemberShape, ShapeKind, TopLevelShape,
7};
8use atelier_core::model::values::{Number, Value as NodeValue};
9use atelier_core::model::{HasIdentity, Model, ShapeID};
10use atelier_core::syntax::{
11    MEMBER_COLLECTION_OPERATIONS, MEMBER_CREATE, MEMBER_DELETE, MEMBER_ERRORS, MEMBER_IDENTIFIERS,
12    MEMBER_INPUT, MEMBER_KEY, MEMBER_LIST, MEMBER_MEMBER, MEMBER_OPERATIONS, MEMBER_OUTPUT,
13    MEMBER_PUT, MEMBER_READ, MEMBER_RENAME, MEMBER_RESOURCES, MEMBER_UPDATE, MEMBER_VALUE,
14    MEMBER_VERSION, MODEL_METADATA, MODEL_SHAPES, SHAPE_APPLY, SHAPE_LIST, SHAPE_MAP,
15    SHAPE_OPERATION, SHAPE_RESOURCE, SHAPE_SERVICE, SHAPE_SET, SHAPE_STRUCTURE, SHAPE_UNION,
16};
17use serde_json::{to_writer, to_writer_pretty, Map, Number as JsonNumber, Value};
18use std::io::Write;
19
20// ------------------------------------------------------------------------------------------------
21// Public Types
22// ------------------------------------------------------------------------------------------------
23
24///
25/// This struct implements the `ModelWriter` trait to write a [Model](../atelier_core/model/struct.Model.html)
26/// in the [JSON AST](https://awslabs.github.io/smithy/1.0/spec/core/json-ast.html) representation.
27///
28/// Currently the JSON writer takes only one parameter which determines whether the resulting JSON
29/// should be *pretty printed* or not, the default is `false`.
30///
31/// ```rust
32/// use atelier_json::JsonWriter;
33///
34/// let writer = JsonWriter::default(); // pretty printing off.
35///
36/// let writer = JsonWriter::new(true); // pretty printing on.
37/// ```
38///
39#[allow(missing_debug_implementations)]
40pub struct JsonWriter {
41    pretty_print: bool,
42}
43
44// ------------------------------------------------------------------------------------------------
45// Public Functions
46// ------------------------------------------------------------------------------------------------
47
48///
49/// Return a [JSON AST](https://awslabs.github.io/smithy/1.0/spec/core/json-ast.html) representation
50/// of a model. The return value is a [Serde JSON/(https://docs.serde.rs/serde_json/) `Value` that
51/// represents the top-level model.
52///
53/// This function is used in the `JsonWriter` implementation.
54///
55pub fn model_to_json(model: &Model) -> Value {
56    let mut top: Map<String, Value> = Default::default();
57
58    let _ = top.insert(
59        ADD_MODEL_SMITHY_VERSION.to_string(),
60        Value::String(model.smithy_version().to_string()),
61    );
62
63    if model.has_metadata() {
64        let mut meta_map: Map<String, Value> = Default::default();
65        for (key, value) in model.metadata() {
66            let _ = meta_map.insert(key.to_string(), from_value(value));
67        }
68        let _ = top.insert(MODEL_METADATA.to_string(), Value::Object(meta_map));
69    }
70    let _ = top.insert(MODEL_SHAPES.to_string(), from_shapes(model));
71
72    Value::Object(top)
73}
74
75// ------------------------------------------------------------------------------------------------
76// Implementations
77// ------------------------------------------------------------------------------------------------
78
79impl Default for JsonWriter {
80    fn default() -> Self {
81        Self {
82            pretty_print: false,
83        }
84    }
85}
86
87impl ModelWriter for JsonWriter {
88    fn write(&mut self, w: &mut impl Write, model: &Model) -> ModelResult<()> {
89        let json = model_to_json(model);
90
91        if self.pretty_print {
92            to_writer_pretty(w, &json)
93                .chain_err(|| ErrorKind::Serialization(FILE_EXTENSION.to_string()).to_string())
94        } else {
95            to_writer(w, &json)
96                .chain_err(|| ErrorKind::Serialization(FILE_EXTENSION.to_string()).to_string())
97        }
98    }
99}
100
101impl<'a> JsonWriter {
102    pub fn new(pretty_print: bool) -> Self {
103        Self { pretty_print }
104    }
105}
106
107// ------------------------------------------------------------------------------------------------
108// Private Functions
109// ------------------------------------------------------------------------------------------------
110
111fn from_shapes(model: &Model) -> Value {
112    let mut shape_map: Map<String, Value> = Default::default();
113    for shape in model.shapes() {
114        let _ = shape_map.insert(shape.id().to_string(), from_shape(shape));
115    }
116    Value::Object(shape_map)
117}
118
119fn from_shape(shape: &TopLevelShape) -> Value {
120    let mut shape_map: Map<String, Value> = Default::default();
121    if shape.has_traits() {
122        let _ = shape_map.insert(
123            ADD_SHAPE_KEY_TRAITS.to_string(),
124            from_traits(shape.traits()),
125        );
126    }
127    match shape.body() {
128        ShapeKind::Simple(v) => {
129            let _ = shape_map.insert(ADD_SHAPE_KEY_TYPE.to_string(), Value::String(v.to_string()));
130        }
131        ShapeKind::List(v) => {
132            let _ = shape_map.insert(
133                ADD_SHAPE_KEY_TYPE.to_string(),
134                Value::String(SHAPE_LIST.to_string()),
135            );
136            let _ = shape_map.insert(MEMBER_MEMBER.to_string(), from_member(v.member()));
137        }
138        ShapeKind::Set(v) => {
139            let _ = shape_map.insert(
140                ADD_SHAPE_KEY_TYPE.to_string(),
141                Value::String(SHAPE_SET.to_string()),
142            );
143            let _ = shape_map.insert(MEMBER_MEMBER.to_string(), from_member(v.member()));
144        }
145        ShapeKind::Map(v) => {
146            let _ = shape_map.insert(
147                ADD_SHAPE_KEY_TYPE.to_string(),
148                Value::String(SHAPE_MAP.to_string()),
149            );
150            let _ = shape_map.insert(MEMBER_KEY.to_string(), from_member(v.key()));
151            let _ = shape_map.insert(MEMBER_VALUE.to_string(), from_member(v.value()));
152        }
153        ShapeKind::Structure(v) => {
154            let _ = shape_map.insert(
155                ADD_SHAPE_KEY_TYPE.to_string(),
156                Value::String(SHAPE_STRUCTURE.to_string()),
157            );
158            if v.has_members() {
159                let _ =
160                    shape_map.insert(ADD_SHAPE_KEY_MEMBERS.to_string(), from_members(v.members()));
161            }
162        }
163        ShapeKind::Union(v) => {
164            let _ = shape_map.insert(
165                ADD_SHAPE_KEY_TYPE.to_string(),
166                Value::String(SHAPE_UNION.to_string()),
167            );
168            if v.has_members() {
169                let _ =
170                    shape_map.insert(ADD_SHAPE_KEY_MEMBERS.to_string(), from_members(v.members()));
171            }
172        }
173        ShapeKind::Service(v) => {
174            let _ = shape_map.insert(
175                ADD_SHAPE_KEY_TYPE.to_string(),
176                Value::String(SHAPE_SERVICE.to_string()),
177            );
178            let _ = shape_map.insert(
179                MEMBER_VERSION.to_string(),
180                Value::String(v.version().to_string()),
181            );
182            if v.has_operations() {
183                let _ = shape_map.insert(
184                    MEMBER_OPERATIONS.to_string(),
185                    Value::Array(v.operations().map(|o| from_reference(o)).collect()),
186                );
187            }
188            if v.has_resources() {
189                let _ = shape_map.insert(
190                    MEMBER_RESOURCES.to_string(),
191                    Value::Array(v.resources().map(|o| from_reference(o)).collect()),
192                );
193            }
194            if v.has_renames() {
195                let mut rename_map: Map<String, Value> = Default::default();
196                for (k, v) in v.renames() {
197                    let _ = rename_map.insert(k.to_string(), Value::String(v.to_string()));
198                }
199                let _ = shape_map.insert(MEMBER_RENAME.to_string(), Value::Object(rename_map));
200            }
201        }
202        ShapeKind::Operation(v) => {
203            let _ = shape_map.insert(
204                ADD_SHAPE_KEY_TYPE.to_string(),
205                Value::String(SHAPE_OPERATION.to_string()),
206            );
207            if let Some(v) = v.input() {
208                let _ = shape_map.insert(MEMBER_INPUT.to_string(), from_reference(v));
209            }
210            if let Some(v) = v.output() {
211                let _ = shape_map.insert(MEMBER_OUTPUT.to_string(), from_reference(v));
212            }
213            if v.has_errors() {
214                let _ = shape_map.insert(
215                    MEMBER_ERRORS.to_string(),
216                    Value::Array(v.errors().map(|o| from_reference(o)).collect()),
217                );
218            }
219        }
220        ShapeKind::Resource(v) => {
221            let _ = shape_map.insert(
222                ADD_SHAPE_KEY_TYPE.to_string(),
223                Value::String(SHAPE_RESOURCE.to_string()),
224            );
225            if v.has_identifiers() {
226                let mut id_map: Map<String, Value> = Default::default();
227                for (id, ref_id) in v.identifiers() {
228                    let _ = id_map.insert(id.to_string(), from_reference(ref_id));
229                }
230                let _ = shape_map.insert(MEMBER_IDENTIFIERS.to_string(), Value::Object(id_map));
231            }
232            if let Some(v) = v.create() {
233                let _ = shape_map.insert(MEMBER_CREATE.to_string(), from_reference(v));
234            }
235            if let Some(v) = v.put() {
236                let _ = shape_map.insert(MEMBER_PUT.to_string(), from_reference(v));
237            }
238            if let Some(v) = v.read() {
239                let _ = shape_map.insert(MEMBER_READ.to_string(), from_reference(v));
240            }
241            if let Some(v) = v.update() {
242                let _ = shape_map.insert(MEMBER_UPDATE.to_string(), from_reference(v));
243            }
244            if let Some(v) = v.delete() {
245                let _ = shape_map.insert(MEMBER_DELETE.to_string(), from_reference(v));
246            }
247            if let Some(v) = v.list() {
248                let _ = shape_map.insert(MEMBER_LIST.to_string(), from_reference(v));
249            }
250            if v.has_operations() {
251                let _ = shape_map.insert(
252                    MEMBER_OPERATIONS.to_string(),
253                    Value::Array(v.operations().map(|o| from_reference(o)).collect()),
254                );
255            }
256            if v.has_collection_operations() {
257                let _ = shape_map.insert(
258                    MEMBER_COLLECTION_OPERATIONS.to_string(),
259                    Value::Array(
260                        v.collection_operations()
261                            .map(|o| from_reference(o))
262                            .collect(),
263                    ),
264                );
265            }
266            if v.has_resources() {
267                let _ = shape_map.insert(
268                    MEMBER_RESOURCES.to_string(),
269                    Value::Array(v.resources().map(|o| from_reference(o)).collect()),
270                );
271            }
272        }
273        ShapeKind::Unresolved => {
274            let _ = shape_map.insert(
275                ADD_SHAPE_KEY_TYPE.to_string(),
276                Value::String(SHAPE_APPLY.to_string()),
277            );
278        }
279    }
280    Value::Object(shape_map)
281}
282
283fn from_traits(traits: &AppliedTraits) -> Value {
284    let mut trait_map: Map<String, Value> = Default::default();
285    for (id, value) in traits {
286        let _ = trait_map.insert(
287            id.to_string(),
288            match value {
289                None => Value::Object(Default::default()),
290                Some(value) => from_value(value),
291            },
292        );
293    }
294    Value::Object(trait_map)
295}
296
297fn from_members<'a>(members: impl Iterator<Item = &'a MemberShape>) -> Value {
298    let mut members_map: Map<String, Value> = Default::default();
299    for member in members {
300        let _ = members_map.insert(member.id().to_string(), from_member(member));
301    }
302    Value::Object(members_map)
303}
304
305fn from_member(member: &MemberShape) -> Value {
306    let mut member_map: Map<String, Value> = Default::default();
307    let _ = member_map.insert(
308        ADD_SHAPE_KEY_TARGET.to_string(),
309        Value::String(member.target().to_string()),
310    );
311    if member.has_traits() {
312        let _ = member_map.insert(
313            ADD_SHAPE_KEY_TRAITS.to_string(),
314            from_traits(member.traits()),
315        );
316    }
317    Value::Object(member_map)
318}
319
320fn from_value(value: &NodeValue) -> Value {
321    match value {
322        NodeValue::None => Value::Null,
323        NodeValue::Array(v) => Value::Array(v.iter().map(|v| from_value(v)).collect()),
324        NodeValue::Object(v) => {
325            let mut object: Map<String, Value> = Default::default();
326            for (k, v) in v {
327                let _ = object.insert(k.clone(), from_value(v));
328            }
329            Value::Object(object)
330        }
331        NodeValue::Number(v) => match v {
332            Number::Integer(v) => Value::Number((*v).into()),
333            Number::Float(v) => Value::Number(JsonNumber::from_f64(*v).unwrap()),
334        },
335        NodeValue::Boolean(v) => Value::Bool(*v),
336        NodeValue::String(v) => Value::String(v.clone()),
337    }
338}
339
340fn from_reference(id: &ShapeID) -> Value {
341    let mut shape_map: Map<String, Value> = Default::default();
342    let _ = shape_map.insert(
343        ADD_SHAPE_KEY_TARGET.to_string(),
344        Value::String(id.to_string()),
345    );
346    Value::Object(shape_map)
347}