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