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 model_init: String,
12 files: HashMap<String, String>,
13}
14
15fn write_struct(
16 writer: &mut Writer,
17 struc: &Struct,
18 base: Option<(&Name, usize)>,
19) -> std::fmt::Result {
20 for field in &struc.fields {
22 fn add_imports(writer: &mut Writer, schema: &Schema) -> std::fmt::Result {
23 match schema {
24 Schema::Struct(Struct { name, .. })
25 | Schema::OneOf {
26 base_name: name, ..
27 }
28 | Schema::Enum {
29 base_name: name, ..
30 } => {
31 writeln!(
32 writer,
33 "from .{} import {}",
34 name.snake_case(conv),
35 name.camel_case(conv)
36 )?;
37 }
38 Schema::Option(inner) => {
39 add_imports(writer, inner)?;
40 }
41 Schema::Vec(inner) => {
42 add_imports(writer, inner)?;
43 }
44 Schema::Map(key_type, value_type) => {
45 add_imports(writer, key_type)?;
46 add_imports(writer, value_type)?;
47 }
48 Schema::Bool
49 | Schema::Int32
50 | Schema::Int64
51 | Schema::Float32
52 | Schema::Float64
53 | Schema::String => {}
54 }
55 Ok(())
56 }
57 add_imports(writer, &field.schema)?;
58 }
59
60 write!(writer, "class {}", struc.name.camel_case(conv))?;
62 if let Some((base_name, _)) = base {
63 write!(writer, "({})", base_name.camel_case(conv))?;
64 }
65 writeln!(writer, ":")?;
66 writer.inc_ident();
67 if let Some((_, tag)) = base {
68 writeln!(writer, "TAG = {}", tag)?;
69 }
70
71 write!(writer, "def __init__(self")?;
73 for field in &struc.fields {
74 write!(writer, ", {}", field.name.snake_case(conv))?;
75 }
76 writeln!(writer, "):")?;
77 for field in &struc.fields {
78 writeln!(
79 writer,
80 " self.{} = {}",
81 field.name.snake_case(conv),
82 field.name.snake_case(conv)
83 )?;
84 }
85 if struc.fields.is_empty() {
86 writeln!(writer, " pass")?;
87 }
88
89 writeln!(writer, "@staticmethod")?;
91 writeln!(writer, "def read_from(stream):")?;
92 writer.inc_ident();
93 for field in &struc.fields {
94 fn assign(writer: &mut Writer, to: &str, schema: &Schema) -> std::fmt::Result {
95 match schema {
96 Schema::Bool => {
97 writeln!(writer, "{} = stream.read_bool()", to)?;
98 }
99 Schema::Int32 => {
100 writeln!(writer, "{} = stream.read_int()", to)?;
101 }
102 Schema::Int64 => {
103 writeln!(writer, "{} = stream.read_long()", to)?;
104 }
105 Schema::Float32 => {
106 writeln!(writer, "{} = stream.read_float()", to)?;
107 }
108 Schema::Float64 => {
109 writeln!(writer, "{} = stream.read_double()", to)?;
110 }
111 Schema::String => {
112 writeln!(writer, "{} = stream.read_string()", to)?;
113 }
114 Schema::Struct(Struct { name, .. })
115 | Schema::OneOf {
116 base_name: name, ..
117 } => {
118 writeln!(
119 writer,
120 "{} = {}.read_from(stream)",
121 to,
122 name.camel_case(conv)
123 )?;
124 }
125 Schema::Option(inner) => {
126 writeln!(writer, "if stream.read_bool():")?;
127 writer.inc_ident();
128 assign(writer, to, inner)?;
129 writer.dec_ident();
130 writeln!(writer, "else:")?;
131 writeln!(writer, " {} = None", to)?;
132 }
133 Schema::Vec(inner) => {
134 writeln!(writer, "{} = []", to)?;
135 writeln!(writer, "for _ in range(stream.read_int()):")?;
136 writer.inc_ident();
137 assign(writer, &format!("{}_element", to), inner)?;
138 writeln!(writer, "{}.append({}_element)", to, to)?;
139 writer.dec_ident();
140 }
141 Schema::Map(key_type, value_type) => {
142 writeln!(writer, "{} = {{}}", to)?;
143 writeln!(writer, "for _ in range(stream.read_int()):")?;
144 writer.inc_ident();
145 assign(writer, &format!("{}_key", to), key_type)?;
146 assign(writer, &format!("{}_value", to), value_type)?;
147 writeln!(writer, "{}[{}_key] = {}_value", to, to, to)?;
148 writer.dec_ident();
149 }
150 Schema::Enum { base_name, .. } => {
151 writeln!(
152 writer,
153 "{} = {}(stream.read_int())",
154 to,
155 base_name.camel_case(conv)
156 )?;
157 }
158 }
159 Ok(())
160 }
161 assign(writer, &field.name.snake_case(conv), &field.schema)?;
162 }
163 write!(writer, "return {}(", struc.name.camel_case(conv))?;
164 let mut first = true;
165 for field in &struc.fields {
166 if first {
167 first = false;
168 } else {
169 write!(writer, ", ")?;
170 }
171 write!(writer, "{}", field.name.snake_case(conv))?;
172 }
173 writeln!(writer, ")")?;
174 writer.dec_ident();
175
176 writeln!(writer, "def write_to(self, stream):")?;
178 writer.inc_ident();
179 if base.is_some() {
180 writeln!(writer, "stream.write_int(self.TAG)")?;
181 } else if struc.fields.is_empty() && struc.magic.is_none() {
182 writeln!(writer, "pass")?;
183 }
184 if let Some(magic) = struc.magic {
185 writeln!(writer, "stream.write_int({})", magic)?;
186 }
187 for field in &struc.fields {
188 fn write(writer: &mut Writer, value: &str, schema: &Schema) -> std::fmt::Result {
189 match schema {
190 Schema::Bool => {
191 writeln!(writer, "stream.write_bool({})", value)?;
192 }
193 Schema::Int32 => {
194 writeln!(writer, "stream.write_int({})", value)?;
195 }
196 Schema::Int64 => {
197 writeln!(writer, "stream.write_long({})", value)?;
198 }
199 Schema::Float32 => {
200 writeln!(writer, "stream.write_float({})", value)?;
201 }
202 Schema::Float64 => {
203 writeln!(writer, "stream.write_double({})", value)?;
204 }
205 Schema::String => {
206 writeln!(writer, "stream.write_string({})", value)?;
207 }
208 Schema::Struct(_) | Schema::OneOf { .. } => {
209 writeln!(writer, "{}.write_to(stream)", value)?;
210 }
211 Schema::Option(inner) => {
212 writeln!(writer, "if {} is None:", value)?;
213 writeln!(writer, " stream.write_bool(False)")?;
214 writeln!(writer, "else:")?;
215 writer.inc_ident();
216 writeln!(writer, "stream.write_bool(True)")?;
217 write(writer, value, inner)?;
218 writer.dec_ident();
219 }
220 Schema::Vec(inner) => {
221 writeln!(writer, "stream.write_int(len({}))", value)?;
222 writeln!(writer, "for element in {}:", value)?;
223 writer.inc_ident();
224 write(writer, "element", inner)?;
225 writer.dec_ident();
226 }
227 Schema::Map(key_type, value_type) => {
228 writeln!(writer, "stream.write_int(len({}))", value)?;
229 writeln!(writer, "for key, value in {}.items():", value)?;
230 writer.inc_ident();
231 write(writer, "key", key_type)?;
232 write(writer, "value", value_type)?;
233 writer.dec_ident();
234 }
235 Schema::Enum { .. } => {
236 writeln!(writer, "stream.write_int({})", value)?;
237 }
238 }
239 Ok(())
240 }
241 write(
242 writer,
243 &format!("self.{}", field.name.snake_case(conv)),
244 &field.schema,
245 )?;
246 }
247 writer.dec_ident();
248
249 writeln!(writer, "def __repr__(self):")?;
251 writer.inc_ident();
252 writeln!(writer, "return \"{}(\" + \\", struc.name.camel_case(conv))?;
253 for (index, field) in struc.fields.iter().enumerate() {
254 write!(writer, " repr(self.{})", field.name.snake_case(conv))?;
255 if index + 1 < struc.fields.len() {
256 write!(writer, " + \",\"")?;
257 }
258 writeln!(writer, " + \\")?;
259 }
260 writeln!(writer, " \")\"")?;
261 writer.dec_ident();
262
263 writer.dec_ident();
264
265 if let Some((base_name, _)) = base {
266 writeln!(
267 writer,
268 "{}.{} = {}",
269 base_name.camel_case(conv),
270 struc.name.camel_case(conv),
271 struc.name.camel_case(conv)
272 )?;
273 }
274
275 Ok(())
276}
277
278impl crate::Generator for Generator {
279 type Options = ();
280 fn new(_name: &str, _version: &str, _: ()) -> Self {
281 let mut files = HashMap::new();
282 files.insert(
283 "stream_wrapper.py".to_owned(),
284 include_str!("stream_wrapper.py").to_owned(),
285 );
286 Self {
287 model_init: String::new(),
288 files,
289 }
290 }
291 fn result(mut self) -> GenResult {
292 if !self.model_init.is_empty() {
293 self.files
294 .insert("model/__init__.py".to_owned(), self.model_init);
295 }
296 self.files.into()
297 }
298 fn add_only(&mut self, schema: &Schema) {
299 match schema {
300 Schema::Enum {
301 documentation: _,
302 base_name,
303 variants,
304 } => {
305 let file_name = format!("model/{}.py", base_name.snake_case(conv));
306 let mut writer = Writer::new();
307 writeln!(writer, "from enum import IntEnum").unwrap();
308 writeln!(writer).unwrap();
309 writeln!(writer, "class {}(IntEnum):", base_name.camel_case(conv)).unwrap();
310 writer.inc_ident();
311 for (index, variant) in variants.iter().enumerate() {
312 writeln!(
313 writer,
314 "{} = {}",
315 variant.name.shouty_snake_case(conv),
316 index
317 )
318 .unwrap();
319 }
320 writer.dec_ident();
321 writeln!(
322 &mut self.model_init,
323 "from .{} import {}",
324 base_name.snake_case(conv),
325 base_name.camel_case(conv),
326 )
327 .unwrap();
328 self.files.insert(file_name, writer.get());
329 }
330 Schema::Struct(struc) => {
331 let file_name = format!("model/{}.py", struc.name.snake_case(conv));
332 let mut writer = Writer::new();
333 write_struct(&mut writer, struc, None).unwrap();
334 writeln!(
335 &mut self.model_init,
336 "from .{} import {}",
337 struc.name.snake_case(conv),
338 struc.name.camel_case(conv)
339 )
340 .unwrap();
341 self.files.insert(file_name, writer.get());
342 }
343 Schema::OneOf {
344 documentation: _,
345 base_name,
346 variants,
347 } => {
348 let file_name = format!("model/{}.py", base_name.snake_case(conv));
349 let mut writer = Writer::new();
350 writeln!(&mut writer, "class {}:", base_name.camel_case(conv)).unwrap();
351 {
352 writer.inc_ident();
353 writeln!(&mut writer, "@staticmethod").unwrap();
354 writeln!(&mut writer, "def read_from(stream):").unwrap();
355 {
356 writer.inc_ident();
357 writeln!(&mut writer, "tag = stream.read_int()").unwrap();
358 for variant in variants {
359 writeln!(
360 &mut writer,
361 "if tag == {}.TAG:",
362 variant.name.camel_case(conv)
363 )
364 .unwrap();
365 writeln!(
366 &mut writer,
367 " return {}.{}.read_from(stream)",
368 base_name.camel_case(conv),
369 variant.name.camel_case(conv),
370 )
371 .unwrap();
372 }
373 writeln!(&mut writer, "raise Exception(\"Unexpected tag value\")").unwrap();
374 writer.dec_ident();
375 }
376 writer.dec_ident();
377 }
378 writeln!(&mut writer).unwrap();
379 for (tag, variant) in variants.iter().enumerate() {
380 write_struct(&mut writer, variant, Some((base_name, tag))).unwrap();
381 }
382 writeln!(
383 &mut self.model_init,
384 "from .{} import {}",
385 base_name.snake_case(conv),
386 base_name.camel_case(conv)
387 )
388 .unwrap();
389 self.files.insert(file_name, writer.get());
390 }
391 Schema::Bool
392 | Schema::Int32
393 | Schema::Int64
394 | Schema::Float32
395 | Schema::Float64
396 | Schema::String
397 | Schema::Option(_)
398 | Schema::Vec(_)
399 | Schema::Map(_, _) => {}
400 }
401 }
402}