1use super::*;
2
3fn conv(name: &str) -> String {
4 name.replace("Int32", "Int")
5 .replace("Int64", "Long")
6 .replace("Float32", "Single")
7 .replace("Float64", "Double")
8 .replace("Params", "Parameters")
9}
10
11pub struct Generator {
12 main_namespace: String,
13 files: Vec<File>,
14}
15
16fn type_name(schema: &Schema) -> String {
17 format!("{}{}", type_name_prearray(schema), type_post_array(schema))
18}
19
20fn type_name_prearray(schema: &Schema) -> String {
21 match schema {
22 Schema::Bool => "bool".to_owned(),
23 Schema::Int32 => "int".to_owned(),
24 Schema::Int64 => "long".to_owned(),
25 Schema::Float32 => "single".to_owned(),
26 Schema::Float64 => "double".to_owned(),
27 Schema::String => "string".to_owned(),
28 Schema::Struct(Struct { name, .. })
29 | Schema::OneOf {
30 base_name: name, ..
31 }
32 | Schema::Enum {
33 base_name: name, ..
34 } => format!("{}", name.camel_case(conv)),
35 Schema::Option(inner) => format!("option<{}>", type_name(inner)),
36 Schema::Vec(inner) => type_name_prearray(inner),
37 Schema::Map(key, value) => format!("Map<{}, {}>", type_name(key), type_name(value)),
38 }
39}
40
41fn type_post_array(schema: &Schema) -> String {
42 match schema {
43 Schema::Vec(inner) => format!("[]{}", type_post_array(inner)),
44 _ => String::new(),
45 }
46}
47
48fn var_name(name: &str) -> &str {
49 match name.rfind('.') {
50 Some(index) => &name[(index + 1)..],
51 None => name,
52 }
53}
54
55fn write_struct(
56 writer: &mut Writer,
57 struc: &Struct,
58 base: Option<(&Name, usize)>,
59) -> std::fmt::Result {
60 let struc_name = if let Some((base, _)) = base {
61 format!("{}{}", base.camel_case(conv), struc.name.camel_case(conv))
62 } else {
63 struc.name.camel_case(conv)
64 };
65
66 if struc.fields.is_empty() {
67 writeln!(writer, "type {} = struct end with", struc_name)?;
68 writer.inc_ident();
69 } else {
70 writeln!(writer, "type {} = {{", struc_name)?;
71 writer.inc_ident();
72 for field in &struc.fields {
73 writeln!(
74 writer,
75 "{}: {};",
76 field.name.camel_case(conv),
77 type_name(&field.schema),
78 )?;
79 }
80 writeln!(writer, "}} with")?;
81 }
82
83 writeln!(
85 writer,
86 "member this.writeTo(writer: System.IO.BinaryWriter) ="
87 )?;
88 writer.inc_ident();
89 if let Some((_, tag)) = base {
90 writeln!(writer, "writer.Write {}", tag)?;
91 }
92 if let Some(magic) = struc.magic {
93 writeln!(writer, "writer.Write {}", magic)?;
94 }
95 for field in &struc.fields {
96 fn write(writer: &mut Writer, value: &str, schema: &Schema) -> std::fmt::Result {
97 match schema {
98 Schema::Bool => {
99 writeln!(writer, "writer.Write {}", value)?;
100 }
101 Schema::Int32 => {
102 writeln!(writer, "writer.Write {}", value)?;
103 }
104 Schema::Int64 => {
105 writeln!(writer, "writer.Write {}", value)?;
106 }
107 Schema::Float32 => {
108 writeln!(writer, "writer.Write {}", value)?;
109 }
110 Schema::Float64 => {
111 writeln!(writer, "writer.Write {}", value)?;
112 }
113 Schema::String => {
114 let data_var = format!("{}Data", var_name(value));
115 writeln!(
116 writer,
117 "let {} : byte[] = System.Text.Encoding.UTF8.GetBytes {}",
118 data_var, value
119 )?;
120 writeln!(writer, "writer.Write {}.Length", data_var)?;
121 writeln!(writer, "writer.Write {}", data_var)?;
122 }
123 Schema::Struct(_) | Schema::OneOf { .. } => {
124 writeln!(writer, "{}.writeTo writer", value)?;
125 }
126 Schema::Option(inner) => {
127 writeln!(writer, "match {} with", value)?;
128 writer.inc_ident();
129 writeln!(writer, "| Some value ->")?;
130 writer.inc_ident();
131 writeln!(writer, "writer.Write true")?;
132 write(writer, "value", inner)?;
133 writer.dec_ident();
134 writeln!(writer, "| None -> writer.Write false")?;
135 writer.dec_ident();
136 }
137 Schema::Vec(inner) => {
138 writeln!(writer, "writer.Write {}.Length", value)?;
139 writeln!(writer, "{} |> Array.iter (fun value ->", value)?;
140 writer.inc_ident();
141 write(writer, "value", inner)?;
142 writer.dec_ident();
143 writeln!(writer, ")")?;
144 }
145 Schema::Map(key_type, value_type) => {
146 writeln!(writer, "writer.Write {}.Count", value)?;
147 writeln!(writer, "{} |> Map.iter (fun key value ->", value)?;
148 writer.inc_ident();
149 write(writer, "key", key_type)?;
150 write(writer, "value", value_type)?;
151 writer.dec_ident();
152 writeln!(writer, ")")?;
153 }
154 Schema::Enum { .. } => {
155 writeln!(writer, "writer.Write (int {})", value)?;
156 }
157 }
158 Ok(())
159 }
160 write(
161 writer,
162 &format!("this.{}", field.name.camel_case(conv)),
163 &field.schema,
164 )?;
165 }
166 writer.dec_ident();
167
168 if struc.fields.is_empty() {
170 writeln!(
171 writer,
172 "static member readFrom(reader: System.IO.BinaryReader) = new {}()",
173 struc_name,
174 )?;
175 } else {
176 writeln!(
177 writer,
178 "static member readFrom(reader: System.IO.BinaryReader) = {{"
179 )?;
180 writer.inc_ident();
181 for field in &struc.fields {
182 fn read(writer: &mut Writer, schema: &Schema) -> std::fmt::Result {
183 match schema {
184 Schema::Bool => {
185 writeln!(writer, "reader.ReadBoolean()")?;
186 }
187 Schema::Int32 => {
188 writeln!(writer, "reader.ReadInt32()")?;
189 }
190 Schema::Int64 => {
191 writeln!(writer, "reader.ReadInt64()")?;
192 }
193 Schema::Float32 => {
194 writeln!(writer, "reader.ReadSingle()")?;
195 }
196 Schema::Float64 => {
197 writeln!(writer, "reader.ReadDouble()")?;
198 }
199 Schema::String => {
200 writeln!(writer, "reader.ReadInt32() |> reader.ReadBytes |> System.Text.Encoding.UTF8.GetString")?;
201 }
202 Schema::Struct(Struct { name, .. })
203 | Schema::OneOf {
204 base_name: name, ..
205 } => {
206 writeln!(writer, "{}.readFrom reader", name.camel_case(conv))?;
207 }
208 Schema::Option(inner) => {
209 writeln!(writer, "match reader.ReadBoolean() with")?;
210 writer.inc_ident();
211 writeln!(writer, "| true ->")?;
212 writer.inc_ident();
213 writeln!(writer, "Some(")?;
214 writer.inc_ident();
215 read(writer, inner)?;
216 writeln!(writer, ")")?;
217 writer.dec_ident();
218 writer.dec_ident();
219 writeln!(writer, "| false -> None")?;
220 writer.dec_ident();
221 }
222 Schema::Vec(inner) => {
223 writeln!(writer, "[|for _ in 1 .. reader.ReadInt32() do")?;
224 writer.inc_ident();
225 write!(writer, "yield ")?;
226 read(writer, inner)?;
227 writer.dec_ident();
228 writeln!(writer, "|]")?;
229 }
230 Schema::Map(key_type, value_type) => {
231 writeln!(writer, "[for _ in 1 .. reader.ReadInt32() do")?;
232 writer.inc_ident();
233 write!(writer, "let key = ")?;
234 read(writer, key_type)?;
235 write!(writer, "let value = ")?;
236 read(writer, value_type)?;
237 writeln!(writer, "yield (key, value)")?;
238 writeln!(writer, "] |> Map.ofList")?;
239 writer.dec_ident();
240 }
241 Schema::Enum { .. } => {
242 writeln!(writer, "reader.ReadInt32() |> enum")?;
243 }
244 }
245 Ok(())
246 }
247 write!(writer, "{} = ", field.name.camel_case(conv))?;
248 read(writer, &field.schema)?;
249 }
250 writer.dec_ident();
251 writeln!(writer, "}}")?;
252 }
253
254 writer.dec_ident();
255
256 Ok(())
257}
258
259impl crate::Generator for Generator {
260 type Options = ();
261 fn new(name: &str, _version: &str, _: ()) -> Self {
262 Self {
263 main_namespace: Name::new(name.to_owned()).camel_case(conv),
264 files: Vec::new(),
265 }
266 }
267 fn result(self) -> GenResult {
268 self.files.into()
269 }
270 fn add_only(&mut self, schema: &Schema) {
271 match schema {
272 Schema::Enum {
273 documentation: _,
274 base_name,
275 variants,
276 } => {
277 let file_name = format!("Model/{}.fs", base_name.camel_case(conv));
278 let mut writer = Writer::new();
279 writeln!(writer, "#nowarn \"0058\"").unwrap();
280 writeln!(writer, "namespace {}.Model", self.main_namespace).unwrap();
281 writeln!(writer, "type {} =", base_name.camel_case(conv)).unwrap();
282 writer.inc_ident();
283 for (tag, variant) in variants.iter().enumerate() {
284 writeln!(writer, "| {} = {}", variant.name.camel_case(conv), tag).unwrap();
285 }
286 writer.dec_ident();
287 self.files.push(File {
288 path: file_name,
289 content: writer.get(),
290 });
291 }
292 Schema::Struct(struc) => {
293 let file_name = format!("Model/{}.fs", struc.name.camel_case(conv));
294 let mut writer = Writer::new();
295 writeln!(writer, "#nowarn \"0058\"").unwrap();
296 writeln!(writer, "namespace {}.Model", self.main_namespace).unwrap();
297 write_struct(&mut writer, struc, None).unwrap();
298 self.files.push(File {
299 path: file_name,
300 content: writer.get(),
301 });
302 }
303 Schema::OneOf {
304 documentation: _,
305 base_name,
306 variants,
307 } => {
308 let file_name = format!("Model/{}.fs", base_name.camel_case(conv));
309 let mut writer = Writer::new();
310 writeln!(writer, "#nowarn \"0058\"").unwrap();
311 writeln!(writer, "namespace {}.Model", self.main_namespace).unwrap();
312
313 for (tag, variant) in variants.iter().enumerate() {
314 writeln!(&mut writer).unwrap();
315 write_struct(&mut writer, variant, Some((base_name, tag))).unwrap();
316 }
317
318 writeln!(&mut writer, "type {} = ", base_name.camel_case(conv)).unwrap();
319 writer.inc_ident();
320 for variant in variants {
321 writeln!(
322 writer,
323 "| {} of {}{}",
324 variant.name.camel_case(conv),
325 base_name.camel_case(conv),
326 variant.name.camel_case(conv)
327 )
328 .unwrap();
329 }
330 writeln!(writer, "with").unwrap();
331
332 writeln!(
333 writer,
334 "member this.writeTo(writer: System.IO.BinaryWriter) ="
335 )
336 .unwrap();
337 writer.inc_ident();
338 writeln!(writer, "match this with").unwrap();
339 writer.inc_ident();
340 for variant in variants {
341 writeln!(
342 writer,
343 "| {} value -> value.writeTo writer",
344 variant.name.camel_case(conv),
345 )
346 .unwrap();
347 }
348 writer.dec_ident();
349 writer.dec_ident();
350
351 writeln!(
352 writer,
353 "static member readFrom(reader: System.IO.BinaryReader) ="
354 )
355 .unwrap();
356 writer.inc_ident();
357 writeln!(writer, "match reader.ReadInt32() with").unwrap();
358 writer.inc_ident();
359 for (tag, variant) in variants.iter().enumerate() {
360 writeln!(
361 writer,
362 "| {} -> {} ({}{}.readFrom reader)",
363 tag,
364 variant.name.camel_case(conv),
365 base_name.camel_case(conv),
366 variant.name.camel_case(conv),
367 )
368 .unwrap();
369 }
370 writeln!(writer, "| x -> failwith (sprintf \"Unexpected tag %d\" x)").unwrap();
371 writer.dec_ident();
372 writer.dec_ident();
373
374 writer.dec_ident();
375 self.files.push(File {
376 path: file_name,
377 content: writer.get(),
378 });
379 }
380 Schema::Bool
381 | Schema::Int32
382 | Schema::Int64
383 | Schema::Float32
384 | Schema::Float64
385 | Schema::String
386 | Schema::Option(_)
387 | Schema::Vec(_)
388 | Schema::Map(_, _) => {}
389 }
390 }
391}