1extern crate inflector;
2extern crate linked_hash_map;
3extern crate reproto_ast as ast;
4extern crate reproto_core as core;
5extern crate serde;
6extern crate serde_json;
7extern crate serde_yaml;
8
9mod format;
10mod json;
11mod sir;
12mod utils;
13mod yaml;
14
15pub use self::format::Format;
16pub use self::json::Json;
17pub use self::yaml::Yaml;
18use ast::{Attribute, AttributeItem, Decl, Field, InterfaceBody, Item, Name, SubType, TupleBody,
19 Type, TypeBody, TypeMember, Value};
20use core::errors::Result;
21use core::{Loc, RpPackage, Source, Span, DEFAULT_TAG};
22use inflector::cases::pascalcase::to_pascal_case;
23use inflector::cases::snakecase::to_snake_case;
24use linked_hash_map::LinkedHashMap;
25use sir::{FieldSir, Sir, SubTypeSir};
26use std::borrow::Cow;
27use std::cmp;
28use std::collections::{HashMap, HashSet};
29use std::fmt;
30use std::hash;
31use std::ops;
32use std::rc::Rc;
33
34#[derive(Debug)]
35pub struct Derive {
36 root_name: String,
37 format: Box<format::Format>,
38 package_prefix: Option<RpPackage>,
39}
40
41#[derive(Debug, Clone)]
42struct Context {
43 path: Vec<String>,
44 package_prefix: Option<Rc<RpPackage>>,
45}
46
47impl Context {
48 fn ident(&self) -> Result<&str> {
50 if let Some(ident) = self.path.iter().last() {
51 Ok(ident.as_str())
52 } else {
53 Err(format!("No last component in name").into())
54 }
55 }
56
57 fn join(&self, name: String) -> Context {
59 let mut path = self.path.iter().cloned().collect::<Vec<_>>();
60 path.push(name);
61
62 Context {
63 path: path,
64 package_prefix: self.package_prefix.clone(),
65 }
66 }
67
68 fn name(&self) -> Name<'static> {
70 Name::Absolute {
71 prefix: None,
72 parts: self.path
73 .clone()
74 .into_iter()
75 .map(|p| Loc::new(Cow::from(p), Span::empty()))
76 .collect(),
77 }
78 }
79}
80
81impl Derive {
82 pub fn new(
83 root_name: String,
84 format: Box<format::Format>,
85 package_prefix: Option<RpPackage>,
86 ) -> Derive {
87 Derive {
88 root_name: root_name,
89 format: format,
90 package_prefix: package_prefix,
91 }
92 }
93}
94
95type TypesCache<'input> = HashMap<Sir, Name<'input>>;
96
97#[derive(Debug, Clone)]
99pub struct Opaque<T> {
100 content: T,
101}
102
103impl<T> Opaque<T> {
104 pub fn new(content: T) -> Self {
105 Self { content: content }
106 }
107}
108
109impl<T> cmp::PartialEq for Opaque<T> {
110 fn eq(&self, _: &Self) -> bool {
111 true
112 }
113}
114
115impl<T> cmp::Eq for Opaque<T> {}
116
117impl<T> hash::Hash for Opaque<T> {
118 fn hash<H: hash::Hasher>(&self, _state: &mut H) {}
119}
120
121impl<T> ops::Deref for Opaque<T> {
122 type Target = T;
123
124 fn deref(&self) -> &Self::Target {
125 &self.content
126 }
127}
128
129impl<T> ops::DerefMut for Opaque<T> {
130 fn deref_mut(&mut self) -> &mut Self::Target {
131 &mut self.content
132 }
133}
134
135struct FieldInit<'a, 'input: 'a> {
136 span: &'a Span,
137 ctx: Context,
138 types: &'a mut TypesCache<'input>,
139}
140
141impl<'a, 'input: 'a> FieldInit<'a, 'input> {
142 fn new(
143 span: &'a Span,
144 ctx: Context,
145 types: &'a mut TypesCache<'input>,
146 ) -> FieldInit<'a, 'input> {
147 FieldInit { span, ctx, types }
148 }
149
150 fn init(
151 self,
152 original_name: String,
153 sir: &FieldSir,
154 members: &mut Vec<TypeMember<'input>>,
155 ) -> Result<Item<'input, Field<'input>>> {
156 let mut comment = Vec::new();
157
158 let name = to_snake_case(&original_name);
159
160 let ty = match sir.field {
161 Sir::Boolean => Type::Boolean,
162 Sir::Float => Type::Float,
163 Sir::Double => Type::Double,
164 Sir::I64(ref examples) => {
165 format_comment(&mut comment, examples)?;
166 Type::Signed { size: 64 }
167 }
168 Sir::U64(ref examples) => {
169 format_comment(&mut comment, examples)?;
170 Type::Unsigned { size: 64 }
171 }
172 Sir::String(ref examples) => {
173 format_comment(&mut comment, examples)?;
174 Type::String
175 }
176 Sir::DateTime(ref examples) => {
177 format_comment(&mut comment, examples)?;
178 Type::DateTime
179 }
180 Sir::Any => Type::Any,
181 Sir::Array(ref inner) => {
182 let field = FieldSir {
183 optional: false,
184 field: (**inner).clone(),
185 };
186
187 let f = FieldInit::new(&self.span, self.ctx.clone(), self.types).init(
188 name.clone(),
189 &field,
190 members,
191 )?;
192
193 Type::Array {
194 inner: Box::new(f.item.ty.clone()),
195 }
196 }
197 ref sir => {
198 let ctx = self.ctx.join(to_pascal_case(&name));
199
200 let name = if let Some(name) = self.types.get(sir).cloned() {
201 name
202 } else {
203 let name = ctx.name();
204
205 self.types.insert(sir.clone(), name.clone());
206
207 let decl = DeclDeriver {
208 span: &self.span,
209 ctx: ctx.clone(),
210 types: self.types,
211 }.derive(sir)?;
212
213 members.push(TypeMember::InnerDecl(decl));
214
215 name
216 };
217
218 Type::Name {
219 name: Loc::new(name, Span::empty()),
220 }
221 }
222 };
223
224 let field_as = if name != original_name {
225 Some(original_name)
226 } else {
227 None
228 };
229
230 let field = Field {
231 required: !sir.optional,
232 name: name.clone().into(),
233 ty: Loc::new(ty.into(), self.span.clone()),
234 field_as: field_as,
235 endl: true,
236 };
237
238 return Ok(Item {
240 comment: comment,
241 attributes: Vec::new(),
242 item: Loc::new(field, self.span.clone()),
243 });
244
245 fn format_comment<T>(out: &mut Vec<Cow<'static, str>>, examples: &[T]) -> Result<()>
247 where
248 T: serde::Serialize + fmt::Debug,
249 {
250 out.push(format!("## Examples").into());
251 out.push("".to_string().into());
252
253 out.push(format!("```json").into());
254
255 let mut seen = HashSet::new();
256
257 for example in examples.iter() {
258 let string = serde_json::to_string_pretty(example)
259 .map_err(|e| format!("Failed to convert to JSON: {}: {:?}", e, example))?;
260
261 if !seen.contains(&string) {
262 seen.insert(string.clone());
263 out.push(string.into());
264 }
265 }
266
267 out.push(format!("```").into());
268
269 Ok(())
270 }
271 }
272}
273
274struct DeclDeriver<'a, 'input: 'a> {
275 span: &'a Span,
276 ctx: Context,
277 types: &'a mut TypesCache<'input>,
278}
279
280impl<'a, 'input: 'a> DeclDeriver<'a, 'input> {
281 fn derive<'s>(self, sir: &'s Sir) -> Result<Decl<'input>> {
283 let decl = match *sir {
284 Sir::Tuple(ref array) => {
285 let tuple = TupleRefiner {
286 span: &self.span,
287 ctx: self.ctx,
288 types: self.types,
289 }.derive(array)?;
290
291 Decl::Tuple(tuple)
292 }
293 Sir::Object(ref object) => {
294 let type_ = TypeRefiner {
295 span: &self.span,
296 ctx: self.ctx,
297 types: self.types,
298 }.derive(object)?;
299
300 Decl::Type(type_)
301 }
302 Sir::Interface(ref type_field, ref sub_types) => {
303 let interface = InterfaceRefiner {
304 span: &self.span,
305 ctx: self.ctx,
306 types: self.types,
307 }.derive(type_field, sub_types)?;
308
309 Decl::Interface(interface)
310 }
311 Sir::Array(ref inner) => self.derive(inner)?,
313 ref value => return Err(format!("Unexpected JSON value: {:?}", value).into()),
314 };
315
316 Ok(decl)
317 }
318}
319
320struct TypeRefiner<'a, 'input: 'a> {
321 span: &'a Span,
322 ctx: Context,
323 types: &'a mut TypesCache<'input>,
324}
325
326impl<'a, 'input: 'a> TypeRefiner<'a, 'input> {
327 fn derive(
329 &mut self,
330 object: &LinkedHashMap<String, FieldSir>,
331 ) -> Result<Item<'input, TypeBody<'input>>> {
332 let mut body = TypeBody {
333 name: Loc::new(self.ctx.ident()?.to_string().into(), Span::empty()),
334 members: Vec::new(),
335 };
336
337 self.init(&mut body, object)?;
338
339 Ok(Item {
340 comment: Vec::new(),
341 attributes: Vec::new(),
342 item: Loc::new(body, self.span.clone()),
343 })
344 }
345
346 fn init(
347 &mut self,
348 base: &mut TypeBody<'input>,
349 object: &LinkedHashMap<String, FieldSir>,
350 ) -> Result<()> {
351 for (name, added) in object.iter() {
352 let field = FieldInit::new(&self.span, self.ctx.clone(), self.types).init(
353 name.to_string(),
354 added,
355 &mut base.members,
356 )?;
357
358 base.members.push(TypeMember::Field(field));
359 }
360
361 Ok(())
362 }
363}
364
365struct SubTypeRefiner<'a, 'input: 'a> {
366 span: &'a Span,
367 ctx: Context,
368 types: &'a mut TypesCache<'input>,
369}
370
371impl<'a, 'input: 'a> SubTypeRefiner<'a, 'input> {
372 fn derive(&mut self, sub_type: &SubTypeSir) -> Result<Item<'input, SubType<'input>>> {
374 let mut body = SubType {
375 name: Loc::new(self.ctx.ident()?.to_string().into(), self.span.clone()),
376 members: vec![],
377 alias: None,
378 };
379
380 self.init(&mut body, sub_type)?;
381
382 Ok(Item {
383 comment: Vec::new(),
384 attributes: Vec::new(),
385 item: Loc::new(body, self.span.clone()),
386 })
387 }
388
389 fn init(&mut self, base: &mut SubType<'input>, sub_type: &SubTypeSir) -> Result<()> {
390 if sub_type.name.as_str() != base.name.as_ref() {
391 base.alias = Some(Loc::new(
392 Value::String(sub_type.name.to_string()),
393 self.span.clone(),
394 ));
395 }
396
397 for (field_name, field_value) in &sub_type.structure {
398 let field = FieldInit::new(&self.span, self.ctx.clone(), self.types).init(
399 field_name.to_string(),
400 field_value,
401 &mut base.members,
402 )?;
403
404 base.members.push(TypeMember::Field(field));
405 }
406
407 Ok(())
408 }
409}
410
411struct InterfaceRefiner<'a, 'input: 'a> {
412 span: &'a Span,
413 ctx: Context,
414 types: &'a mut TypesCache<'input>,
415}
416
417impl<'a, 'input: 'a> InterfaceRefiner<'a, 'input> {
418 fn derive(
420 &mut self,
421 tag: &str,
422 sub_types: &[SubTypeSir],
423 ) -> Result<Item<'input, InterfaceBody<'input>>> {
424 let mut attributes = Vec::new();
425
426 if tag != DEFAULT_TAG {
427 let name = Loc::new("type_info".into(), self.span.clone());
428 let mut values = Vec::new();
429
430 values.push(AttributeItem::NameValue {
431 name: Loc::new("type".into(), self.span.clone()),
432 value: Loc::new(Value::String("type".to_string()), self.span.clone()),
433 });
434
435 let a = Attribute::List(name, values);
436
437 attributes.push(Loc::new(a, self.span.clone()));
438 };
439
440 let mut body = InterfaceBody {
441 name: Loc::new(self.ctx.ident()?.to_string().into(), Span::empty()),
442 members: Vec::new(),
443 sub_types: Vec::new(),
444 };
445
446 self.init(&mut body, sub_types)?;
447
448 Ok(Item {
449 comment: Vec::new(),
450 attributes: attributes,
451 item: Loc::new(body, self.span.clone()),
452 })
453 }
454
455 fn init(&mut self, base: &mut InterfaceBody<'input>, sub_types: &[SubTypeSir]) -> Result<()> {
456 for st in sub_types {
457 let ident = to_pascal_case(&st.name);
458 let ctx = self.ctx.join(ident.clone());
459
460 let sub_type = SubTypeRefiner {
461 span: self.span,
462 ctx: ctx,
463 types: self.types,
464 }.derive(st)?;
465
466 base.sub_types.push(sub_type);
467 }
468
469 Ok(())
470 }
471}
472
473struct TupleRefiner<'a, 'input: 'a> {
474 span: &'a Span,
475 ctx: Context,
476 types: &'a mut TypesCache<'input>,
477}
478
479impl<'a, 'input: 'a> TupleRefiner<'a, 'input> {
480 fn derive(&mut self, array: &[FieldSir]) -> Result<Item<'input, TupleBody<'input>>> {
482 let mut body = TupleBody {
483 name: Loc::new(self.ctx.ident()?.to_string().into(), Span::empty()),
484 members: Vec::new(),
485 };
486
487 self.init(&mut body, array)?;
488
489 Ok(Item {
490 comment: Vec::new(),
491 attributes: Vec::new(),
492 item: Loc::new(body, self.span.clone()),
493 })
494 }
495
496 fn init(&mut self, base: &mut TupleBody<'input>, array: &[FieldSir]) -> Result<()> {
497 for (index, added) in array.iter().enumerate() {
498 let field = FieldInit::new(&self.span, self.ctx.clone(), self.types).init(
499 format!("field_{}", index),
500 added,
501 &mut base.members,
502 )?;
503
504 base.members.push(TypeMember::Field(field));
505 }
506
507 Ok(())
508 }
509}
510
511pub fn derive<'input>(derive: Derive, object: &'input Source) -> Result<Decl<'input>> {
513 let Derive {
514 root_name,
515 format,
516 package_prefix,
517 } = derive;
518
519 let sir = format.decode(object)?;
520
521 let span = Span::empty();
522
523 let mut types = HashMap::new();
524
525 let ctx = Context {
526 path: vec![root_name],
527 package_prefix: package_prefix.as_ref().map(|p| Rc::new(p.clone())),
528 };
529
530 let decl = DeclDeriver {
531 span: &span,
532 ctx: ctx,
533 types: &mut types,
534 }.derive(&sir)?;
535
536 Ok(decl)
537}
538
539#[cfg(test)]
540mod tests {
541 use super::{derive, Derive, Json};
542 use ast::Decl;
543 use core::Source;
544
545 fn input<T>(input: &str, test: T)
546 where
547 T: Fn(Decl) -> (),
548 {
549 let source = Source::bytes("test", input.as_bytes().iter().cloned().collect());
550
551 let derive_config = Derive {
552 root_name: "Generator".to_string(),
553 format: Box::new(Json),
554 package_prefix: None,
555 };
556
557 test(derive(derive_config, &source).expect("bad derive"))
558 }
559
560 #[test]
561 fn simple_declaration() {
562 input(r#"{"id": 42, "name": "Oscar"}"#, |decl| {
563 let ty = match decl {
564 Decl::Type(ty) => ty,
565 other => panic!("expected type, got: {:?}", other),
566 };
567
568 assert_eq!(2, ty.members.len());
569 });
570 }
571
572 #[test]
573 fn test_interface() {
574 input(
575 r#"[
576 {"kind": "dragon", "name": "Stephen", "age": 4812, "fire": "blue"},
577 {"kind": "knight", "name": "Olivia", "armor": "Unobtanium"}
578]"#,
579 |decl| {
580 let intf = match decl {
581 Decl::Interface(intf) => intf,
582 other => panic!("expected interface, got: {:?}", other),
583 };
584
585 assert_eq!(2, intf.sub_types.len());
586 },
587 );
588 }
589}