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