1pub use trans;
2
3use serde::{Deserialize, Serialize};
4use std::collections::{HashMap, HashSet};
5use std::fmt::Write;
6use std::path::Path;
7use trans::*;
8
9pub mod gens;
10
11#[derive(Debug)]
12pub struct File {
13 pub path: String,
14 pub content: String,
15}
16
17#[derive(Debug)]
18pub struct GenResult {
19 pub files: Vec<File>,
20}
21
22impl GenResult {
23 pub fn write_to<P: AsRef<Path>>(&self, target_dir: P) -> std::io::Result<()> {
24 let target_dir = target_dir.as_ref();
25 for file in &self.files {
26 if let Some(parent) = Path::new(&file.path).parent() {
27 std::fs::create_dir_all(target_dir.join(parent))?;
28 }
29 use std::io::Write;
30 std::fs::File::create(target_dir.join(&file.path))?
31 .write_all(file.content.as_bytes())?;
32 }
33 Ok(())
34 }
35}
36
37impl From<HashMap<String, String>> for GenResult {
38 fn from(file_map: HashMap<String, String>) -> Self {
39 Self {
40 files: file_map
41 .into_iter()
42 .map(|(path, content)| File { path, content })
43 .collect(),
44 }
45 }
46}
47
48impl From<Vec<File>> for GenResult {
49 fn from(files: Vec<File>) -> Self {
50 Self { files }
51 }
52}
53
54pub trait Generator {
55 type Options: Default;
56 fn new(name: &str, version: &str, options: Self::Options) -> Self;
57 fn add_only(&mut self, schema: &trans::Schema);
58 fn result(self) -> GenResult;
59}
60
61pub struct GeneratorImpl<T: Generator> {
62 inner: T,
63 added: HashMap<trans::Name, trans::Schema>,
64}
65
66impl<T: Generator> GeneratorImpl<T> {
67 pub fn new(name: &str, version: &str, options: T::Options) -> Self {
68 Self {
69 inner: T::new(name, version, options),
70 added: HashMap::new(),
71 }
72 }
73 pub fn add(&mut self, schema: &Schema) {
74 let schema_name = schema.full_name();
75 let current = self.added.get(&schema_name);
76 if let Some(current) = current {
77 assert_eq!(
78 current, schema,
79 "Two schemas with same name but different structure"
80 );
81 return;
82 }
83 self.added.insert(schema_name, schema.clone());
84 match schema {
85 Schema::Struct(Struct { fields, .. }) => {
86 for field in fields {
87 self.add(&field.schema);
88 }
89 }
90 Schema::OneOf { variants, .. } => {
91 for variant in variants {
92 for field in &variant.fields {
93 self.add(&field.schema);
94 }
95 }
96 }
97 Schema::Option(inner) => {
98 self.add(inner);
99 }
100 Schema::Vec(inner) => {
101 self.add(inner);
102 }
103 Schema::Map(key_type, value_type) => {
104 self.add(key_type);
105 self.add(value_type);
106 }
107 Schema::Bool
108 | Schema::Int32
109 | Schema::Int64
110 | Schema::Float32
111 | Schema::Float64
112 | Schema::String
113 | Schema::Enum { .. } => {}
114 }
115 self.inner.add_only(schema);
116 }
117 pub fn result(self) -> GenResult {
118 self.inner.result()
119 }
120}
121
122pub struct Writer {
123 content: String,
124 ident_level: usize,
125}
126
127impl Writer {
128 pub fn new() -> Self {
129 Self {
130 content: String::new(),
131 ident_level: 0,
132 }
133 }
134 pub fn inc_ident(&mut self) {
135 self.ident_level += 1;
136 }
137 pub fn dec_ident(&mut self) {
138 self.ident_level -= 1;
139 }
140 pub fn get(self) -> String {
141 assert_eq!(self.ident_level, 0, "Incorrect indentation");
142 self.content
143 }
144}
145
146impl std::fmt::Write for Writer {
147 fn write_str(&mut self, s: &str) -> std::fmt::Result {
148 for c in s.chars() {
149 if c != '\n' && self.content.chars().last().unwrap_or('\n') == '\n' {
150 for _ in 0..self.ident_level * 4 {
151 self.content.push(' ');
152 }
153 }
154 self.content.push(c);
155 }
156 Ok(())
157 }
158}