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