1use super::*;
2
3fn conv(name: &str) -> String {
4 name.replace("Int32", "Int")
5 .replace("Int64", "Long")
6 .replace("Float32", "Float")
7 .replace("Float64", "Double")
8 .replace("Params", "Parameters")
9}
10
11pub struct Generator {
12 model_init: String,
13 files: HashMap<String, String>,
14}
15
16fn type_name(schema: &Schema) -> String {
17 match schema {
18 Schema::Bool => "bool".to_owned(),
19 Schema::Int32 => "int".to_owned(),
20 Schema::Int64 => "long".to_owned(),
21 Schema::Float32 => "float".to_owned(),
22 Schema::Float64 => "double".to_owned(),
23 Schema::String => "string".to_owned(),
24 Schema::Struct(Struct { name, .. })
25 | Schema::OneOf {
26 base_name: name, ..
27 }
28 | Schema::Enum {
29 base_name: name, ..
30 } => name.camel_case(conv),
31 Schema::Option(inner) => format!("Nullable!({})", type_name(inner)),
32 Schema::Vec(inner) => format!("{}[]", type_name(inner)),
33 Schema::Map(key, value) => format!("{}[{}]", type_name(value), type_name(key),),
34 }
35}
36
37fn index_var_name(index_var: &mut usize) -> String {
38 let result = "ijk".chars().nth(*index_var).unwrap();
39 *index_var += 1;
40 result.to_string()
41}
42
43fn var_name(name: &str) -> &str {
44 match name.rfind('.') {
45 Some(index) => &name[(index + 1)..],
46 None => name,
47 }
48}
49
50fn write_struct(
51 writer: &mut Writer,
52 struc: &Struct,
53 base: Option<(&Name, usize)>,
54) -> std::fmt::Result {
55 if let Some((base_name, _)) = base {
57 writeln!(
58 writer,
59 "static class {} : {} {{",
60 struc.name.camel_case(conv),
61 base_name.camel_case(conv)
62 )?;
63 } else {
64 writeln!(writer, "struct {} {{", struc.name.camel_case(conv))?;
65 }
66 writer.inc_ident();
67 if let Some((_, tag)) = base {
68 writeln!(writer, "static const int TAG = {};", tag)?;
69 }
70
71 for field in &struc.fields {
73 writeln!(
74 writer,
75 "{} {};",
76 type_name(&field.schema),
77 field.name.mixed_case(conv)
78 )?;
79 }
80
81 if base.is_some() {
83 writeln!(writer, "this() {{}}")?;
84 }
85 if !struc.fields.is_empty() {
86 write!(writer, "this(")?;
87 for (index, field) in struc.fields.iter().enumerate() {
88 if index > 0 {
89 write!(writer, ", ")?;
90 }
91 write!(
92 writer,
93 "{} {}",
94 type_name(&field.schema),
95 field.name.mixed_case(conv)
96 )?;
97 }
98 writeln!(writer, ") {{")?;
99 for field in &struc.fields {
100 writeln!(
101 writer,
102 " this.{} = {};",
103 field.name.mixed_case(conv),
104 field.name.mixed_case(conv)
105 )?;
106 }
107 writeln!(writer, "}}")?;
108 }
109
110 writeln!(
112 writer,
113 "static {} readFrom(Stream reader) {{",
114 struc.name.camel_case(conv)
115 )?;
116 writer.inc_ident();
117 writeln!(
118 writer,
119 "auto result = {}{}();",
120 if base.is_some() { "new " } else { "" },
121 struc.name.camel_case(conv)
122 )?;
123 for field in &struc.fields {
124 fn assign(
125 writer: &mut Writer,
126 to: &str,
127 schema: &Schema,
128 index_var: &mut usize,
129 ) -> std::fmt::Result {
130 match schema {
131 Schema::Bool => {
132 writeln!(writer, "{} = reader.readBool();", to)?;
133 }
134 Schema::Int32 => {
135 writeln!(writer, "{} = reader.readInt();", to)?;
136 }
137 Schema::Int64 => {
138 writeln!(writer, "{} = reader.readLong();", to)?;
139 }
140 Schema::Float32 => {
141 writeln!(writer, "{} = reader.readFloat();", to)?;
142 }
143 Schema::Float64 => {
144 writeln!(writer, "{} = reader.readDouble();", to)?;
145 }
146 Schema::String => {
147 writeln!(writer, "{} = reader.readString();", to)?;
148 }
149 Schema::Struct(Struct { name, .. })
150 | Schema::OneOf {
151 base_name: name, ..
152 } => {
153 writeln!(
154 writer,
155 "{} = {}.readFrom(reader);",
156 to,
157 name.camel_case(conv)
158 )?;
159 }
160 Schema::Option(inner) => {
161 writeln!(writer, "if (reader.readBool()) {{")?;
162 writer.inc_ident();
163 assign(writer, to, inner, index_var)?;
164 writer.dec_ident();
165 writeln!(writer, "}} else {{")?;
166 writeln!(writer, " {}.nullify();", to)?;
167 writeln!(writer, "}}")?;
168 }
169 Schema::Vec(inner) => {
170 writeln!(
171 writer,
172 "{} = new {}[reader.readInt()];",
173 to,
174 type_name(inner),
175 )?;
176 let index_var_name = index_var_name(index_var);
177 writeln!(
178 writer,
179 "for (int {} = 0; {} < {}.length; {}++) {{",
180 index_var_name, index_var_name, to, index_var_name
181 )?;
182 writer.inc_ident();
183 assign(
184 writer,
185 &format!("{}[{}]", to, index_var_name),
186 inner,
187 index_var,
188 )?;
189 writer.dec_ident();
190 writeln!(writer, "}}")?;
191 }
192 Schema::Map(key_type, value_type) => {
193 let to_size = format!("{}Size", var_name(to));
194 writeln!(writer, "int {} = reader.readInt();", to_size)?;
195 writeln!(writer, "{}.clear();", to)?;
196 let index_var_name = index_var_name(index_var);
197 writeln!(
198 writer,
199 "for (int {} = 0; {} < {}; {}++) {{",
200 index_var_name, index_var_name, to_size, index_var_name
201 )?;
202 writer.inc_ident();
203 writeln!(writer, "{} {}Key;", type_name(key_type), var_name(to))?;
204 assign(writer, &format!("{}Key", var_name(to)), key_type, index_var)?;
205 writeln!(writer, "{} {}Value;", type_name(value_type), var_name(to))?;
206 assign(
207 writer,
208 &format!("{}Value", var_name(to)),
209 value_type,
210 index_var,
211 )?;
212 writeln!(
213 writer,
214 "{}[{}Key] = {}Value;",
215 to,
216 var_name(to),
217 var_name(to)
218 )?;
219 writer.dec_ident();
220 writeln!(writer, "}}")?;
221 }
222 Schema::Enum {
223 documentation: _,
224 base_name,
225 variants,
226 } => {
227 writeln!(writer, "switch (reader.readInt()) {{")?;
228 for (tag, variant) in variants.iter().enumerate() {
229 writeln!(writer, "case {}:", tag)?;
230 writeln!(
231 writer,
232 " {} = {}.{};",
233 to,
234 base_name.camel_case(conv),
235 variant.name.camel_case(conv)
236 )?;
237 writeln!(writer, " break;")?;
238 }
239 writeln!(writer, "default:")?;
240 writeln!(writer, " throw new Exception(\"Unexpected tag value\");")?;
241 writeln!(writer, "}}")?;
242 }
243 }
244 Ok(())
245 }
246 assign(
247 writer,
248 &format!("result.{}", field.name.mixed_case(conv)),
249 &field.schema,
250 &mut 0,
251 )?;
252 }
253 writeln!(writer, "return result;")?;
254 writer.dec_ident();
255 writeln!(writer, "}}")?;
256
257 writeln!(
259 writer,
260 "{}void writeTo(Stream writer) const {{",
261 if base.is_some() { "override " } else { "" }
262 )?;
263 writer.inc_ident();
264 if base.is_some() {
265 writeln!(writer, "writer.write(TAG);")?;
266 }
267 if let Some(magic) = struc.magic {
268 writeln!(writer, "writer.write({});", magic)?;
269 }
270 for field in &struc.fields {
271 fn write(writer: &mut Writer, value: &str, schema: &Schema) -> std::fmt::Result {
272 match schema {
273 Schema::Bool => {
274 writeln!(writer, "writer.write({});", value)?;
275 }
276 Schema::Int32 => {
277 writeln!(writer, "writer.write({});", value)?;
278 }
279 Schema::Int64 => {
280 writeln!(writer, "writer.write({});", value)?;
281 }
282 Schema::Float32 => {
283 writeln!(writer, "writer.write({});", value)?;
284 }
285 Schema::Float64 => {
286 writeln!(writer, "writer.write({});", value)?;
287 }
288 Schema::String => {
289 writeln!(writer, "writer.write({});", value)?;
290 }
291 Schema::Struct(_) | Schema::OneOf { .. } => {
292 writeln!(writer, "{}.writeTo(writer);", value)?;
293 }
294 Schema::Option(inner) => {
295 writeln!(writer, "if ({}.isNull()) {{", value)?;
296 writeln!(writer, " writer.write(false);")?;
297 writeln!(writer, "}} else {{")?;
298 writer.inc_ident();
299 writeln!(writer, "writer.write(true);")?;
300 write(writer, &format!("{}.get", value), inner)?;
301 writer.dec_ident();
302 writeln!(writer, "}}")?;
303 }
304 Schema::Vec(inner) => {
305 writeln!(writer, "writer.write(cast(int)({}.length));", value)?;
306 writeln!(writer, "foreach ({}Element; {}) {{", var_name(value), value)?;
307 writer.inc_ident();
308 write(writer, &format!("{}Element", var_name(value)), inner)?;
309 writer.dec_ident();
310 writeln!(writer, "}}")?;
311 }
312 Schema::Map(key_type, value_type) => {
313 writeln!(writer, "writer.write(cast(int)({}.length));", value)?;
314 writeln!(
315 writer,
316 "foreach ({}Key, {}Value; {}) {{",
317 var_name(value),
318 var_name(value),
319 value
320 )?;
321 writer.inc_ident();
322 write(writer, &format!("{}Key", var_name(value)), key_type)?;
323 write(writer, &format!("{}Value", var_name(value)), value_type)?;
324 writer.dec_ident();
325 writeln!(writer, "}}")?;
326 }
327 Schema::Enum { .. } => {
328 writeln!(writer, "writer.write(cast(int)({}));", value)?;
329 }
330 }
331 Ok(())
332 }
333 write(writer, &field.name.mixed_case(conv), &field.schema)?;
334 }
335 writer.dec_ident();
336 writeln!(writer, "}}")?;
337
338 writeln!(
340 writer,
341 "{}string toString() const {{",
342 if base.is_some() { "override " } else { "" }
343 )?;
344 writer.inc_ident();
345 writeln!(writer, "return {:?} ~ \"(\" ~", struc.name.camel_case(conv))?;
346 writer.inc_ident();
347 for field in &struc.fields {
348 writeln!(writer, "to!string({}) ~", field.name.mixed_case(conv))?;
349 }
350 writeln!(writer, "\")\";")?;
351 writer.dec_ident();
352 writer.dec_ident();
353 writeln!(writer, "}}")?;
354
355 writer.dec_ident();
356 writeln!(writer, "}}")?;
357 Ok(())
358}
359
360impl crate::Generator for Generator {
361 type Options = ();
362 fn new(_name: &str, _version: &str, _: ()) -> Self {
363 let mut files = HashMap::new();
364 files.insert("stream.d".to_owned(), include_str!("stream.d").to_owned());
365 Self {
366 model_init: String::new(),
367 files,
368 }
369 }
370 fn result(mut self) -> GenResult {
371 if !self.model_init.is_empty() {
372 self.files
373 .insert("model/package.d".to_owned(), self.model_init);
374 }
375 self.files.into()
376 }
377 fn add_only(&mut self, schema: &Schema) {
378 match schema {
379 Schema::Enum {
380 documentation: _,
381 base_name,
382 variants,
383 } => {
384 let file_name = format!("model/{}.d", base_name.snake_case(conv));
385 let mut writer = Writer::new();
386 writeln!(writer, "enum {} : int {{", base_name.camel_case(conv)).unwrap();
387 writer.inc_ident();
388 for (tag, variant) in variants.iter().enumerate() {
389 writeln!(writer, "{} = {},", variant.name.camel_case(conv), tag,).unwrap();
390 }
391 writer.dec_ident();
392 writeln!(writer, "}}").unwrap();
393 self.files.insert(file_name, writer.get());
394 writeln!(
395 &mut self.model_init,
396 "public import {};",
397 base_name.snake_case(conv),
398 )
399 .unwrap();
400 }
401 Schema::Struct(struc) => {
402 let file_name = format!("model/{}.d", struc.name.snake_case(conv));
403 let mut writer = Writer::new();
404 writeln!(writer, "import model;").unwrap();
405 writeln!(writer, "import stream;").unwrap();
406 writeln!(writer, "import std.conv;").unwrap();
407 writeln!(writer, "import std.typecons : Nullable;").unwrap();
408 writeln!(writer).unwrap();
409 write_struct(&mut writer, struc, None).unwrap();
410 self.files.insert(file_name, writer.get());
411 writeln!(
412 &mut self.model_init,
413 "public import {};",
414 struc.name.snake_case(conv),
415 )
416 .unwrap();
417 }
418 Schema::OneOf {
419 documentation: _,
420 base_name,
421 variants,
422 } => {
423 let file_name = format!("model/{}.d", base_name.snake_case(conv));
424 let mut writer = Writer::new();
425 writeln!(writer, "import model;").unwrap();
426 writeln!(writer, "import stream;").unwrap();
427 writeln!(writer, "import std.conv;").unwrap();
428 writeln!(writer, "import std.typecons : Nullable;").unwrap();
429 writeln!(writer).unwrap();
430 writeln!(
431 &mut writer,
432 "abstract class {} {{",
433 base_name.camel_case(conv)
434 )
435 .unwrap();
436 {
437 writer.inc_ident();
438 writeln!(&mut writer, "abstract void writeTo(Stream writer) const;").unwrap();
439 writeln!(
440 &mut writer,
441 "static {} readFrom(Stream reader) {{",
442 base_name.camel_case(conv)
443 )
444 .unwrap();
445 {
446 writer.inc_ident();
447 writeln!(&mut writer, "switch (reader.readInt()) {{").unwrap();
448 writer.inc_ident();
449 for variant in variants {
450 writeln!(&mut writer, "case {}.TAG:", variant.name.camel_case(conv))
451 .unwrap();
452 writeln!(
453 &mut writer,
454 " return {}.readFrom(reader);",
455 variant.name.camel_case(conv)
456 )
457 .unwrap();
458 }
459 writeln!(&mut writer, "default:").unwrap();
460 writeln!(
461 &mut writer,
462 " throw new Exception(\"Unexpected tag value\");"
463 )
464 .unwrap();
465 writer.dec_ident();
466 writeln!(&mut writer, "}}").unwrap();
467 writer.dec_ident();
468 }
469 writeln!(&mut writer, "}}").unwrap();
470 for (tag, variant) in variants.iter().enumerate() {
471 writeln!(&mut writer).unwrap();
472 write_struct(&mut writer, variant, Some((base_name, tag))).unwrap();
473 }
474 writer.dec_ident();
475 }
476 writeln!(&mut writer, "}}").unwrap();
477 self.files.insert(file_name, writer.get());
478 writeln!(
479 &mut self.model_init,
480 "public import {};",
481 base_name.snake_case(conv),
482 )
483 .unwrap();
484 }
485 Schema::Bool
486 | Schema::Int32
487 | Schema::Int64
488 | Schema::Float32
489 | Schema::Float64
490 | Schema::String
491 | Schema::Option(_)
492 | Schema::Vec(_)
493 | Schema::Map(_, _) => {}
494 }
495 }
496}