@arrirpc/codegen-rust 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1988 @@
1
+ 'use strict';
2
+
3
+ const node_child_process = require('node:child_process');
4
+ const fs = require('node:fs');
5
+ const codegenUtils = require('@arrirpc/codegen-utils');
6
+ const path = require('pathe');
7
+ const assert = require('assert');
8
+
9
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
10
+
11
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
12
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
13
+ const assert__default = /*#__PURE__*/_interopDefaultCompat(assert);
14
+
15
+ const reservedKeywords = [
16
+ "as",
17
+ "break",
18
+ "const",
19
+ "continue",
20
+ "crate",
21
+ "else",
22
+ "enum",
23
+ "extern",
24
+ "false",
25
+ "fn",
26
+ "for",
27
+ "if",
28
+ "impl",
29
+ "in",
30
+ "let",
31
+ "loop",
32
+ "match",
33
+ "mod",
34
+ "move",
35
+ "mut",
36
+ "pub",
37
+ "ref",
38
+ "return",
39
+ "self",
40
+ "Self",
41
+ "static",
42
+ "struct",
43
+ "super",
44
+ "trait",
45
+ "true",
46
+ "type",
47
+ "unsafe",
48
+ "use",
49
+ "where",
50
+ "while",
51
+ "async",
52
+ "await",
53
+ "dyn",
54
+ "abstract",
55
+ "become",
56
+ "box",
57
+ "do",
58
+ "final",
59
+ "macro",
60
+ "override",
61
+ "priv",
62
+ "typeof",
63
+ "unsized",
64
+ "virtual",
65
+ "yield",
66
+ "try",
67
+ "macro_rules",
68
+ "union",
69
+ "'static",
70
+ "dyn"
71
+ ];
72
+ const illegalChars = `.!@#$%^&*()-+=\\][{}'";?`;
73
+ const numberChars = "0123456789";
74
+ function validRustIdentifier(key) {
75
+ const output = codegenUtils.removeDisallowedChars(codegenUtils.snakeCase(key), illegalChars);
76
+ if (numberChars.includes(output.charAt(0))) {
77
+ return `r#_${output}`;
78
+ }
79
+ if (reservedKeywords.includes(output)) {
80
+ return `r#${output}`;
81
+ }
82
+ return output;
83
+ }
84
+ function validRustName(name) {
85
+ const output = codegenUtils.removeDisallowedChars(
86
+ codegenUtils.pascalCase(name, { normalize: true }),
87
+ illegalChars
88
+ );
89
+ if (numberChars.includes(output.charAt(0))) {
90
+ return `r#_${output}`;
91
+ }
92
+ if (reservedKeywords.includes(output)) {
93
+ return `r#${output}`;
94
+ }
95
+ return output;
96
+ }
97
+ path__default.resolve(__dirname, "../.temp");
98
+ function outputIsOptionType(schema, context) {
99
+ return schema.nullable === true || context.isOptional === true;
100
+ }
101
+ function getTypeName(schema, context) {
102
+ if (schema.metadata?.id) {
103
+ return validRustName(schema.metadata.id);
104
+ }
105
+ if (context.discriminatorKey && context.discriminatorValue) {
106
+ const parts = context.instancePath.split("/");
107
+ const name = validRustName(
108
+ `${parts.join("_")}_${context.discriminatorValue}`
109
+ );
110
+ return name;
111
+ }
112
+ return validRustName(context.instancePath.split("/").join("_"));
113
+ }
114
+ function formatDescriptionComment(description, leading = "") {
115
+ return description.split("\n").map((line) => `${leading}/// ${line}`).join("\n");
116
+ }
117
+
118
+ function rustAnyFromSchema(schema, context) {
119
+ return {
120
+ typeName: context.isOptional ? `Option<serde_json::Value>` : "serde_json::Value",
121
+ defaultValue: context.isOptional ? `None` : `serde_json::Value::Null`,
122
+ isNullable: false,
123
+ fromJsonTemplate(input, key) {
124
+ const innerKey = validRustIdentifier(`${key}_val`);
125
+ if (context.isOptional) {
126
+ return `match ${input} {
127
+ Some(${innerKey}) => Some(${innerKey}.to_owned()),
128
+ _ => None,
129
+ }`;
130
+ }
131
+ return `match ${input} {
132
+ Some(${innerKey}) => ${innerKey}.to_owned(),
133
+ _ => serde_json::Value::Null,
134
+ }`;
135
+ },
136
+ toJsonTemplate(input, target) {
137
+ return `${target}.push_str(
138
+ serde_json::to_string(${input})
139
+ .unwrap_or("null".to_string())
140
+ .as_str(),
141
+ )`;
142
+ },
143
+ toQueryStringTemplate() {
144
+ return `println!("[WARNING] cannot serialize any's to query params. Skipping field at ${context.instancePath}.")`;
145
+ },
146
+ content: ""
147
+ };
148
+ }
149
+
150
+ function rustArrayFromSchema(schema, context) {
151
+ const innerType = rustTypeFromSchema(schema.elements, {
152
+ instancePath: `${context.instancePath}/element`,
153
+ schemaPath: `${context.schemaPath}/elements`,
154
+ clientVersion: context.clientVersion,
155
+ clientName: context.clientName,
156
+ typeNamePrefix: context.typeNamePrefix,
157
+ generatedTypes: context.generatedTypes
158
+ });
159
+ const isOptionType = outputIsOptionType(schema, context);
160
+ const typeName = isOptionType ? `Option<Vec<${innerType.typeName}>>` : `Vec<${innerType.typeName}>`;
161
+ const defaultValue = isOptionType ? `None` : `Vec::new()`;
162
+ return {
163
+ typeName,
164
+ defaultValue,
165
+ isNullable: schema.nullable ?? false,
166
+ fromJsonTemplate(input, key) {
167
+ const innerKey = validRustIdentifier(`${key}_val`);
168
+ if (isOptionType) {
169
+ return `match ${input} {
170
+ Some(serde_json::Value::Array(${innerKey})) => {
171
+ let mut ${innerKey}_result: Vec<${innerType.typeName}> = Vec::new();
172
+ for ${innerKey}_element in ${innerKey} {
173
+ ${innerKey}_result.push(${innerType.fromJsonTemplate(`Some(${innerKey}_element)`, `${innerKey}_element`)});
174
+ }
175
+ Some(${innerKey}_result)
176
+ }
177
+ _ => None,
178
+ }`;
179
+ }
180
+ return `match ${input} {
181
+ Some(serde_json::Value::Array(${innerKey})) => {
182
+ let mut ${innerKey}_result: Vec<${innerType.typeName}> = Vec::new();
183
+ for ${innerKey}_element in ${innerKey} {
184
+ ${innerKey}_result.push(${innerType.fromJsonTemplate(`Some(${innerKey}_element)`, `${innerKey}_element`)});
185
+ }
186
+ ${innerKey}_result
187
+ }
188
+ _ => Vec::new(),
189
+ }`;
190
+ },
191
+ toJsonTemplate(input, target) {
192
+ let innerTypeToJson = innerType.toJsonTemplate(`_element_`, target);
193
+ if (innerType.isNullable) {
194
+ innerTypeToJson = `match _element_ {
195
+ Some(_element_val_) => {
196
+ ${innerType.toJsonTemplate(`_element_val_`, target)};
197
+ },
198
+ _ => {
199
+ ${target}.push_str("null");
200
+ }
201
+ }`;
202
+ }
203
+ return `${target}.push('[');
204
+ for (_index_, _element_) in ${input}.iter().enumerate() {
205
+ if _index_ != 0 {
206
+ ${target}.push(',');
207
+ }
208
+ ${innerTypeToJson};
209
+ }
210
+ ${target}.push(']')`;
211
+ },
212
+ toQueryStringTemplate() {
213
+ return `println!("[WARNING] cannot serialize arrays to query params. Skipping field at ${context.instancePath}.")`;
214
+ },
215
+ content: innerType.content
216
+ };
217
+ }
218
+
219
+ function rustTaggedUnionFromSchema(schema, context) {
220
+ const enumName = `${context.typeNamePrefix}${getTypeName(schema, context)}`;
221
+ const isOptionType = outputIsOptionType(schema, context);
222
+ const defaultValue = isOptionType ? "None" : `${enumName}::new()`;
223
+ const result = {
224
+ typeName: isOptionType ? `Option<${enumName}>` : enumName,
225
+ defaultValue,
226
+ isNullable: isOptionType,
227
+ fromJsonTemplate(input, key) {
228
+ const innerKey = validRustIdentifier(`${key}_val`);
229
+ if (isOptionType) {
230
+ return `match ${input} {
231
+ Some(${innerKey}) => match ${innerKey} {
232
+ serde_json::Value::Object(_) => {
233
+ Some(${enumName}::from_json(${innerKey}.to_owned()))
234
+ }
235
+ _ => None,
236
+ },
237
+ _ => None,
238
+ }`;
239
+ }
240
+ return `match ${input} {
241
+ Some(${innerKey}) => match ${innerKey} {
242
+ serde_json::Value::Object(_) => {
243
+ ${enumName}::from_json(${innerKey}.to_owned())
244
+ }
245
+ _ => ${enumName}::new(),
246
+ },
247
+ _ => ${enumName}::new(),
248
+ }`;
249
+ },
250
+ toJsonTemplate(input, target) {
251
+ return `${target}.push_str(${input}.to_json_string().as_str())`;
252
+ },
253
+ toQueryStringTemplate() {
254
+ return `println!("[WARNING] cannot serialize nested objects to query params. Skipping field at ${context.instancePath}.")`;
255
+ },
256
+ content: ""
257
+ };
258
+ if (context.generatedTypes.includes(enumName)) {
259
+ return result;
260
+ }
261
+ const discriminatorKey = schema.discriminator;
262
+ const discriminatorValues = Object.keys(schema.mapping);
263
+ if (discriminatorValues.length === 0)
264
+ throw new Error(
265
+ `Discriminator schemas must have at least one subtype. Issue at ${context.schemaPath}.`
266
+ );
267
+ const subTypes = [];
268
+ const subTypeContent = [];
269
+ const discriminatorKeyProperty = validRustIdentifier(discriminatorKey);
270
+ const fromJsonParts = [];
271
+ for (const discriminatorValue of discriminatorValues) {
272
+ const subTypeName = validRustName(discriminatorValue);
273
+ const subSchema = schema.mapping[discriminatorValue];
274
+ const subType = {
275
+ name: subTypeName,
276
+ properties: [],
277
+ toJsonParts: [],
278
+ toQueryParts: [],
279
+ isDeprecated: subSchema.metadata?.isDeprecated ?? false,
280
+ description: subSchema.metadata?.description ?? ""
281
+ };
282
+ fromJsonParts.push(`"${discriminatorValue}" => {`);
283
+ subType.toJsonParts.push(
284
+ ` _json_output_.push_str("\\"${discriminatorKey}\\":\\"${discriminatorValue}\\"");`
285
+ );
286
+ subType.toQueryParts.push(
287
+ `_query_parts_.push(format!("${discriminatorKey}=${discriminatorValue}"));`
288
+ );
289
+ for (const key of Object.keys(subSchema.properties)) {
290
+ const keySchema = subSchema.properties[key];
291
+ const keyType = rustTypeFromSchema(keySchema, {
292
+ clientVersion: context.clientVersion,
293
+ clientName: context.clientName,
294
+ typeNamePrefix: context.typeNamePrefix,
295
+ instancePath: `${context.instancePath}/${key}`,
296
+ schemaPath: `${context.schemaPath}/mapping/${key}`,
297
+ generatedTypes: context.generatedTypes,
298
+ discriminatorKey,
299
+ discriminatorValue
300
+ });
301
+ if (keyType.content)
302
+ subTypeContent.push(keyType.content);
303
+ const keyName = validRustIdentifier(key);
304
+ subType.properties.push({
305
+ name: keyName,
306
+ defaultValue: keyType.defaultValue,
307
+ typeName: keyType.typeName,
308
+ isDeprecated: keySchema.metadata?.isDeprecated ?? false,
309
+ description: keySchema.metadata?.description ?? ""
310
+ });
311
+ fromJsonParts.push(
312
+ `let ${keyName} = ${keyType.fromJsonTemplate(`_val_.get("${key}")`, key)};`
313
+ );
314
+ subType.toJsonParts.push(
315
+ ` _json_output_.push_str(",\\"${key}\\":");`
316
+ );
317
+ if (keyType.isNullable) {
318
+ const innerKey = validRustIdentifier(`${key}_val`);
319
+ subType.toJsonParts.push(`match ${keyName} {
320
+ Some(${innerKey}) => {
321
+ ${keyType.toJsonTemplate(innerKey, "_json_output_")};
322
+ }
323
+ _ => {
324
+ _json_output_.push_str("null");
325
+ }
326
+ };`);
327
+ } else {
328
+ subType.toJsonParts.push(
329
+ `${keyType.toJsonTemplate(keyName, "_json_output_")};`
330
+ );
331
+ }
332
+ subType.toQueryParts.push(
333
+ `${keyType.toQueryStringTemplate(keyName, key, "_query_parts_")};`
334
+ );
335
+ }
336
+ for (const key of Object.keys(subSchema.optionalProperties ?? {})) {
337
+ const keySchema = subSchema.optionalProperties[key];
338
+ const keyType = rustTypeFromSchema(keySchema, {
339
+ clientVersion: context.clientVersion,
340
+ clientName: context.clientName,
341
+ typeNamePrefix: context.typeNamePrefix,
342
+ instancePath: `${context.instancePath}/key`,
343
+ schemaPath: `${context.schemaPath}/mapping/${key}`,
344
+ generatedTypes: context.generatedTypes,
345
+ discriminatorKey,
346
+ discriminatorValue
347
+ });
348
+ if (keyType.content)
349
+ subTypeContent.push(keyType.content);
350
+ const keyName = validRustIdentifier(key);
351
+ subType.properties.push({
352
+ name: keyName,
353
+ defaultValue: keyType.defaultValue,
354
+ typeName: keyType.typeName,
355
+ isDeprecated: keySchema.metadata?.isDeprecated ?? false,
356
+ description: keySchema.metadata?.description ?? ""
357
+ });
358
+ fromJsonParts.push(
359
+ `let ${keyName} = ${keyType.fromJsonTemplate(`_val_.get("${key}")`, key)};`
360
+ );
361
+ subType.toJsonParts.push(
362
+ ` _json_output_.push_str(",\\"${key}\\":");`
363
+ );
364
+ if (keyType.isNullable) {
365
+ const innerKey = validRustIdentifier(`${key}_val`);
366
+ subType.toJsonParts.push(`match ${keyName} {
367
+ Some(${innerKey}) => {
368
+ ${keyType.toJsonTemplate(innerKey, "_json_output_")};
369
+ }
370
+ _ => {
371
+ _json_output_.push_str("null");
372
+ }
373
+ };`);
374
+ } else {
375
+ subType.toJsonParts.push(
376
+ `${keyType.toJsonTemplate(keyName, "_json_output_")};`
377
+ );
378
+ }
379
+ }
380
+ fromJsonParts.push(`Self::${subTypeName} {
381
+ ${subType.properties.map((prop) => `${prop.name},`).join("\n")}
382
+ }`);
383
+ fromJsonParts.push(`}`);
384
+ subTypes.push(subType);
385
+ }
386
+ let leading = "";
387
+ if (schema.metadata?.description) {
388
+ leading += formatDescriptionComment(schema.metadata.description);
389
+ leading += "\n";
390
+ }
391
+ if (schema.metadata?.isDeprecated) {
392
+ leading += "#[deprecated]\n";
393
+ }
394
+ result.content = `${leading}#[derive(Clone, Debug, PartialEq)]
395
+ pub enum ${enumName} {
396
+ ${subTypes.map((type) => {
397
+ let leading2 = "";
398
+ if (type.description) {
399
+ leading2 += formatDescriptionComment(type.description);
400
+ leading2 += "\n";
401
+ }
402
+ if (type.isDeprecated) {
403
+ leading2 += "#[deprecated]\n";
404
+ }
405
+ return `${leading2}${type.name} {
406
+ ${type.properties.map((prop) => {
407
+ let leading3 = "";
408
+ if (prop.description) {
409
+ leading3 += formatDescriptionComment(prop.description);
410
+ leading3 += "\n";
411
+ }
412
+ if (prop.isDeprecated) {
413
+ leading3 += "#[deprecated]\n";
414
+ }
415
+ return `${leading3}${prop.name}: ${prop.typeName},`;
416
+ }).join("\n")}
417
+ },`;
418
+ }).join("\n")}
419
+ }
420
+
421
+ impl ArriModel for ${enumName} {
422
+ fn new() -> Self {
423
+ Self::${subTypes[0].name} {
424
+ ${subTypes[0]?.properties.map((prop) => `${prop.name}: ${prop.defaultValue},`).join("\n")}
425
+ }
426
+ }
427
+
428
+ fn from_json(input: serde_json::Value) -> Self {
429
+ match input {
430
+ serde_json::Value::Object(_val_) => {
431
+ let ${discriminatorKeyProperty} = match _val_.get("${discriminatorKey}") {
432
+ Some(serde_json::Value::String(${discriminatorKeyProperty}_val)) => ${discriminatorKeyProperty}_val.to_owned(),
433
+ _ => "".to_string(),
434
+ };
435
+ match ${discriminatorKeyProperty}.as_str() {
436
+ ${fromJsonParts.join("\n")}
437
+ _ => Self::new(),
438
+ }
439
+ }
440
+ _ => Self::new(),
441
+ }
442
+ }
443
+
444
+ fn from_json_string(input: String) -> Self {
445
+ match serde_json::from_str(input.as_str()) {
446
+ Ok(val) => Self::from_json(val),
447
+ _ => Self::new(),
448
+ }
449
+ }
450
+
451
+ fn to_json_string(&self) -> String {
452
+ let mut _json_output_ = "{".to_string();
453
+ match &self {
454
+ ${subTypes.map(
455
+ (type) => `Self::${type.name} { ${type.properties.map((prop) => `${prop.name},`).join("\n")}} => {
456
+ ${type.toJsonParts.join("\n")}
457
+ }`
458
+ )}
459
+ }
460
+ _json_output_.push('}');
461
+ _json_output_
462
+ }
463
+
464
+ fn to_query_params_string(&self) -> String {
465
+ let mut _query_parts_: Vec<String> = Vec::new();
466
+ match &self {
467
+ ${subTypes.map(
468
+ (type) => `Self::${type.name} { ${type.properties.map((prop) => `${prop.name},`).join("\n")}} => {
469
+ ${type.toQueryParts.join("\n")}
470
+ }`
471
+ )}
472
+ }
473
+ _query_parts_.join("&")
474
+ }
475
+ }
476
+
477
+ ${subTypeContent.join("\n\n")}`;
478
+ context.generatedTypes.push(enumName);
479
+ return result;
480
+ }
481
+
482
+ function rustEnumFromSchema(schema, context) {
483
+ const enumName = `${context.typeNamePrefix}${getTypeName(schema, context)}`;
484
+ const isOptionType = outputIsOptionType(schema, context);
485
+ const typeName = isOptionType ? `Option<${enumName}>` : enumName;
486
+ const defaultValue = isOptionType ? "None" : `${enumName}::default()`;
487
+ const result = {
488
+ typeName,
489
+ defaultValue,
490
+ isNullable: schema.nullable ?? false,
491
+ fromJsonTemplate(input, key) {
492
+ const innerKey = validRustIdentifier(`${key}_val`);
493
+ if (isOptionType) {
494
+ return `match ${input} {
495
+ Some(serde_json::Value::String(${innerKey})) => {
496
+ Some(${enumName}::from_string(${innerKey}.to_owned()))
497
+ }
498
+ _ => None,
499
+ }`;
500
+ }
501
+ return `match ${input} {
502
+ Some(serde_json::Value::String(${innerKey})) => {
503
+ ${enumName}::from_string(${innerKey}.to_owned())
504
+ }
505
+ _ => ${enumName}::default(),
506
+ }`;
507
+ },
508
+ toJsonTemplate(input, target) {
509
+ return `${target}.push_str(format!("\\"{}\\"", ${input}.serial_value()).as_str())`;
510
+ },
511
+ toQueryStringTemplate(input, key, target) {
512
+ const innerKey = validRustIdentifier(`${key}_val`);
513
+ if (context.isOptional) {
514
+ return `match ${input} {
515
+ Some(${innerKey}) => {
516
+ ${target}.push(format!("${key}={}", ${innerKey}.serial_value()));
517
+ }
518
+ _ => {}
519
+ }`;
520
+ }
521
+ if (schema.nullable) {
522
+ return `match ${input} {
523
+ Some(${innerKey}) => {
524
+ ${target}.push(format!("${key}={}", ${innerKey}.serial_value()));
525
+ }
526
+ _ => {
527
+ ${target}.push("${key}=null".to_string());
528
+ }
529
+ }`;
530
+ }
531
+ return `${target}.push(format!("${key}={}", ${input}.serial_value()))`;
532
+ },
533
+ content: ""
534
+ };
535
+ if (context.generatedTypes.includes(enumName)) {
536
+ return result;
537
+ }
538
+ let defaultEnumValue = "";
539
+ const initializationParts = [];
540
+ const fromStringParts = [];
541
+ const serialValueParts = [];
542
+ for (let i = 0; i < schema.enum.length; i++) {
543
+ const val = schema.enum[i];
544
+ const valName = validRustName(val);
545
+ if (i === 0) {
546
+ defaultEnumValue = valName;
547
+ }
548
+ initializationParts.push(` ${valName},`);
549
+ fromStringParts.push(` "${val}" => Self::${valName},`);
550
+ serialValueParts.push(
551
+ ` ${enumName}::${valName} => "${val}".to_string(),`
552
+ );
553
+ }
554
+ let leading = "";
555
+ if (schema.metadata?.description) {
556
+ leading += `${formatDescriptionComment(schema.metadata.description)}
557
+ `;
558
+ }
559
+ if (schema.metadata?.isDeprecated) {
560
+ leading += `#[deprecated]
561
+ `;
562
+ }
563
+ result.content = `${leading}#[derive(Clone, Debug, PartialEq)]
564
+ pub enum ${enumName} {
565
+ ${initializationParts.join("\n")}
566
+ }
567
+
568
+ impl ArriEnum for ${enumName} {
569
+ fn default() -> Self {
570
+ ${enumName}::${defaultEnumValue}
571
+ }
572
+ fn from_string(input: String) -> Self {
573
+ match input.as_str() {
574
+ ${fromStringParts.join("\n")}
575
+ _ => Self::default(),
576
+ }
577
+ }
578
+ fn serial_value(&self) -> String {
579
+ match &self {
580
+ ${serialValueParts.join("\n")}
581
+ }
582
+ }
583
+ }`;
584
+ context.generatedTypes.push(enumName);
585
+ return result;
586
+ }
587
+
588
+ function rustObjectFromSchema(schema, context) {
589
+ const isOptionType = outputIsOptionType(schema, context);
590
+ const structName = `${context.typeNamePrefix}${getTypeName(schema, context)}`;
591
+ const typeName = isOptionType ? `Option<${structName}>` : structName;
592
+ const defaultValue = isOptionType ? `None` : `${structName}::new()`;
593
+ const result = {
594
+ typeName,
595
+ defaultValue,
596
+ isNullable: schema.nullable ?? false,
597
+ fromJsonTemplate(input, key) {
598
+ const innerKey = validRustIdentifier(`${key}_val`);
599
+ if (isOptionType) {
600
+ return `match ${input} {
601
+ Some(${innerKey}) => match ${innerKey} {
602
+ serde_json::Value::Object(_) => {
603
+ Some(${structName}::from_json(${innerKey}.to_owned()))
604
+ }
605
+ _ => None,
606
+ },
607
+ _ => None,
608
+ }`;
609
+ }
610
+ return `match ${input} {
611
+ Some(${innerKey}) => ${structName}::from_json(${innerKey}.to_owned()),
612
+ _ => ${structName}::new(),
613
+ }`;
614
+ },
615
+ toJsonTemplate(input, target) {
616
+ return `${target}.push_str(${input}.to_json_string().as_str())`;
617
+ },
618
+ toQueryStringTemplate() {
619
+ return `println!("[WARNING] cannot serialize nested objects to query params. Skipping field at ${context.instancePath}.")`;
620
+ },
621
+ content: ""
622
+ };
623
+ if (context.generatedTypes.includes(structName)) {
624
+ return result;
625
+ }
626
+ const fieldNames = [];
627
+ const fieldDeclarationParts = [];
628
+ const defaultParts = [];
629
+ const fromJsonParts = [];
630
+ const toJsonParts = [];
631
+ const toQueryParamParams = [];
632
+ const subContent = [];
633
+ const requiredKeys = Object.keys(schema.properties);
634
+ const optionalKeys = Object.keys(schema.optionalProperties ?? {});
635
+ const hasKeys = requiredKeys.length > 0;
636
+ for (let i = 0; i < requiredKeys.length; i++) {
637
+ const key = requiredKeys[i];
638
+ const prop = schema.properties[key];
639
+ const innerType = rustTypeFromSchema(prop, {
640
+ clientVersion: context.clientVersion,
641
+ clientName: context.clientName,
642
+ typeNamePrefix: context.typeNamePrefix,
643
+ instancePath: `/${structName}/${key}`,
644
+ schemaPath: `${context.schemaPath}/properties/${key}`,
645
+ generatedTypes: context.generatedTypes
646
+ });
647
+ if (innerType.content) {
648
+ subContent.push(innerType.content);
649
+ }
650
+ const fieldName = validRustIdentifier(key);
651
+ fieldNames.push(fieldName);
652
+ let leading2 = "";
653
+ if (prop.metadata?.description) {
654
+ leading2 += formatDescriptionComment(prop.metadata.description);
655
+ leading2 += "\n";
656
+ }
657
+ if (prop.metadata?.isDeprecated) {
658
+ leading2 += ` #[deprecated]
659
+ `;
660
+ }
661
+ fieldDeclarationParts.push(
662
+ `${leading2} pub ${fieldName}: ${innerType.typeName}`
663
+ );
664
+ defaultParts.push(` ${fieldName}: ${innerType.defaultValue}`);
665
+ fromJsonParts.push(
666
+ ` let ${fieldName} = ${innerType.fromJsonTemplate(`_val_.get("${key}")`, key)};`
667
+ );
668
+ if (i === 0) {
669
+ toJsonParts.push(` _json_output_.push_str("\\"${key}\\":");`);
670
+ } else {
671
+ toJsonParts.push(` _json_output_.push_str(",\\"${key}\\":");`);
672
+ }
673
+ if (innerType.isNullable) {
674
+ const innerKey = validRustIdentifier(`${key}_val`);
675
+ toJsonParts.push(` match &self.${fieldName} {
676
+ Some(${innerKey}) => {
677
+ ${innerType.toJsonTemplate(innerKey, "_json_output_")};
678
+ }
679
+ _ => {
680
+ _json_output_.push_str("null");
681
+ }
682
+ };`);
683
+ } else {
684
+ const leading3 = codegenUtils.isSchemaFormElements(prop) || codegenUtils.isSchemaFormValues(prop) ? "" : "&";
685
+ toJsonParts.push(
686
+ ` ${innerType.toJsonTemplate(`${leading3}self.${fieldName}`, "_json_output_")};`
687
+ );
688
+ }
689
+ toQueryParamParams.push(
690
+ ` ${innerType.toQueryStringTemplate(`&self.${fieldName}`, key, "_query_parts_")};`
691
+ );
692
+ }
693
+ for (let i = 0; i < optionalKeys.length; i++) {
694
+ const key = optionalKeys[i];
695
+ const prop = schema.optionalProperties[key];
696
+ const innerType = rustTypeFromSchema(prop, {
697
+ clientVersion: context.clientVersion,
698
+ clientName: context.clientName,
699
+ typeNamePrefix: context.typeNamePrefix,
700
+ instancePath: `/${structName}/${key}`,
701
+ schemaPath: `${context.schemaPath}/optionalProperties/${key}`,
702
+ generatedTypes: context.generatedTypes,
703
+ isOptional: true
704
+ });
705
+ if (innerType.content) {
706
+ subContent.push(innerType.content);
707
+ }
708
+ const fieldName = validRustIdentifier(key);
709
+ fieldNames.push(fieldName);
710
+ let leading2 = prop.metadata?.description ? `${prop.metadata.description.split("\n").map((line) => ` /// ${line}`).join("\n")}
711
+ ` : "";
712
+ if (prop.metadata?.isDeprecated) {
713
+ leading2 += ` #[deprecated]
714
+ `;
715
+ }
716
+ fieldDeclarationParts.push(
717
+ `${leading2} pub ${fieldName}: ${innerType.typeName}`
718
+ );
719
+ defaultParts.push(` ${fieldName}: ${innerType.defaultValue}`);
720
+ fromJsonParts.push(
721
+ ` let ${fieldName} = ${innerType.fromJsonTemplate(`_val_.get("${key}")`, key)};`
722
+ );
723
+ if (hasKeys) {
724
+ const innerKey = validRustIdentifier(`${key}_val`);
725
+ toJsonParts.push(`match &self.${fieldName} {
726
+ Some(${innerKey}) => {
727
+ _json_output_.push_str(",\\"${key}\\":");
728
+ ${innerType.toJsonTemplate(innerKey, "_json_output_")}
729
+ },
730
+ _ => {}
731
+ };`);
732
+ } else {
733
+ const innerKey = validRustIdentifier(`${key}_val`);
734
+ toJsonParts.push(` match &self.${fieldName} {
735
+ Some(${innerKey}) => {
736
+ ${i !== 0 ? `if _has_keys_ {
737
+ _json_output_.push(',');
738
+ }` : ""}
739
+ _json_output_.push_str("\\"${key}\\":");
740
+ ${innerType.toJsonTemplate(innerKey, "_json_output_")};
741
+ ${i !== optionalKeys.length - 1 ? "_has_keys_ = true;" : ""}
742
+ }
743
+ _ => {}
744
+ };`);
745
+ }
746
+ toQueryParamParams.push(
747
+ ` ${innerType.toQueryStringTemplate(`&self.${fieldName}`, key, "_query_parts_")};`
748
+ );
749
+ }
750
+ context.generatedTypes.push(structName);
751
+ let selfDeclaration = `Self {
752
+ ${fieldNames.join(",\n ")},
753
+ }`;
754
+ if (fieldNames.length < 4) {
755
+ selfDeclaration = `Self { ${fieldNames.join(", ")} }`;
756
+ }
757
+ let leading = "";
758
+ if (schema.metadata?.description) {
759
+ leading += `${schema.metadata.description.split("\n").map((line) => `/// ${line}`).join("\n")}
760
+ `;
761
+ }
762
+ if (schema.metadata?.isDeprecated) {
763
+ leading += `#[deprecated]
764
+ `;
765
+ }
766
+ result.content = `${leading}#[derive(Clone, Debug, PartialEq)]
767
+ pub struct ${structName} {
768
+ ${fieldDeclarationParts.join(",\n")},
769
+ }
770
+
771
+ impl ArriModel for ${structName} {
772
+ fn new() -> Self {
773
+ Self {
774
+ ${defaultParts.join(",\n")},
775
+ }
776
+ }
777
+ fn from_json(input: serde_json::Value) -> Self {
778
+ match input {
779
+ serde_json::Value::Object(_val_) => {
780
+ ${fromJsonParts.join("\n")}
781
+ ${selfDeclaration}
782
+ }
783
+ _ => Self::new(),
784
+ }
785
+ }
786
+ fn from_json_string(input: String) -> Self {
787
+ match serde_json::from_str(input.as_str()) {
788
+ Ok(val) => Self::from_json(val),
789
+ _ => Self::new(),
790
+ }
791
+ }
792
+ fn to_json_string(&self) -> String {
793
+ let mut _json_output_ = "{".to_string();
794
+ ${!hasKeys ? `let mut _has_keys_ = false;` : ""}
795
+ ${toJsonParts.join("\n")}
796
+ _json_output_.push('}');
797
+ _json_output_
798
+ }
799
+ fn to_query_params_string(&self) -> String {
800
+ let mut _query_parts_: Vec<String> = Vec::new();
801
+ ${toQueryParamParams.join("\n")}
802
+ _query_parts_.join("&")
803
+ }
804
+ }
805
+
806
+ ${subContent.join("\n\n")}`;
807
+ return result;
808
+ }
809
+
810
+ function rustStringFromSchema(schema, context) {
811
+ const isOptionType = outputIsOptionType(schema, context);
812
+ const defaultValue = isOptionType ? "None" : '"".to_string()';
813
+ const typeName = isOptionType ? "Option<String>" : "String";
814
+ return {
815
+ typeName,
816
+ defaultValue,
817
+ isNullable: schema.nullable ?? false,
818
+ fromJsonTemplate(input, key) {
819
+ const innerKey = validRustIdentifier(`${key}_val`);
820
+ if (isOptionType) {
821
+ return `match ${input} {
822
+ Some(serde_json::Value::String(${innerKey})) => Some(${innerKey}.to_owned()),
823
+ _ => None,
824
+ }`;
825
+ }
826
+ return `match ${input} {
827
+ Some(serde_json::Value::String(${innerKey})) => ${innerKey}.to_owned(),
828
+ _ => "".to_string(),
829
+ }`;
830
+ },
831
+ toJsonTemplate(input, target) {
832
+ return `${target}.push_str(serialize_string(${input}).as_str())`;
833
+ },
834
+ toQueryStringTemplate(input, key, target) {
835
+ const innerKey = validRustIdentifier(`${key}_val`);
836
+ if (context.isOptional) {
837
+ return `match ${input} {
838
+ Some(${innerKey}) => {
839
+ ${target}.push(format!("${key}={}", ${innerKey}));
840
+ }
841
+ _ => {}
842
+ }`;
843
+ }
844
+ if (schema.nullable) {
845
+ return `match ${input} {
846
+ Some(${innerKey}) => {
847
+ ${target}.push(format!("${key}={}", ${innerKey}));
848
+ }
849
+ _ => {
850
+ ${target}.push("${key}=null".to_string());
851
+ }
852
+ }`;
853
+ }
854
+ return `${target}.push(format!("${key}={}", ${input}))`;
855
+ },
856
+ content: ""
857
+ };
858
+ }
859
+ function rustBooleanFromSchema(schema, context) {
860
+ const isOptionType = outputIsOptionType(schema, context);
861
+ const defaultValue = isOptionType ? "None" : "false";
862
+ const typeName = isOptionType ? "Option<bool>" : "bool";
863
+ return {
864
+ typeName,
865
+ defaultValue,
866
+ isNullable: schema.nullable ?? false,
867
+ fromJsonTemplate(input, key) {
868
+ const innerKey = validRustIdentifier(`${key}_val`);
869
+ if (isOptionType) {
870
+ return `match ${input} {
871
+ Some(serde_json::Value::Bool(${innerKey})) => Some(${innerKey}.to_owned()),
872
+ _ => None,
873
+ }`;
874
+ }
875
+ return `match ${input} {
876
+ Some(serde_json::Value::Bool(${innerKey})) => ${innerKey}.to_owned(),
877
+ _ => false,
878
+ }`;
879
+ },
880
+ toJsonTemplate(input, target) {
881
+ return `${target}.push_str(${input}.to_string().as_str())`;
882
+ },
883
+ toQueryStringTemplate(input, key, target) {
884
+ const innerKey = validRustIdentifier(`${key}_val`);
885
+ if (context.isOptional) {
886
+ return `match ${input} {
887
+ Some(${innerKey}) => {
888
+ ${target}.push(format!("${key}={}", ${innerKey}));
889
+ }
890
+ _ => {}
891
+ }`;
892
+ }
893
+ if (schema.nullable) {
894
+ return `match ${input} {
895
+ Some(${innerKey}) => {
896
+ ${target}.push(format!("${key}={}", ${innerKey}));
897
+ }
898
+ _ => {
899
+ ${target}.push("${key}=null".to_string());
900
+ }
901
+ }`;
902
+ }
903
+ return `${target}.push(format!("${key}={}", ${input}))`;
904
+ },
905
+ content: ""
906
+ };
907
+ }
908
+ function rustTimestampFromSchema(schema, context) {
909
+ const isOptionType = outputIsOptionType(schema, context);
910
+ const typeName = isOptionType ? "Option<DateTime<FixedOffset>>" : "DateTime<FixedOffset>";
911
+ const defaultValue = isOptionType ? "None" : "DateTime::default()";
912
+ return {
913
+ typeName,
914
+ defaultValue,
915
+ isNullable: schema.nullable ?? false,
916
+ fromJsonTemplate(input, key) {
917
+ const innerKey = validRustIdentifier(`${key}_val`);
918
+ if (isOptionType) {
919
+ return `match ${input} {
920
+ Some(serde_json::Value::String(${innerKey})) => {
921
+ match DateTime::<FixedOffset>::parse_from_rfc3339(${innerKey}) {
922
+ Ok(${innerKey}_result) => Some(${innerKey}_result),
923
+ Err(_) => None,
924
+ }
925
+ }
926
+ _ => None,
927
+ }`;
928
+ }
929
+ return `match ${input} {
930
+ Some(serde_json::Value::String(${innerKey})) => {
931
+ DateTime::<FixedOffset>::parse_from_rfc3339(${innerKey})
932
+ .unwrap_or(DateTime::default())
933
+ }
934
+ _ => DateTime::default(),
935
+ }`;
936
+ },
937
+ toJsonTemplate(input, target) {
938
+ return `${target}.push_str(serialize_date_time(${input}, true).as_str())`;
939
+ },
940
+ toQueryStringTemplate(input, key, target) {
941
+ const innerKey = validRustIdentifier(`${key}_val`);
942
+ if (context.isOptional) {
943
+ return `match ${input} {
944
+ Some(${innerKey}) => {
945
+ ${target}.push(format!(
946
+ "${key}={}",
947
+ serialize_date_time(${innerKey}, false)
948
+ ));
949
+ }
950
+ _ => {}
951
+ }`;
952
+ }
953
+ if (schema.nullable) {
954
+ return `match ${input} {
955
+ Some(${innerKey}) => {
956
+ ${target}.push(format!(
957
+ "${key}={}",
958
+ serialize_date_time(${innerKey}, false)
959
+ ));
960
+ }
961
+ _ => {
962
+ ${target}.push("${key}=null".to_string());
963
+ }
964
+ }`;
965
+ }
966
+ return `${target}.push(format!(
967
+ "${key}={}",
968
+ serialize_date_time(${input}, false)
969
+ ))`;
970
+ },
971
+ content: ""
972
+ };
973
+ }
974
+ function rustF32FromSchema(schema, context) {
975
+ const isOptionType = outputIsOptionType(schema, context);
976
+ const typeName = isOptionType ? `Option<f32>` : "f32";
977
+ const defaultValue = isOptionType ? `None` : "0.0";
978
+ return {
979
+ typeName,
980
+ defaultValue,
981
+ isNullable: schema.nullable ?? false,
982
+ fromJsonTemplate(input, key) {
983
+ const innerKey = validRustIdentifier(`${key}_val`);
984
+ if (isOptionType) {
985
+ return `match ${input} {
986
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_f64() {
987
+ Some(${innerKey}_result) => Some(${innerKey}_result as f32),
988
+ _ => None,
989
+ },
990
+ _ => None,
991
+ }`;
992
+ }
993
+ return `match ${input} {
994
+ Some(serde_json::Value::Number(${innerKey})) => {
995
+ ${innerKey}.as_f64().unwrap_or(0.0) as f32
996
+ }
997
+ _ => 0.0,
998
+ }`;
999
+ },
1000
+ toJsonTemplate(input, target) {
1001
+ return `${target}.push_str(${input}.to_string().as_str())`;
1002
+ },
1003
+ toQueryStringTemplate(input, key, target) {
1004
+ const innerKey = validRustIdentifier(`${key}_val`);
1005
+ if (context.isOptional) {
1006
+ return `match ${input} {
1007
+ Some(${innerKey}) => {
1008
+ ${target}.push(format!("${key}={}", ${innerKey}));
1009
+ }
1010
+ _ => {}
1011
+ }`;
1012
+ }
1013
+ if (schema.nullable) {
1014
+ return `match ${input} {
1015
+ Some(${innerKey}) => {
1016
+ ${target}.push(format!("${key}={}", ${innerKey}));
1017
+ }
1018
+ _ => {
1019
+ ${target}.push("${key}=null".to_string());
1020
+ }
1021
+ }`;
1022
+ }
1023
+ return `${target}.push(format!("${key}={}", ${input}))`;
1024
+ },
1025
+ content: ""
1026
+ };
1027
+ }
1028
+ function rustF64FromSchema(schema, context) {
1029
+ const isOptionType = outputIsOptionType(schema, context);
1030
+ const typeName = isOptionType ? `Option<f64>` : "f64";
1031
+ const defaultValue = isOptionType ? `None` : "0.0";
1032
+ return {
1033
+ typeName,
1034
+ defaultValue,
1035
+ isNullable: schema.nullable ?? false,
1036
+ fromJsonTemplate(input, key) {
1037
+ const innerKey = validRustIdentifier(`${key}_val`);
1038
+ if (isOptionType) {
1039
+ return `match ${input} {
1040
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_f64() {
1041
+ Some(${innerKey}_result) => Some(${innerKey}_result),
1042
+ _ => None,
1043
+ },
1044
+ _ => None,
1045
+ }`;
1046
+ }
1047
+ return `match ${input} {
1048
+ Some(serde_json::Value::Number(${innerKey})) => {
1049
+ ${innerKey}.as_f64().unwrap_or(0.0)
1050
+ }
1051
+ _ => 0.0,
1052
+ }`;
1053
+ },
1054
+ toJsonTemplate(input, target) {
1055
+ return `${target}.push_str(${input}.to_string().as_str())`;
1056
+ },
1057
+ toQueryStringTemplate(input, key, target) {
1058
+ const innerKey = validRustIdentifier(`${key}_val`);
1059
+ if (context.isOptional) {
1060
+ return `match ${input} {
1061
+ Some(${innerKey}) => {
1062
+ ${target}.push(format!("${key}={}", ${innerKey}));
1063
+ }
1064
+ _ => {}
1065
+ }`;
1066
+ }
1067
+ if (schema.nullable) {
1068
+ return `match ${input} {
1069
+ Some(${innerKey}) => {
1070
+ ${target}.push(format!("${key}={}", ${innerKey}));
1071
+ }
1072
+ _ => {
1073
+ ${target}.push("${key}=null".to_string());
1074
+ }
1075
+ }`;
1076
+ }
1077
+ return `${target}.push(format!("${key}={}", ${input}))`;
1078
+ },
1079
+ content: ""
1080
+ };
1081
+ }
1082
+ function rustI8FromSchema(schema, context) {
1083
+ const isOptionType = outputIsOptionType(schema, context);
1084
+ const typeName = isOptionType ? `Option<i8>` : "i8";
1085
+ const defaultValue = isOptionType ? `None` : "0";
1086
+ return {
1087
+ typeName,
1088
+ defaultValue,
1089
+ isNullable: schema.nullable ?? false,
1090
+ fromJsonTemplate(input, key) {
1091
+ const innerKey = validRustIdentifier(`${key}_val`);
1092
+ if (isOptionType) {
1093
+ return `match ${input} {
1094
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_i64() {
1095
+ Some(${innerKey}_result) => match i8::try_from(${innerKey}_result) {
1096
+ Ok(${innerKey}_result_val) => Some(${innerKey}_result_val),
1097
+ Err(_) => None,
1098
+ },
1099
+ _ => None,
1100
+ },
1101
+ _ => None,
1102
+ }`;
1103
+ }
1104
+ return `match ${input} {
1105
+ Some(serde_json::Value::Number(${innerKey})) => {
1106
+ i8::try_from(${innerKey}.as_i64().unwrap_or(0)).unwrap_or(0)
1107
+ }
1108
+ _ => 0,
1109
+ }`;
1110
+ },
1111
+ toJsonTemplate(input, target) {
1112
+ return `${target}.push_str(${input}.to_string().as_str())`;
1113
+ },
1114
+ toQueryStringTemplate(input, key, target) {
1115
+ const innerKey = validRustIdentifier(`${key}_val`);
1116
+ if (context.isOptional) {
1117
+ return `match ${input} {
1118
+ Some(${innerKey}) => {
1119
+ ${target}.push(format!("${key}={}", ${innerKey}));
1120
+ }
1121
+ _ => {}
1122
+ }`;
1123
+ }
1124
+ if (schema.nullable) {
1125
+ return `match ${input} {
1126
+ Some(${innerKey}) => {
1127
+ ${target}.push(format!("${key}={}", ${innerKey}));
1128
+ }
1129
+ _ => {
1130
+ ${target}.push("${key}=null".to_string());
1131
+ }
1132
+ }`;
1133
+ }
1134
+ return `${target}.push(format!("${key}={}", ${input}))`;
1135
+ },
1136
+ content: ""
1137
+ };
1138
+ }
1139
+ function rustU8FromSchema(schema, context) {
1140
+ const isOptionType = outputIsOptionType(schema, context);
1141
+ const typeName = isOptionType ? "Option<u8>" : "u8";
1142
+ const defaultValue = isOptionType ? "None" : "0";
1143
+ return {
1144
+ typeName,
1145
+ defaultValue,
1146
+ isNullable: schema.nullable ?? false,
1147
+ fromJsonTemplate(input, key) {
1148
+ const innerKey = validRustIdentifier(`${key}_val`);
1149
+ if (isOptionType) {
1150
+ return `match ${input} {
1151
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_u64() {
1152
+ Some(${innerKey}_result) => match u8::try_from(${innerKey}_result) {
1153
+ Ok(${innerKey}_result_val) => Some(${innerKey}_result_val),
1154
+ Err(_) => None,
1155
+ },
1156
+ _ => None,
1157
+ },
1158
+ _ => None,
1159
+ }`;
1160
+ }
1161
+ return `match ${input} {
1162
+ Some(serde_json::Value::Number(${innerKey})) => {
1163
+ u8::try_from(${innerKey}.as_u64().unwrap_or(0)).unwrap_or(0)
1164
+ }
1165
+ _ => 0,
1166
+ }`;
1167
+ },
1168
+ toJsonTemplate(input, target) {
1169
+ return `${target}.push_str(${input}.to_string().as_str())`;
1170
+ },
1171
+ toQueryStringTemplate(input, key, target) {
1172
+ const innerKey = validRustIdentifier(`${key}_val`);
1173
+ if (context.isOptional) {
1174
+ return `match ${input} {
1175
+ Some(${innerKey}) => {
1176
+ ${target}.push(format!("${key}={}", ${innerKey}));
1177
+ }
1178
+ _ => {}
1179
+ }`;
1180
+ }
1181
+ if (schema.nullable) {
1182
+ return `match ${input} {
1183
+ Some(${innerKey}) => {
1184
+ ${target}.push(format!("${key}={}", ${innerKey}));
1185
+ }
1186
+ _ => {
1187
+ ${target}.push("${key}=null".to_string());
1188
+ }
1189
+ }`;
1190
+ }
1191
+ return `${target}.push(format!("${key}={}", ${input}))`;
1192
+ },
1193
+ content: ""
1194
+ };
1195
+ }
1196
+ function rustI16FromSchema(schema, context) {
1197
+ const isOptionType = outputIsOptionType(schema, context);
1198
+ const typeName = isOptionType ? "Option<i16>" : "i16";
1199
+ const defaultValue = isOptionType ? "None" : "0";
1200
+ return {
1201
+ typeName,
1202
+ defaultValue,
1203
+ isNullable: schema.nullable ?? false,
1204
+ fromJsonTemplate(input, key) {
1205
+ const innerKey = validRustIdentifier(`${key}_val`);
1206
+ if (isOptionType) {
1207
+ return `match ${input} {
1208
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_i64() {
1209
+ Some(${innerKey}_result) => match i16::try_from(${innerKey}_result) {
1210
+ Ok(${innerKey}_result_val) => Some(${innerKey}_result_val),
1211
+ Err(_) => None,
1212
+ },
1213
+ _ => None,
1214
+ },
1215
+ _ => None,
1216
+ }`;
1217
+ }
1218
+ return `match ${input} {
1219
+ Some(serde_json::Value::Number(${innerKey})) => {
1220
+ i16::try_from(${innerKey}.as_i64().unwrap_or(0)).unwrap_or(0)
1221
+ }
1222
+ _ => 0,
1223
+ }`;
1224
+ },
1225
+ toJsonTemplate(input, target) {
1226
+ return `${target}.push_str(${input}.to_string().as_str())`;
1227
+ },
1228
+ toQueryStringTemplate(input, key, target) {
1229
+ const innerKey = validRustIdentifier(`${key}_val`);
1230
+ if (context.isOptional) {
1231
+ return `match ${input} {
1232
+ Some(${innerKey}) => {
1233
+ ${target}.push(format!("${key}={}", ${innerKey}));
1234
+ }
1235
+ _ => {}
1236
+ }`;
1237
+ }
1238
+ if (schema.nullable) {
1239
+ return `match ${input} {
1240
+ Some(${innerKey}) => {
1241
+ ${target}.push(format!("${key}={}", ${innerKey}));
1242
+ }
1243
+ _ => {
1244
+ ${target}.push("${key}=null".to_string());
1245
+ }
1246
+ }`;
1247
+ }
1248
+ return `${target}.push(format!("${key}={}", ${input}))`;
1249
+ },
1250
+ content: ""
1251
+ };
1252
+ }
1253
+ function rustU16FromSchema(schema, context) {
1254
+ const isOptionType = outputIsOptionType(schema, context);
1255
+ const typeName = isOptionType ? "Option<u16>" : "u16";
1256
+ const defaultValue = isOptionType ? "None" : "0";
1257
+ return {
1258
+ typeName,
1259
+ defaultValue,
1260
+ isNullable: schema.nullable ?? false,
1261
+ fromJsonTemplate(input, key) {
1262
+ const innerKey = validRustIdentifier(`${key}_val`);
1263
+ if (isOptionType) {
1264
+ return `match ${input} {
1265
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_u64() {
1266
+ Some(${innerKey}_result) => match u16::try_from(${innerKey}_result) {
1267
+ Ok(${innerKey}_result_val) => Some(${innerKey}_result_val),
1268
+ Err(_) => None,
1269
+ },
1270
+ _ => None,
1271
+ },
1272
+ _ => None,
1273
+ }`;
1274
+ }
1275
+ return `match ${input} {
1276
+ Some(serde_json::Value::Number(${innerKey})) => {
1277
+ u16::try_from(${innerKey}.as_u64().unwrap_or(0)).unwrap_or(0)
1278
+ }
1279
+ _ => 0,
1280
+ }`;
1281
+ },
1282
+ toJsonTemplate(input, target) {
1283
+ return `${target}.push_str(${input}.to_string().as_str())`;
1284
+ },
1285
+ toQueryStringTemplate(input, key, target) {
1286
+ const innerKey = validRustIdentifier(`${key}_val`);
1287
+ if (context.isOptional) {
1288
+ return `match ${input} {
1289
+ Some(${innerKey}) => {
1290
+ ${target}.push(format!("${key}={}", ${innerKey}));
1291
+ }
1292
+ _ => {}
1293
+ }`;
1294
+ }
1295
+ if (schema.nullable) {
1296
+ return `match ${input} {
1297
+ Some(${innerKey}) => {
1298
+ ${target}.push(format!("${key}={}", ${innerKey}));
1299
+ }
1300
+ _ => {
1301
+ ${target}.push("${key}=null".to_string());
1302
+ }
1303
+ }`;
1304
+ }
1305
+ return `${target}.push(format!("${key}={}", ${input}))`;
1306
+ },
1307
+ content: ""
1308
+ };
1309
+ }
1310
+ function rustI32FromSchema(schema, context) {
1311
+ const isOptionType = outputIsOptionType(schema, context);
1312
+ const typeName = isOptionType ? "Option<i32>" : "i32";
1313
+ const defaultValue = isOptionType ? "None" : "0";
1314
+ return {
1315
+ typeName,
1316
+ defaultValue,
1317
+ isNullable: schema.nullable ?? false,
1318
+ fromJsonTemplate(input, key) {
1319
+ const innerKey = validRustIdentifier(`${key}_val`);
1320
+ if (isOptionType) {
1321
+ return `match ${input} {
1322
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_i64() {
1323
+ Some(${innerKey}_result) => match i32::try_from(${innerKey}_result) {
1324
+ Ok(${innerKey}_result_val) => Some(${innerKey}_result_val),
1325
+ Err(_) => None,
1326
+ },
1327
+ _ => None,
1328
+ },
1329
+ _ => None,
1330
+ }`;
1331
+ }
1332
+ return `match ${input} {
1333
+ Some(serde_json::Value::Number(${innerKey})) => {
1334
+ i32::try_from(${innerKey}.as_i64().unwrap_or(0)).unwrap_or(0)
1335
+ }
1336
+ _ => 0,
1337
+ }`;
1338
+ },
1339
+ toJsonTemplate(input, target) {
1340
+ return `${target}.push_str(${input}.to_string().as_str())`;
1341
+ },
1342
+ toQueryStringTemplate(input, key, target) {
1343
+ const innerKey = validRustIdentifier(`${key}_val`);
1344
+ if (context.isOptional) {
1345
+ return `match ${input} {
1346
+ Some(${innerKey}) => {
1347
+ ${target}.push(format!("${key}={}", ${innerKey}));
1348
+ }
1349
+ _ => {}
1350
+ }`;
1351
+ }
1352
+ if (schema.nullable) {
1353
+ return `match ${input} {
1354
+ Some(${innerKey}) => {
1355
+ ${target}.push(format!("${key}={}", ${innerKey}));
1356
+ }
1357
+ _ => {
1358
+ ${target}.push("${key}=null".to_string());
1359
+ }
1360
+ }`;
1361
+ }
1362
+ return `${target}.push(format!("${key}={}", ${input}))`;
1363
+ },
1364
+ content: ""
1365
+ };
1366
+ }
1367
+ function rustU32FromSchema(schema, context) {
1368
+ const isOptionType = outputIsOptionType(schema, context);
1369
+ const typeName = isOptionType ? "Option<u32>" : "u32";
1370
+ const defaultValue = isOptionType ? "None" : "0";
1371
+ return {
1372
+ typeName,
1373
+ defaultValue,
1374
+ isNullable: schema.nullable ?? false,
1375
+ fromJsonTemplate(input, key) {
1376
+ const innerKey = validRustIdentifier(`${key}_val`);
1377
+ if (isOptionType) {
1378
+ return `match ${input} {
1379
+ Some(serde_json::Value::Number(${innerKey})) => match ${innerKey}.as_u64() {
1380
+ Some(${innerKey}_result) => match u32::try_from(${innerKey}_result) {
1381
+ Ok(${innerKey}_result_val) => Some(${innerKey}_result_val),
1382
+ Err(_) => None,
1383
+ },
1384
+ _ => None,
1385
+ },
1386
+ _ => None,
1387
+ }`;
1388
+ }
1389
+ return `match ${input} {
1390
+ Some(serde_json::Value::Number(${innerKey})) => {
1391
+ u32::try_from(${innerKey}.as_u64().unwrap_or(0)).unwrap_or(0)
1392
+ }
1393
+ _ => 0,
1394
+ }`;
1395
+ },
1396
+ toJsonTemplate(input, target) {
1397
+ return `${target}.push_str(${input}.to_string().as_str())`;
1398
+ },
1399
+ toQueryStringTemplate(input, key, target) {
1400
+ const innerKey = validRustIdentifier(`${key}_val`);
1401
+ if (context.isOptional) {
1402
+ return `match ${input} {
1403
+ Some(${innerKey}) => {
1404
+ ${target}.push(format!("${key}={}", ${innerKey}));
1405
+ }
1406
+ _ => {}
1407
+ }`;
1408
+ }
1409
+ if (schema.nullable) {
1410
+ return `match ${input} {
1411
+ Some(${innerKey}) => {
1412
+ ${target}.push(format!("${key}={}", ${innerKey}));
1413
+ }
1414
+ _ => {
1415
+ ${target}.push("${key}=null".to_string());
1416
+ }
1417
+ }`;
1418
+ }
1419
+ return `${target}.push(format!("${key}={}", ${input}))`;
1420
+ },
1421
+ content: ""
1422
+ };
1423
+ }
1424
+ function rustI64FromSchema(schema, context) {
1425
+ const isOptionType = outputIsOptionType(schema, context);
1426
+ const typeName = isOptionType ? "Option<i64>" : "i64";
1427
+ const defaultValue = isOptionType ? "None" : "0";
1428
+ return {
1429
+ typeName,
1430
+ defaultValue,
1431
+ isNullable: schema.nullable ?? false,
1432
+ fromJsonTemplate(input, key) {
1433
+ const innerKey = validRustIdentifier(`${key}_val`);
1434
+ if (isOptionType) {
1435
+ return `match ${input} {
1436
+ Some(serde_json::Value::String(${innerKey})) => match ${innerKey}.parse::<i64>() {
1437
+ Ok(${innerKey}_result) => Some(${innerKey}_result),
1438
+ Err(_) => None,
1439
+ },
1440
+ _ => None,
1441
+ }`;
1442
+ }
1443
+ return `match ${input} {
1444
+ Some(serde_json::Value::String(${innerKey})) => {
1445
+ ${innerKey}.parse::<i64>().unwrap_or(0)
1446
+ }
1447
+ _ => 0,
1448
+ }`;
1449
+ },
1450
+ toJsonTemplate(input, target) {
1451
+ return `${target}.push_str(format!("\\"{}\\"", ${input}).as_str())`;
1452
+ },
1453
+ toQueryStringTemplate(input, key, target) {
1454
+ const innerKey = validRustIdentifier(`${key}_val`);
1455
+ if (context.isOptional) {
1456
+ return `match ${input} {
1457
+ Some(${innerKey}) => {
1458
+ ${target}.push(format!("${key}={}", ${innerKey}));
1459
+ }
1460
+ _ => {}
1461
+ }`;
1462
+ }
1463
+ if (schema.nullable) {
1464
+ return `match ${input} {
1465
+ Some(${innerKey}) => {
1466
+ ${target}.push(format!("${key}={}", ${innerKey}));
1467
+ }
1468
+ _ => {
1469
+ ${target}.push("${key}=null".to_string());
1470
+ }
1471
+ }`;
1472
+ }
1473
+ return `${target}.push(format!("${key}={}", ${input}))`;
1474
+ },
1475
+ content: ""
1476
+ };
1477
+ }
1478
+ function rustU64FromSchema(schema, context) {
1479
+ const isOptionType = outputIsOptionType(schema, context);
1480
+ const typeName = isOptionType ? "Option<u64>" : "u64";
1481
+ const defaultValue = isOptionType ? "None" : "0";
1482
+ return {
1483
+ typeName,
1484
+ defaultValue,
1485
+ isNullable: schema.nullable ?? false,
1486
+ fromJsonTemplate(input, key) {
1487
+ const innerKey = validRustIdentifier(`${key}_val`);
1488
+ if (isOptionType) {
1489
+ return `match ${input} {
1490
+ Some(serde_json::Value::String(${innerKey})) => match ${innerKey}.parse::<u64>() {
1491
+ Ok(${innerKey}_result) => Some(${innerKey}_result),
1492
+ Err(_) => None,
1493
+ },
1494
+ _ => None,
1495
+ }`;
1496
+ }
1497
+ return `match ${input} {
1498
+ Some(serde_json::Value::String(${innerKey})) => {
1499
+ ${innerKey}.parse::<u64>().unwrap_or(0)
1500
+ }
1501
+ _ => 0,
1502
+ }`;
1503
+ },
1504
+ toJsonTemplate(input, target) {
1505
+ return `${target}.push_str(format!("\\"{}\\"", ${input}).as_str())`;
1506
+ },
1507
+ toQueryStringTemplate(input, key, target) {
1508
+ const innerKey = validRustIdentifier(`${key}_val`);
1509
+ if (context.isOptional) {
1510
+ return `match ${input} {
1511
+ Some(${innerKey}) => {
1512
+ ${target}.push(format!("${key}={}", ${innerKey}));
1513
+ }
1514
+ _ => {}
1515
+ }`;
1516
+ }
1517
+ if (schema.nullable) {
1518
+ return `match ${input} {
1519
+ Some(${innerKey}) => {
1520
+ ${target}.push(format!("${key}={}", ${innerKey}));
1521
+ }
1522
+ _ => {
1523
+ ${target}.push("${key}=null".to_string());
1524
+ }
1525
+ }`;
1526
+ }
1527
+ return `${target}.push(format!("${key}={}", ${input}))`;
1528
+ },
1529
+ content: ""
1530
+ };
1531
+ }
1532
+
1533
+ function rustRpcFromSchema(schema, context) {
1534
+ switch (schema.transport) {
1535
+ case "http":
1536
+ return rustHttpRpcFromSchema(schema, context);
1537
+ case "ws":
1538
+ return rustWsRpcFromSchema(schema, context);
1539
+ default:
1540
+ console.warn(
1541
+ `[rust-codegen] Unknown transport type "${schema.transport}". Skipping ${context.instancePath}.`
1542
+ );
1543
+ return "";
1544
+ }
1545
+ }
1546
+ function rustHttpRpcFromSchema(schema, context) {
1547
+ if (schema.isEventStream) {
1548
+ console.warn(
1549
+ `[rust-codegen] SSE is not supported at this time. Skipping ${context.instancePath}.`
1550
+ );
1551
+ return "";
1552
+ }
1553
+ const functionName = getFunctionName(context.instancePath);
1554
+ const params = schema.params ? validRustName(schema.params) : void 0;
1555
+ const response = schema.response ? validRustName(schema.response) : void 0;
1556
+ let leading = "";
1557
+ if (schema.description) {
1558
+ leading += formatDescriptionComment(schema.description);
1559
+ leading += "\n";
1560
+ }
1561
+ if (schema.isDeprecated) {
1562
+ leading += "#[deprecated]\n";
1563
+ }
1564
+ return `${leading}pub async fn ${functionName} (
1565
+ self: &Self,
1566
+ ${params ? `params: ${context.typeNamePrefix}${params},` : ""}
1567
+ ) -> Result<${context.typeNamePrefix}${response ?? "()"}, ArriServerError> {
1568
+ parsed_arri_request(
1569
+ ArriParsedRequestOptions {
1570
+ http_client: &self.config.http_client,
1571
+ url: format!("{}${schema.path}", &self.config.base_url),
1572
+ method: reqwest::Method::${schema.method.toUpperCase()},
1573
+ headers: self.config.headers,
1574
+ client_version: "${context.clientVersion}".to_string(),
1575
+ },
1576
+ ${params ? `Some(params)` : "None::<EmptyArriModel>"},
1577
+ |body| ${response ? `return ${context.typeNamePrefix}${response}::from_json_string(body)` : "{}"},
1578
+ )
1579
+ .await
1580
+ }`;
1581
+ }
1582
+ function rustWsRpcFromSchema(schema, context) {
1583
+ console.warn(
1584
+ `[rust-codegen] WS RPCs are not supported at this time. Skipping ${context.instancePath}.`
1585
+ );
1586
+ return "";
1587
+ }
1588
+ function getFunctionName(instancePath) {
1589
+ assert__default(instancePath.length > 0);
1590
+ const name = instancePath.split(".").pop() ?? "";
1591
+ return validRustIdentifier(name);
1592
+ }
1593
+ function getServiceName(instancePath, context) {
1594
+ assert__default(instancePath.length > 0);
1595
+ const name = instancePath.split(".").join("_");
1596
+ return validRustName(`${context.clientName}_${name}_Service`);
1597
+ }
1598
+ function rustServiceFromSchema(schema, context) {
1599
+ const serviceName = getServiceName(context.instancePath, context);
1600
+ const subServices = [];
1601
+ const subServiceContent = [];
1602
+ const rpcParts = [];
1603
+ for (const key of Object.keys(schema)) {
1604
+ const subSchema = schema[key];
1605
+ if (codegenUtils.isServiceDefinition(subSchema)) {
1606
+ const subService = rustServiceFromSchema(subSchema, {
1607
+ clientVersion: context.clientVersion,
1608
+ clientName: context.clientName,
1609
+ typeNamePrefix: context.typeNamePrefix,
1610
+ instancePath: `${context.instancePath}.${key}`,
1611
+ schemaPath: `${context.schemaPath}.${key}`,
1612
+ generatedTypes: context.generatedTypes
1613
+ });
1614
+ if (subService.content) {
1615
+ subServices.push({
1616
+ key: validRustIdentifier(key),
1617
+ name: subService.name
1618
+ });
1619
+ }
1620
+ continue;
1621
+ }
1622
+ if (codegenUtils.isRpcDefinition(subSchema)) {
1623
+ const rpc = rustRpcFromSchema(subSchema, {
1624
+ clientVersion: context.clientVersion,
1625
+ clientName: context.clientName,
1626
+ typeNamePrefix: context.typeNamePrefix,
1627
+ instancePath: `${context.instancePath}.${key}`,
1628
+ schemaPath: `${context.schemaPath}.${key}`,
1629
+ generatedTypes: context.generatedTypes
1630
+ });
1631
+ if (rpc) {
1632
+ rpcParts.push(rpc);
1633
+ }
1634
+ continue;
1635
+ }
1636
+ throw new Error(
1637
+ `[rust-codegen] Invalid schema at /procedures/${context.instancePath}.`
1638
+ );
1639
+ }
1640
+ return {
1641
+ name: serviceName,
1642
+ content: `pub struct ${serviceName}<'a> {
1643
+ config: &'a ArriClientConfig,
1644
+ ${subServices.map((service) => ` pub ${service.key}: ${service.name}<'a>,`).join("\n")}
1645
+ }
1646
+
1647
+ impl<'a> ArriClientService<'a> for ${serviceName}<'a> {
1648
+ fn create(config: &'a ArriClientConfig) -> Self {
1649
+ Self {
1650
+ config: &config,
1651
+ ${subServices.map((service) => ` ${service.key}: ${service.name}::create(config),`).join("\n")}
1652
+ }
1653
+ }
1654
+ }
1655
+
1656
+ impl ${serviceName}<'_> {
1657
+ ${rpcParts.join("\n")}
1658
+ }
1659
+
1660
+ ${subServiceContent.join("\n\n")}
1661
+ `
1662
+ };
1663
+ }
1664
+
1665
+ function rustRecordFromSchema(schema, context) {
1666
+ const innerType = rustTypeFromSchema(schema.values, {
1667
+ clientVersion: context.clientVersion,
1668
+ clientName: context.clientName,
1669
+ typeNamePrefix: context.typeNamePrefix,
1670
+ instancePath: `${context.instancePath}/value`,
1671
+ schemaPath: `${context.schemaPath}/values`,
1672
+ generatedTypes: context.generatedTypes
1673
+ });
1674
+ const isOptionType = outputIsOptionType(schema, context);
1675
+ const typeName = isOptionType ? `Option<BTreeMap<String, ${innerType.typeName}>>` : `BTreeMap<String, ${innerType.typeName}>`;
1676
+ const defaultValue = isOptionType ? `None` : `BTreeMap::new()`;
1677
+ return {
1678
+ typeName,
1679
+ defaultValue,
1680
+ isNullable: schema.nullable ?? false,
1681
+ fromJsonTemplate(input, key) {
1682
+ const innerKey = validRustIdentifier(`${key}_val`);
1683
+ if (isOptionType) {
1684
+ return `match ${input} {
1685
+ Some(serde_json::Value::Object(${innerKey})) => {
1686
+ let mut ${innerKey}_result: BTreeMap<String, ${innerType.typeName}> = BTreeMap::new();
1687
+ for (_key_, _value_) in ${innerKey}.into_iter() {
1688
+ ${innerKey}_result.insert(
1689
+ _key_.to_owned(),
1690
+ ${innerType.fromJsonTemplate(`Some(_value_.to_owned())`, `value`)},
1691
+ );
1692
+ }
1693
+ Some(${innerKey}_result)
1694
+ }
1695
+ _ => None,
1696
+ }`;
1697
+ }
1698
+ return `match ${input} {
1699
+ Some(serde_json::Value::Object(${innerKey})) => {
1700
+ let mut ${innerKey}_result: BTreeMap<String, ${innerType.typeName}> = BTreeMap::new();
1701
+ for (_key_, _value_) in ${innerKey}.into_iter() {
1702
+ ${innerKey}_result.insert(
1703
+ _key_.to_owned(),
1704
+ ${innerType.fromJsonTemplate(`Some(_value_.to_owned())`, `value`)},
1705
+ );
1706
+ }
1707
+ ${innerKey}_result
1708
+ }
1709
+ _ => BTreeMap::new(),
1710
+ }`;
1711
+ },
1712
+ toJsonTemplate(input, target) {
1713
+ if (innerType.isNullable) {
1714
+ return `${target}.push('{');
1715
+ for (_index_, (_key_, _value_)) in ${input}.iter().enumerate() {
1716
+ if _index_ != 0 {
1717
+ ${target}.push(',');
1718
+ }
1719
+ ${target}.push_str(format!("\\"{}\\":", _key_).as_str());
1720
+ match _value_ {
1721
+ Some(value_val) => {
1722
+ ${innerType.toJsonTemplate("value_val", target)};
1723
+ },
1724
+ _ => {
1725
+ ${target}.push_str("null");
1726
+ }
1727
+ }
1728
+ }
1729
+ ${target}.push('}')`;
1730
+ }
1731
+ return `${target}.push('{');
1732
+ for (_index_, (_key_, _value_)) in ${input}.iter().enumerate() {
1733
+ if _index_ != 0 {
1734
+ ${target}.push(',');
1735
+ }
1736
+ ${target}.push_str(format!("\\"{}\\":", _key_).as_str());
1737
+ ${innerType.toJsonTemplate(`_value_`, target)};
1738
+ }
1739
+ ${target}.push('}')`;
1740
+ },
1741
+ toQueryStringTemplate() {
1742
+ return `println!("[WARNING] cannot serialize nested objects to query params. Skipping field at ${context.instancePath}.")`;
1743
+ },
1744
+ content: innerType.content
1745
+ };
1746
+ }
1747
+
1748
+ function rustRefFromSchema(schema, context) {
1749
+ const innerTypeName = `${context.typeNamePrefix}${validRustName(schema.ref)}`;
1750
+ const isOptionType = outputIsOptionType(schema, context);
1751
+ let typeName = `Box<${innerTypeName}>`;
1752
+ if (isOptionType) {
1753
+ typeName = `Option<${typeName}>`;
1754
+ }
1755
+ let defaultValue;
1756
+ if (isOptionType) {
1757
+ defaultValue = "None";
1758
+ } else {
1759
+ defaultValue = `Box::new(${innerTypeName}::new())`;
1760
+ }
1761
+ return {
1762
+ typeName,
1763
+ defaultValue,
1764
+ isNullable: schema.nullable ?? false,
1765
+ fromJsonTemplate(input, key) {
1766
+ const innerKey = validRustIdentifier(`${key}_val`);
1767
+ const valFromJson = (input2) => {
1768
+ {
1769
+ return `Box::new(${innerTypeName}::from_json(${input2}.to_owned()))`;
1770
+ }
1771
+ };
1772
+ if (isOptionType) {
1773
+ return `match ${input} {
1774
+ Some(${innerKey}) => match ${innerKey} {
1775
+ serde_json::Value::Object(_) => {
1776
+ Some(${valFromJson(innerKey)})
1777
+ }
1778
+ _ => None,
1779
+ },
1780
+ _ => None,
1781
+ }`;
1782
+ }
1783
+ return `match ${input} {
1784
+ Some(${innerKey}) => match ${innerKey} {
1785
+ serde_json::Value::Object(_) => {
1786
+ ${valFromJson(innerKey)}
1787
+ }
1788
+ _ => ${valFromJson(innerKey)},
1789
+ },
1790
+ _ => Box::new(${innerTypeName}::new()),
1791
+ }`;
1792
+ },
1793
+ toJsonTemplate(input, target) {
1794
+ return `${target}.push_str(${input}.to_json_string().as_str())`;
1795
+ },
1796
+ toQueryStringTemplate() {
1797
+ return `println!("[WARNING] cannot serialize nested objects to query params. Skipping field at ${context.instancePath}.")`;
1798
+ },
1799
+ content: ""
1800
+ };
1801
+ }
1802
+
1803
+ const rustClientGenerator = codegenUtils.defineGeneratorPlugin(
1804
+ (options) => {
1805
+ return {
1806
+ generator(def) {
1807
+ const context = {
1808
+ clientVersion: def.info?.version ?? "",
1809
+ clientName: options.clientName ?? "Client",
1810
+ typeNamePrefix: options.typePrefix ?? "",
1811
+ instancePath: "",
1812
+ schemaPath: "",
1813
+ generatedTypes: []
1814
+ };
1815
+ const client = createRustClient(def, {
1816
+ ...context
1817
+ });
1818
+ const outputFile = path__default.resolve(options.outputFile);
1819
+ fs__default.writeFileSync(outputFile, client);
1820
+ const shouldFormat = options.format ?? true;
1821
+ if (shouldFormat) {
1822
+ try {
1823
+ node_child_process.execSync(`rustfmt ${outputFile} --edition 2021`, {
1824
+ stdio: "inherit"
1825
+ });
1826
+ } catch (err) {
1827
+ console.error(`Error formatting`, err);
1828
+ }
1829
+ }
1830
+ },
1831
+ options
1832
+ };
1833
+ }
1834
+ );
1835
+ function createRustClient(def, context) {
1836
+ const services = codegenUtils.unflattenProcedures(def.procedures);
1837
+ const rpcParts = [];
1838
+ const subServices = [];
1839
+ const subServiceContent = [];
1840
+ for (const key of Object.keys(services)) {
1841
+ const subDef = services[key];
1842
+ if (codegenUtils.isServiceDefinition(subDef)) {
1843
+ const service = rustServiceFromSchema(subDef, {
1844
+ clientVersion: def.info?.version ?? "",
1845
+ clientName: context.clientName,
1846
+ typeNamePrefix: context.typeNamePrefix,
1847
+ instancePath: key,
1848
+ schemaPath: key,
1849
+ generatedTypes: context.generatedTypes
1850
+ });
1851
+ if (service.content) {
1852
+ subServices.push({
1853
+ key: validRustIdentifier(key),
1854
+ name: service.name
1855
+ });
1856
+ subServiceContent.push(service.content);
1857
+ }
1858
+ continue;
1859
+ }
1860
+ if (codegenUtils.isRpcDefinition(subDef)) {
1861
+ const rpc = rustRpcFromSchema(subDef, {
1862
+ clientVersion: def.info?.version ?? "",
1863
+ clientName: context.clientName,
1864
+ typeNamePrefix: context.typeNamePrefix,
1865
+ instancePath: key,
1866
+ schemaPath: key,
1867
+ generatedTypes: context.generatedTypes
1868
+ });
1869
+ if (rpc) {
1870
+ rpcParts.push(rpc);
1871
+ }
1872
+ continue;
1873
+ }
1874
+ }
1875
+ const modelParts = [];
1876
+ for (const key of Object.keys(def.definitions)) {
1877
+ const result = rustTypeFromSchema(def.definitions[key], {
1878
+ ...context,
1879
+ clientVersion: def.info?.version ?? "",
1880
+ instancePath: key,
1881
+ schemaPath: ""
1882
+ });
1883
+ if (result.content) {
1884
+ modelParts.push(result.content);
1885
+ }
1886
+ }
1887
+ if (rpcParts.length === 0 && subServiceContent.length === 0) {
1888
+ return `#![allow(dead_code, unused_imports, unused_variables, unconditional_recursion, deprecated)]
1889
+ use arri_client::{
1890
+ chrono::{DateTime, FixedOffset},
1891
+ serde_json::{self},
1892
+ utils::{serialize_date_time, serialize_string},
1893
+ ArriEnum, ArriModel,
1894
+ };
1895
+ use std::collections::BTreeMap;
1896
+ ${modelParts.join("\n\n")}`;
1897
+ }
1898
+ const clientName = validRustName(context.clientName);
1899
+ return `#![allow(dead_code, unused_imports, unused_variables, unconditional_recursion, deprecated)]
1900
+ use arri_client::{
1901
+ chrono::{DateTime, FixedOffset},
1902
+ parsed_arri_request, reqwest, serde_json,
1903
+ utils::{serialize_date_time, serialize_string},
1904
+ ArriClientConfig, ArriClientService, ArriEnum, ArriModel, ArriParsedRequestOptions,
1905
+ ArriServerError, EmptyArriModel,
1906
+ };
1907
+ use std::collections::BTreeMap;
1908
+
1909
+ pub struct ${clientName}<'a> {
1910
+ config: &'a ArriClientConfig,
1911
+ ${subServices.map((service) => ` pub ${service.key}: ${service.name}<'a>,`).join("\n")}
1912
+ }
1913
+
1914
+ impl<'a> ArriClientService<'a> for ${clientName}<'a> {
1915
+ fn create(config: &'a ArriClientConfig) -> Self {
1916
+ Self {
1917
+ config: &config,
1918
+ ${subServices.map((service) => ` ${service.key}: ${service.name}::create(config),`).join("\n")}
1919
+ }
1920
+ }
1921
+ }
1922
+
1923
+ impl ${clientName}<'_> {
1924
+ ${rpcParts.join("\n")}
1925
+ }
1926
+
1927
+ ${subServiceContent.join("\n\n")}
1928
+
1929
+ ${modelParts.join("\n\n")}`;
1930
+ }
1931
+ function rustTypeFromSchema(schema, context) {
1932
+ if (codegenUtils.isSchemaFormType(schema)) {
1933
+ switch (schema.type) {
1934
+ case "string":
1935
+ return rustStringFromSchema(schema, context);
1936
+ case "boolean":
1937
+ return rustBooleanFromSchema(schema, context);
1938
+ case "timestamp":
1939
+ return rustTimestampFromSchema(schema, context);
1940
+ case "float32":
1941
+ return rustF32FromSchema(schema, context);
1942
+ case "float64":
1943
+ return rustF64FromSchema(schema, context);
1944
+ case "int8":
1945
+ return rustI8FromSchema(schema, context);
1946
+ case "uint8":
1947
+ return rustU8FromSchema(schema, context);
1948
+ case "int16":
1949
+ return rustI16FromSchema(schema, context);
1950
+ case "uint16":
1951
+ return rustU16FromSchema(schema, context);
1952
+ case "int32":
1953
+ return rustI32FromSchema(schema, context);
1954
+ case "uint32":
1955
+ return rustU32FromSchema(schema, context);
1956
+ case "int64":
1957
+ return rustI64FromSchema(schema, context);
1958
+ case "uint64":
1959
+ return rustU64FromSchema(schema, context);
1960
+ default:
1961
+ schema.type;
1962
+ throw new Error(`Unhandled schema type: "${schema.type}"`);
1963
+ }
1964
+ }
1965
+ if (codegenUtils.isSchemaFormProperties(schema)) {
1966
+ return rustObjectFromSchema(schema, context);
1967
+ }
1968
+ if (codegenUtils.isSchemaFormEnum(schema)) {
1969
+ return rustEnumFromSchema(schema, context);
1970
+ }
1971
+ if (codegenUtils.isSchemaFormElements(schema)) {
1972
+ return rustArrayFromSchema(schema, context);
1973
+ }
1974
+ if (codegenUtils.isSchemaFormValues(schema)) {
1975
+ return rustRecordFromSchema(schema, context);
1976
+ }
1977
+ if (codegenUtils.isSchemaFormDiscriminator(schema)) {
1978
+ return rustTaggedUnionFromSchema(schema, context);
1979
+ }
1980
+ if (codegenUtils.isSchemaFormRef(schema)) {
1981
+ return rustRefFromSchema(schema, context);
1982
+ }
1983
+ return rustAnyFromSchema(schema, context);
1984
+ }
1985
+
1986
+ exports.createRustClient = createRustClient;
1987
+ exports.rustClientGenerator = rustClientGenerator;
1988
+ exports.rustTypeFromSchema = rustTypeFromSchema;