@aztec/bb.js 0.0.1-commit.fce3e4f → 0.0.1-commit.fffb133c

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.
Files changed (183) hide show
  1. package/build/amd64-linux/bb +0 -0
  2. package/build/amd64-linux/nodejs_module.node +0 -0
  3. package/build/amd64-macos/bb +0 -0
  4. package/build/amd64-macos/nodejs_module.node +0 -0
  5. package/build/arm64-linux/bb +0 -0
  6. package/build/arm64-linux/nodejs_module.node +0 -0
  7. package/build/arm64-macos/bb +0 -0
  8. package/build/arm64-macos/nodejs_module.node +0 -0
  9. package/dest/browser/barretenberg/backend.d.ts +49 -17
  10. package/dest/browser/barretenberg/backend.d.ts.map +1 -1
  11. package/dest/browser/barretenberg/backend.js +111 -11
  12. package/dest/browser/barretenberg/index.d.ts +2 -2
  13. package/dest/browser/barretenberg/index.d.ts.map +1 -1
  14. package/dest/browser/barretenberg/index.js +2 -2
  15. package/dest/browser/barretenberg_wasm/barretenberg_wasm_main/index.js +1 -1
  16. package/dest/browser/barretenberg_wasm/fetch_code/browser/barretenberg-threads.js +1 -1
  17. package/dest/browser/barretenberg_wasm/fetch_code/browser/barretenberg.js +1 -1
  18. package/dest/browser/bb_backends/index.d.ts +3 -1
  19. package/dest/browser/bb_backends/index.d.ts.map +1 -1
  20. package/dest/browser/cbind/generate.d.ts +5 -2
  21. package/dest/browser/cbind/generate.d.ts.map +1 -1
  22. package/dest/browser/cbind/generate.js +47 -25
  23. package/dest/browser/cbind/generated/api_types.d.ts +766 -1687
  24. package/dest/browser/cbind/generated/api_types.d.ts.map +1 -1
  25. package/dest/browser/cbind/generated/api_types.js +1465 -1555
  26. package/dest/browser/cbind/generated/async.d.ts +3 -5
  27. package/dest/browser/cbind/generated/async.d.ts.map +1 -1
  28. package/dest/browser/cbind/generated/async.js +13 -33
  29. package/dest/browser/cbind/generated/sync.d.ts +3 -5
  30. package/dest/browser/cbind/generated/sync.d.ts.map +1 -1
  31. package/dest/browser/cbind/generated/sync.js +13 -31
  32. package/dest/browser/cbind/naming.d.ts +16 -0
  33. package/dest/browser/cbind/naming.d.ts.map +1 -0
  34. package/dest/browser/cbind/naming.js +24 -0
  35. package/dest/browser/cbind/rust_codegen.d.ts +26 -0
  36. package/dest/browser/cbind/rust_codegen.d.ts.map +1 -0
  37. package/dest/browser/cbind/rust_codegen.js +461 -0
  38. package/dest/browser/cbind/schema_visitor.d.ts +47 -0
  39. package/dest/browser/cbind/schema_visitor.d.ts.map +1 -0
  40. package/dest/browser/cbind/schema_visitor.js +158 -0
  41. package/dest/browser/cbind/typescript_codegen.d.ts +30 -0
  42. package/dest/browser/cbind/typescript_codegen.d.ts.map +1 -0
  43. package/dest/browser/cbind/typescript_codegen.js +365 -0
  44. package/dest/browser/index.d.ts +2 -2
  45. package/dest/browser/index.d.ts.map +1 -1
  46. package/dest/browser/index.js +2 -2
  47. package/dest/node/barretenberg/backend.d.ts +49 -17
  48. package/dest/node/barretenberg/backend.d.ts.map +1 -1
  49. package/dest/node/barretenberg/backend.js +111 -11
  50. package/dest/node/barretenberg/backend.test.d.ts +2 -0
  51. package/dest/node/barretenberg/backend.test.d.ts.map +1 -0
  52. package/dest/node/barretenberg/backend.test.js +103 -0
  53. package/dest/node/barretenberg/index.d.ts +2 -2
  54. package/dest/node/barretenberg/index.d.ts.map +1 -1
  55. package/dest/node/barretenberg/index.js +2 -2
  56. package/dest/node/barretenberg_wasm/barretenberg-threads.wasm.gz +0 -0
  57. package/dest/node/barretenberg_wasm/barretenberg_wasm_main/index.js +1 -1
  58. package/dest/node/bb_backends/index.d.ts +3 -1
  59. package/dest/node/bb_backends/index.d.ts.map +1 -1
  60. package/dest/node/bb_backends/node/index.d.ts +1 -1
  61. package/dest/node/bb_backends/node/index.d.ts.map +1 -1
  62. package/dest/node/bb_backends/node/index.js +5 -5
  63. package/dest/node/bb_backends/node/native_shm.d.ts +3 -2
  64. package/dest/node/bb_backends/node/native_shm.d.ts.map +1 -1
  65. package/dest/node/bb_backends/node/native_shm.js +40 -21
  66. package/dest/node/bb_backends/node/native_shm_async.d.ts +2 -2
  67. package/dest/node/bb_backends/node/native_shm_async.d.ts.map +1 -1
  68. package/dest/node/bb_backends/node/native_shm_async.js +17 -21
  69. package/dest/node/bb_backends/node/native_socket.d.ts +1 -1
  70. package/dest/node/bb_backends/node/native_socket.d.ts.map +1 -1
  71. package/dest/node/bb_backends/node/native_socket.js +7 -5
  72. package/dest/node/bb_backends/node/platform.d.ts +1 -1
  73. package/dest/node/bb_backends/node/platform.d.ts.map +1 -1
  74. package/dest/node/bb_backends/node/platform.js +7 -2
  75. package/dest/node/cbind/generate.d.ts +5 -2
  76. package/dest/node/cbind/generate.d.ts.map +1 -1
  77. package/dest/node/cbind/generate.js +47 -25
  78. package/dest/node/cbind/generated/api_types.d.ts +766 -1687
  79. package/dest/node/cbind/generated/api_types.d.ts.map +1 -1
  80. package/dest/node/cbind/generated/api_types.js +1465 -1555
  81. package/dest/node/cbind/generated/async.d.ts +3 -5
  82. package/dest/node/cbind/generated/async.d.ts.map +1 -1
  83. package/dest/node/cbind/generated/async.js +13 -33
  84. package/dest/node/cbind/generated/sync.d.ts +3 -5
  85. package/dest/node/cbind/generated/sync.d.ts.map +1 -1
  86. package/dest/node/cbind/generated/sync.js +13 -31
  87. package/dest/node/cbind/naming.d.ts +16 -0
  88. package/dest/node/cbind/naming.d.ts.map +1 -0
  89. package/dest/node/cbind/naming.js +24 -0
  90. package/dest/node/cbind/rust_codegen.d.ts +26 -0
  91. package/dest/node/cbind/rust_codegen.d.ts.map +1 -0
  92. package/dest/node/cbind/rust_codegen.js +461 -0
  93. package/dest/node/cbind/schema_visitor.d.ts +47 -0
  94. package/dest/node/cbind/schema_visitor.d.ts.map +1 -0
  95. package/dest/node/cbind/schema_visitor.js +158 -0
  96. package/dest/node/cbind/typescript_codegen.d.ts +30 -0
  97. package/dest/node/cbind/typescript_codegen.d.ts.map +1 -0
  98. package/dest/node/cbind/typescript_codegen.js +365 -0
  99. package/dest/node/index.d.ts +2 -2
  100. package/dest/node/index.d.ts.map +1 -1
  101. package/dest/node/index.js +2 -2
  102. package/dest/node-cjs/barretenberg/backend.d.ts +49 -17
  103. package/dest/node-cjs/barretenberg/backend.d.ts.map +1 -1
  104. package/dest/node-cjs/barretenberg/backend.js +113 -11
  105. package/dest/node-cjs/barretenberg/backend.test.d.ts +2 -0
  106. package/dest/node-cjs/barretenberg/backend.test.d.ts.map +1 -0
  107. package/dest/node-cjs/barretenberg/backend.test.js +105 -0
  108. package/dest/node-cjs/barretenberg/index.d.ts +2 -2
  109. package/dest/node-cjs/barretenberg/index.d.ts.map +1 -1
  110. package/dest/node-cjs/barretenberg/index.js +4 -2
  111. package/dest/node-cjs/barretenberg_wasm/barretenberg-threads.wasm.gz +0 -0
  112. package/dest/node-cjs/barretenberg_wasm/barretenberg_wasm_main/index.js +1 -1
  113. package/dest/node-cjs/bb_backends/index.d.ts +3 -1
  114. package/dest/node-cjs/bb_backends/index.d.ts.map +1 -1
  115. package/dest/node-cjs/bb_backends/node/index.d.ts +1 -1
  116. package/dest/node-cjs/bb_backends/node/index.d.ts.map +1 -1
  117. package/dest/node-cjs/bb_backends/node/index.js +5 -5
  118. package/dest/node-cjs/bb_backends/node/native_shm.d.ts +3 -2
  119. package/dest/node-cjs/bb_backends/node/native_shm.d.ts.map +1 -1
  120. package/dest/node-cjs/bb_backends/node/native_shm.js +39 -20
  121. package/dest/node-cjs/bb_backends/node/native_shm_async.d.ts +2 -2
  122. package/dest/node-cjs/bb_backends/node/native_shm_async.d.ts.map +1 -1
  123. package/dest/node-cjs/bb_backends/node/native_shm_async.js +17 -21
  124. package/dest/node-cjs/bb_backends/node/native_socket.d.ts +1 -1
  125. package/dest/node-cjs/bb_backends/node/native_socket.d.ts.map +1 -1
  126. package/dest/node-cjs/bb_backends/node/native_socket.js +7 -5
  127. package/dest/node-cjs/bb_backends/node/platform.d.ts +1 -1
  128. package/dest/node-cjs/bb_backends/node/platform.d.ts.map +1 -1
  129. package/dest/node-cjs/bb_backends/node/platform.js +7 -2
  130. package/dest/node-cjs/cbind/generate.d.ts +5 -2
  131. package/dest/node-cjs/cbind/generate.d.ts.map +1 -1
  132. package/dest/node-cjs/cbind/generate.js +47 -25
  133. package/dest/node-cjs/cbind/generated/api_types.d.ts +766 -1687
  134. package/dest/node-cjs/cbind/generated/api_types.d.ts.map +1 -1
  135. package/dest/node-cjs/cbind/generated/api_types.js +1671 -1771
  136. package/dest/node-cjs/cbind/generated/async.d.ts +3 -5
  137. package/dest/node-cjs/cbind/generated/async.d.ts.map +1 -1
  138. package/dest/node-cjs/cbind/generated/async.js +12 -32
  139. package/dest/node-cjs/cbind/generated/sync.d.ts +3 -5
  140. package/dest/node-cjs/cbind/generated/sync.d.ts.map +1 -1
  141. package/dest/node-cjs/cbind/generated/sync.js +12 -30
  142. package/dest/node-cjs/cbind/naming.d.ts +16 -0
  143. package/dest/node-cjs/cbind/naming.d.ts.map +1 -0
  144. package/dest/node-cjs/cbind/naming.js +28 -0
  145. package/dest/node-cjs/cbind/rust_codegen.d.ts +26 -0
  146. package/dest/node-cjs/cbind/rust_codegen.d.ts.map +1 -0
  147. package/dest/node-cjs/cbind/rust_codegen.js +465 -0
  148. package/dest/node-cjs/cbind/schema_visitor.d.ts +47 -0
  149. package/dest/node-cjs/cbind/schema_visitor.d.ts.map +1 -0
  150. package/dest/node-cjs/cbind/schema_visitor.js +162 -0
  151. package/dest/node-cjs/cbind/typescript_codegen.d.ts +30 -0
  152. package/dest/node-cjs/cbind/typescript_codegen.d.ts.map +1 -0
  153. package/dest/node-cjs/cbind/typescript_codegen.js +369 -0
  154. package/dest/node-cjs/index.d.ts +2 -2
  155. package/dest/node-cjs/index.d.ts.map +1 -1
  156. package/dest/node-cjs/index.js +4 -2
  157. package/package.json +1 -1
  158. package/src/barretenberg/backend.test.ts +122 -0
  159. package/src/barretenberg/backend.ts +151 -25
  160. package/src/barretenberg/index.ts +9 -1
  161. package/src/barretenberg_wasm/barretenberg_wasm_main/index.ts +1 -1
  162. package/src/bb_backends/index.ts +3 -0
  163. package/src/bb_backends/node/index.ts +9 -4
  164. package/src/bb_backends/node/native_shm.ts +38 -19
  165. package/src/bb_backends/node/native_shm_async.ts +15 -19
  166. package/src/bb_backends/node/native_socket.ts +7 -5
  167. package/src/bb_backends/node/platform.ts +6 -1
  168. package/src/cbind/generate.ts +51 -32
  169. package/src/cbind/naming.ts +27 -0
  170. package/src/cbind/rust_codegen.ts +504 -0
  171. package/src/cbind/schema_visitor.ts +219 -0
  172. package/src/cbind/typescript_codegen.ts +419 -0
  173. package/src/index.ts +4 -0
  174. package/dest/browser/cbind/schema_compiler.d.ts +0 -68
  175. package/dest/browser/cbind/schema_compiler.d.ts.map +0 -1
  176. package/dest/browser/cbind/schema_compiler.js +0 -600
  177. package/dest/node/cbind/schema_compiler.d.ts +0 -68
  178. package/dest/node/cbind/schema_compiler.d.ts.map +0 -1
  179. package/dest/node/cbind/schema_compiler.js +0 -600
  180. package/dest/node-cjs/cbind/schema_compiler.d.ts +0 -68
  181. package/dest/node-cjs/cbind/schema_compiler.d.ts.map +0 -1
  182. package/dest/node-cjs/cbind/schema_compiler.js +0 -607
  183. package/src/cbind/schema_compiler.ts +0 -745
@@ -1,5 +1,8 @@
1
1
  /**
2
- * Generate TypeScript bindings from msgpack schema
2
+ * Multi-language code generation from BB msgpack schema
3
+ *
4
+ * Architecture:
5
+ * Raw Schema → SchemaVisitor → CompiledSchema IR → Language Codegens → Files
3
6
  */
4
7
 
5
8
  import { writeFileSync, mkdirSync } from 'fs';
@@ -8,36 +11,42 @@ import { exec } from 'child_process';
8
11
  import { promisify } from 'util';
9
12
  import { fileURLToPath } from 'url';
10
13
  import { unpack } from 'msgpackr';
11
- import {
12
- createSharedTypesCompiler,
13
- createSyncApiCompiler,
14
- createAsyncApiCompiler,
15
- type SchemaCompiler,
16
- } from './schema_compiler.js';
14
+ import { SchemaVisitor, type CompiledSchema } from './schema_visitor.js';
15
+ import { TypeScriptCodegen } from './typescript_codegen.js';
16
+ import { RustCodegen } from './rust_codegen.js';
17
17
 
18
18
  const execAsync = promisify(exec);
19
19
 
20
- interface GeneratorConfig {
20
+ // Language generators - all use the same CompiledSchema IR
21
+ interface LanguageGenerator {
21
22
  name: string;
22
- outputFile: string;
23
- createCompiler: () => SchemaCompiler;
23
+ enabled: boolean;
24
+ generate: (compiled: CompiledSchema) => Array<{ path: string; content: string }>;
24
25
  }
25
26
 
26
- const GENERATORS: GeneratorConfig[] = [
27
+ const LANGUAGE_GENERATORS: LanguageGenerator[] = [
27
28
  {
28
- name: 'Shared types',
29
- outputFile: 'generated/api_types.ts',
30
- createCompiler: createSharedTypesCompiler,
29
+ name: 'TypeScript',
30
+ enabled: true,
31
+ generate: (compiled) => {
32
+ const tsGen = new TypeScriptCodegen();
33
+ return [
34
+ { path: 'generated/api_types.ts', content: tsGen.generateTypes(compiled) },
35
+ { path: 'generated/sync.ts', content: tsGen.generateSyncApi(compiled) },
36
+ { path: 'generated/async.ts', content: tsGen.generateAsyncApi(compiled) },
37
+ ];
38
+ },
31
39
  },
32
40
  {
33
- name: 'Sync API',
34
- outputFile: 'generated/sync.ts',
35
- createCompiler: createSyncApiCompiler,
36
- },
37
- {
38
- name: 'Async API',
39
- outputFile: 'generated/async.ts',
40
- createCompiler: createAsyncApiCompiler,
41
+ name: 'Rust',
42
+ enabled: true,
43
+ generate: (compiled) => {
44
+ const rustGen = new RustCodegen();
45
+ return [
46
+ { path: '../../../rust/barretenberg-rs/src/generated_types.rs', content: rustGen.generateTypes(compiled) },
47
+ { path: '../../../rust/barretenberg-rs/src/api.rs', content: rustGen.generateApi(compiled) },
48
+ ];
49
+ },
41
50
  },
42
51
  ];
43
52
 
@@ -56,29 +65,39 @@ async function generate() {
56
65
  throw new Error('Invalid schema: missing commands or responses');
57
66
  }
58
67
 
59
- console.log('Generating TypeScript bindings...\n');
68
+ // Compile schema once using visitor pattern
69
+ console.log('Compiling schema...');
70
+ const visitor = new SchemaVisitor();
71
+ const compiled = visitor.visit(schema.commands, schema.responses);
72
+
73
+ console.log(`Found ${compiled.commands.length} commands, ${compiled.structs.size} structs\n`);
60
74
 
61
75
  // Ensure output directory exists
62
76
  const outputDir = join(__dirname, 'generated');
63
77
  mkdirSync(outputDir, { recursive: true });
64
78
 
65
- // Generate each output file
66
- for (const config of GENERATORS) {
67
- const compiler = config.createCompiler();
68
- compiler.processApiSchema(schema.commands, schema.responses);
79
+ // Generate all language bindings from compiled IR
80
+ for (const generator of LANGUAGE_GENERATORS) {
81
+ if (!generator.enabled) {
82
+ console.log(`⊘ ${generator.name}: disabled`);
83
+ continue;
84
+ }
69
85
 
70
- const outputPath = join(__dirname, config.outputFile);
71
- const content = compiler.compile();
72
- writeFileSync(outputPath, content);
86
+ const files = generator.generate(compiled);
73
87
 
74
- console.log(`✓ ${config.name}: ${outputPath}`);
88
+ for (const file of files) {
89
+ const outputPath = join(__dirname, file.path);
90
+ mkdirSync(dirname(outputPath), { recursive: true });
91
+ writeFileSync(outputPath, file.content);
92
+ console.log(`✓ ${generator.name}: ${outputPath}`);
93
+ }
75
94
  }
76
95
 
77
96
  // Generate curve constants
78
97
  console.log('\nGenerating curve constants...');
79
98
  await generateCurveConstants(bbBuildPath, outputDir);
80
99
 
81
- console.log('\nGeneration complete!');
100
+ console.log('\n✨ Generation complete! Clean, maintainable, multi-language architecture.');
82
101
  }
83
102
 
84
103
  async function generateCurveConstants(bbBuildPath: string, outputDir: string) {
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared naming utilities for code generators
3
+ */
4
+
5
+ /**
6
+ * Convert camelCase or PascalCase to snake_case
7
+ * @example toSnakeCase("Blake2s") -> "blake2s"
8
+ * @example toSnakeCase("poseidonHash") -> "poseidon_hash"
9
+ */
10
+ export function toSnakeCase(name: string): string {
11
+ return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
12
+ }
13
+
14
+ /**
15
+ * Convert snake_case to PascalCase
16
+ * @example toPascalCase("blake2s") -> "Blake2s"
17
+ * @example toPascalCase("poseidon_hash") -> "PoseidonHash"
18
+ */
19
+ export function toPascalCase(name: string): string {
20
+ // Already PascalCase (no underscores and starts with uppercase)
21
+ if (!name.includes('_') && name[0] === name[0].toUpperCase()) {
22
+ return name;
23
+ }
24
+ return name.split('_').map(part =>
25
+ part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()
26
+ ).join('');
27
+ }
@@ -0,0 +1,504 @@
1
+ /**
2
+ * Rust Code Generator - String template based
3
+ *
4
+ * Philosophy:
5
+ * - String templates for file structure
6
+ * - Simple type mapping
7
+ * - Idiomatic Rust conventions
8
+ * - No complex abstraction
9
+ */
10
+
11
+ import type { CompiledSchema, Type, Struct, Field } from './schema_visitor.js';
12
+ import { toSnakeCase, toPascalCase } from './naming.js';
13
+
14
+ export class RustCodegen {
15
+ // Type mapping: Schema type -> Rust type
16
+ private mapType(type: Type): string {
17
+ switch (type.kind) {
18
+ case 'primitive':
19
+ switch (type.primitive) {
20
+ case 'bool': return 'bool';
21
+ case 'u8': return 'u8';
22
+ case 'u16': return 'u16';
23
+ case 'u32': return 'u32';
24
+ case 'u64': return 'u64';
25
+ case 'f64': return 'f64';
26
+ case 'string': return 'String';
27
+ case 'bytes': return 'Vec<u8>';
28
+ case 'field2': return '[Vec<u8>; 2]'; // Extension field (Fq2) - pair of 32-byte field elements
29
+ }
30
+ break;
31
+
32
+ case 'vector':
33
+ return `Vec<${this.mapType(type.element!)}>`;
34
+
35
+ case 'array':
36
+ const elemType = this.mapType(type.element!);
37
+ // Large arrays become Vec for ergonomics
38
+ return type.size! > 32 ? `Vec<${elemType}>` : `[${elemType}; ${type.size}]`;
39
+
40
+ case 'optional':
41
+ return `Option<${this.mapType(type.element!)}>`;
42
+
43
+ case 'struct':
44
+ // Convert struct names to PascalCase for Rust conventions
45
+ return toPascalCase(type.struct!.name);
46
+ }
47
+
48
+ return 'Unknown';
49
+ }
50
+
51
+ // Check if field needs serde(with = "serde_bytes")
52
+ private needsSerdeBytes(type: Type): boolean {
53
+ return type.kind === 'primitive' && type.primitive === 'bytes';
54
+ }
55
+
56
+ // Check if field needs serde(with = "serde_vec_bytes")
57
+ private needsSerdeVecBytes(type: Type): boolean {
58
+ return type.kind === 'vector' && this.needsSerdeBytes(type.element!);
59
+ }
60
+
61
+ // Check if field needs serde(with = "serde_array4_bytes") - for [Vec<u8>; 4] (Poseidon2 state)
62
+ private needsSerdeArray4Bytes(type: Type): boolean {
63
+ return type.kind === 'array' && type.size === 4 && this.needsSerdeBytes(type.element!);
64
+ }
65
+
66
+ // Generate struct field
67
+ private generateField(field: Field): string {
68
+ const rustName = toSnakeCase(field.name);
69
+ const rustType = this.mapType(field.type);
70
+ let attrs = '';
71
+
72
+ // Add serde rename if needed
73
+ if (field.name !== rustName) {
74
+ attrs += ` #[serde(rename = "${field.name}")]\n`;
75
+ }
76
+
77
+ // Add serde bytes handling
78
+ if (this.needsSerdeArray4Bytes(field.type)) {
79
+ attrs += ` #[serde(with = "serde_array4_bytes")]\n`;
80
+ } else if (this.needsSerdeVecBytes(field.type)) {
81
+ attrs += ` #[serde(with = "serde_vec_bytes")]\n`;
82
+ } else if (this.needsSerdeBytes(field.type)) {
83
+ attrs += ` #[serde(with = "serde_bytes")]\n`;
84
+ }
85
+
86
+ return `${attrs} pub ${rustName}: ${rustType},`;
87
+ }
88
+
89
+ // Generate a struct definition
90
+ private generateStruct(struct: Struct, isCommand: boolean): string {
91
+ const rustName = toPascalCase(struct.name);
92
+ const fields = struct.fields.map(f => this.generateField(f)).join('\n');
93
+
94
+ // Add serde rename if struct name changed
95
+ const serdeRename = struct.name !== rustName
96
+ ? `\n#[serde(rename = "${struct.name}")]`
97
+ : '';
98
+
99
+ // Commands need __typename field for struct identification, but skip it during serialization
100
+ const typenameField = isCommand
101
+ ? ` #[serde(rename = "__typename", skip_serializing)]\n pub type_name: String,\n`
102
+ : '';
103
+
104
+ // Generate constructor for commands
105
+ const constructor = isCommand ? this.generateConstructor(struct, rustName) : '';
106
+
107
+ return `/// ${struct.name}
108
+ #[derive(Debug, Clone, Serialize, Deserialize)]${serdeRename}
109
+ pub struct ${rustName} {
110
+ ${typenameField}${fields}
111
+ }${constructor}`;
112
+ }
113
+
114
+ // Generate constructor for command structs
115
+ private generateConstructor(struct: Struct, rustName: string): string {
116
+ const params = struct.fields.map(f =>
117
+ `${toSnakeCase(f.name)}: ${this.mapType(f.type)}`
118
+ ).join(', ');
119
+
120
+ const fieldInits = [
121
+ ` type_name: "${struct.name}".to_string(),`,
122
+ ...struct.fields.map(f => ` ${toSnakeCase(f.name)},`),
123
+ ].join('\n');
124
+
125
+ return `
126
+
127
+ impl ${rustName} {
128
+ pub fn new(${params}) -> Self {
129
+ Self {
130
+ ${fieldInits}
131
+ }
132
+ }
133
+ }`;
134
+ }
135
+
136
+ // Generate Command enum
137
+ private generateCommandEnum(schema: CompiledSchema): string {
138
+ const names = Array.from(schema.structs.keys());
139
+ const variants = names
140
+ .map(name => {
141
+ const rustName = toPascalCase(name);
142
+ return ` ${rustName}(${rustName}),`;
143
+ })
144
+ .join('\n');
145
+
146
+ const serializeCases = names
147
+ .map(name => {
148
+ const rustName = toPascalCase(name);
149
+ return ` Command::${rustName}(data) => {
150
+ tuple.serialize_element("${name}")?;
151
+ tuple.serialize_element(data)?;
152
+ }`;
153
+ })
154
+ .join('\n');
155
+
156
+ const deserializeCases = names
157
+ .map(name => {
158
+ const rustName = toPascalCase(name);
159
+ return ` "${name}" => {
160
+ let data = seq.next_element()?
161
+ .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
162
+ Ok(Command::${rustName}(data))
163
+ }`;
164
+ })
165
+ .join('\n');
166
+
167
+ const variantNames = names
168
+ .map(name => `"${name}"`)
169
+ .join(', ');
170
+
171
+ return `/// Command enum - wraps all possible commands
172
+ #[derive(Debug, Clone)]
173
+ pub enum Command {
174
+ ${variants}
175
+ }
176
+
177
+ impl Serialize for Command {
178
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
179
+ where S: serde::Serializer {
180
+ use serde::ser::SerializeTuple;
181
+ let mut tuple = serializer.serialize_tuple(2)?;
182
+ match self {
183
+ ${serializeCases}
184
+ }
185
+ tuple.end()
186
+ }
187
+ }
188
+
189
+ impl<'de> Deserialize<'de> for Command {
190
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
191
+ where D: serde::Deserializer<'de> {
192
+ use serde::de::{SeqAccess, Visitor};
193
+ struct CommandVisitor;
194
+
195
+ impl<'de> Visitor<'de> for CommandVisitor {
196
+ type Value = Command;
197
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
198
+ formatter.write_str("a 2-element array [name, payload]")
199
+ }
200
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
201
+ where A: SeqAccess<'de> {
202
+ let name: String = seq.next_element()?
203
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
204
+ match name.as_str() {
205
+ ${deserializeCases}
206
+ _ => Err(serde::de::Error::unknown_variant(&name, &[${variantNames}])),
207
+ }
208
+ }
209
+ }
210
+ deserializer.deserialize_tuple(2, CommandVisitor)
211
+ }
212
+ }`;
213
+ }
214
+
215
+ // Generate Response enum
216
+ private generateResponseEnum(schema: CompiledSchema): string {
217
+ // Include all response types from commands plus ErrorResponse if it exists
218
+ const commandResponseTypes = Array.from(new Set(schema.commands.map(c => c.responseType)));
219
+ const responseTypes = schema.responses.has('ErrorResponse')
220
+ ? [...commandResponseTypes, 'ErrorResponse']
221
+ : commandResponseTypes;
222
+ const variants = responseTypes
223
+ .map(name => {
224
+ const rustName = toPascalCase(name);
225
+ return ` ${rustName}(${rustName}),`;
226
+ })
227
+ .join('\n');
228
+
229
+ const serializeCases = responseTypes
230
+ .map(name => {
231
+ const rustName = toPascalCase(name);
232
+ return ` Response::${rustName}(data) => {
233
+ tuple.serialize_element("${name}")?;
234
+ tuple.serialize_element(data)?;
235
+ }`;
236
+ })
237
+ .join('\n');
238
+
239
+ const deserializeCases = responseTypes
240
+ .map(name => {
241
+ const rustName = toPascalCase(name);
242
+ return ` "${name}" => {
243
+ let data = seq.next_element()?
244
+ .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
245
+ Ok(Response::${rustName}(data))
246
+ }`;
247
+ })
248
+ .join('\n');
249
+
250
+ const variantNames = responseTypes.map(name => `"${name}"`).join(', ');
251
+
252
+ return `/// Response enum - wraps all possible responses
253
+ #[derive(Debug, Clone)]
254
+ pub enum Response {
255
+ ${variants}
256
+ }
257
+
258
+ impl Serialize for Response {
259
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
260
+ where S: serde::Serializer {
261
+ use serde::ser::SerializeTuple;
262
+ let mut tuple = serializer.serialize_tuple(2)?;
263
+ match self {
264
+ ${serializeCases}
265
+ }
266
+ tuple.end()
267
+ }
268
+ }
269
+
270
+ impl<'de> Deserialize<'de> for Response {
271
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
272
+ where D: serde::Deserializer<'de> {
273
+ use serde::de::{SeqAccess, Visitor};
274
+ struct ResponseVisitor;
275
+
276
+ impl<'de> Visitor<'de> for ResponseVisitor {
277
+ type Value = Response;
278
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
279
+ formatter.write_str("a 2-element array [name, payload]")
280
+ }
281
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
282
+ where A: SeqAccess<'de> {
283
+ let name: String = seq.next_element()?
284
+ .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
285
+ match name.as_str() {
286
+ ${deserializeCases}
287
+ _ => Err(serde::de::Error::unknown_variant(&name, &[${variantNames}])),
288
+ }
289
+ }
290
+ }
291
+ deserializer.deserialize_tuple(2, ResponseVisitor)
292
+ }
293
+ }`;
294
+ }
295
+
296
+ // Generate serde helper modules
297
+ private generateSerdeHelpers(): string {
298
+ return `mod serde_bytes {
299
+ use serde::{Deserialize, Deserializer, Serializer};
300
+ pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
301
+ where S: Serializer { serializer.serialize_bytes(bytes) }
302
+ pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
303
+ where D: Deserializer<'de> { <Vec<u8>>::deserialize(deserializer) }
304
+ }
305
+
306
+ mod serde_vec_bytes {
307
+ use serde::{Deserialize, Deserializer, Serializer, Serialize};
308
+ use serde::ser::SerializeSeq;
309
+ use serde::de::{SeqAccess, Visitor};
310
+
311
+ #[derive(Serialize, Deserialize)]
312
+ struct BytesWrapper(#[serde(with = "super::serde_bytes")] Vec<u8>);
313
+
314
+ pub fn serialize<S>(vec: &Vec<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
315
+ where S: Serializer {
316
+ let mut seq = serializer.serialize_seq(Some(vec.len()))?;
317
+ for bytes in vec {
318
+ seq.serialize_element(&BytesWrapper(bytes.clone()))?;
319
+ }
320
+ seq.end()
321
+ }
322
+ pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
323
+ where D: Deserializer<'de> {
324
+ struct VecVecU8Visitor;
325
+ impl<'de> Visitor<'de> for VecVecU8Visitor {
326
+ type Value = Vec<Vec<u8>>;
327
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
328
+ formatter.write_str("a sequence of byte arrays")
329
+ }
330
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
331
+ where A: SeqAccess<'de> {
332
+ let mut vec = Vec::new();
333
+ while let Some(wrapper) = seq.next_element::<BytesWrapper>()? {
334
+ vec.push(wrapper.0);
335
+ }
336
+ Ok(vec)
337
+ }
338
+ }
339
+ deserializer.deserialize_seq(VecVecU8Visitor)
340
+ }
341
+ }
342
+
343
+ mod serde_array4_bytes {
344
+ use serde::{Deserialize, Deserializer, Serialize, Serializer};
345
+ use serde::ser::SerializeTuple;
346
+ use serde::de::{SeqAccess, Visitor};
347
+
348
+ #[derive(Serialize, Deserialize)]
349
+ struct BytesWrapper(#[serde(with = "super::serde_bytes")] Vec<u8>);
350
+
351
+ pub fn serialize<S>(arr: &[Vec<u8>; 4], serializer: S) -> Result<S::Ok, S::Error>
352
+ where S: Serializer {
353
+ let mut tup = serializer.serialize_tuple(4)?;
354
+ for bytes in arr {
355
+ tup.serialize_element(&BytesWrapper(bytes.clone()))?;
356
+ }
357
+ tup.end()
358
+ }
359
+ pub fn deserialize<'de, D>(deserializer: D) -> Result<[Vec<u8>; 4], D::Error>
360
+ where D: Deserializer<'de> {
361
+ struct Array4Visitor;
362
+ impl<'de> Visitor<'de> for Array4Visitor {
363
+ type Value = [Vec<u8>; 4];
364
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
365
+ formatter.write_str("an array of 4 byte arrays")
366
+ }
367
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
368
+ where A: SeqAccess<'de> {
369
+ let mut arr: [Vec<u8>; 4] = Default::default();
370
+ for (i, item) in arr.iter_mut().enumerate() {
371
+ *item = seq.next_element::<BytesWrapper>()?
372
+ .ok_or_else(|| serde::de::Error::invalid_length(i, &self))?.0;
373
+ }
374
+ Ok(arr)
375
+ }
376
+ }
377
+ deserializer.deserialize_tuple(4, Array4Visitor)
378
+ }
379
+ }`;
380
+ }
381
+
382
+ // Generate types file
383
+ generateTypes(schema: CompiledSchema): string {
384
+ // Create set of top-level command struct names (only these need __typename)
385
+ const commandNames = new Set(schema.commands.map(c => c.name));
386
+
387
+ // Generate all structs (commands first, then responses)
388
+ const commandStructs = Array.from(schema.structs.values())
389
+ .map(s => this.generateStruct(s, commandNames.has(s.name)))
390
+ .join('\n\n');
391
+
392
+ const responseStructs = Array.from(schema.responses.values())
393
+ .map(s => this.generateStruct(s, false))
394
+ .join('\n\n');
395
+
396
+ return `//! AUTOGENERATED - DO NOT EDIT
397
+ //! Generated from Barretenberg msgpack schema
398
+
399
+ use serde::{Deserialize, Serialize};
400
+
401
+ ${this.generateSerdeHelpers()}
402
+
403
+ ${commandStructs}
404
+
405
+ ${responseStructs}
406
+
407
+ ${this.generateCommandEnum(schema)}
408
+
409
+ ${this.generateResponseEnum(schema)}
410
+ `;
411
+ }
412
+
413
+ // Generate API method
414
+ private generateApiMethod(command: {name: string, fields: Field[], responseType: string}): string {
415
+ const methodName = toSnakeCase(command.name);
416
+ const cmdRustName = toPascalCase(command.name);
417
+ const respRustName = toPascalCase(command.responseType);
418
+
419
+ const params = command.fields.map(f => {
420
+ const rustType = this.mapType(f.type);
421
+ // Only convert simple Vec<u8> to &[u8], not nested types
422
+ const apiType = rustType === 'Vec<u8>' ? '&[u8]' : rustType;
423
+ return `${toSnakeCase(f.name)}: ${apiType}`;
424
+ }).join(', ');
425
+
426
+ const paramConversions = command.fields.map(f => {
427
+ const name = toSnakeCase(f.name);
428
+ const rustType = this.mapType(f.type);
429
+ // Only convert slices back to Vec
430
+ if (rustType === 'Vec<u8>') {
431
+ return `${name}.to_vec()`;
432
+ }
433
+ return name;
434
+ }).join(', ');
435
+
436
+ return ` /// Execute ${command.name} command
437
+ pub fn ${methodName}(&mut self, ${params}) -> Result<${respRustName}> {
438
+ let cmd = Command::${cmdRustName}(${cmdRustName}::new(${paramConversions}));
439
+ match self.execute(cmd)? {
440
+ Response::${respRustName}(resp) => Ok(resp),
441
+ Response::ErrorResponse(err) => Err(BarretenbergError::Backend(
442
+ err.message
443
+ )),
444
+ _ => Err(BarretenbergError::InvalidResponse(
445
+ "Expected ${command.responseType}".to_string()
446
+ )),
447
+ }
448
+ }`;
449
+ }
450
+
451
+ // Generate API file
452
+ generateApi(schema: CompiledSchema): string {
453
+ const apiMethods = schema.commands
454
+ .filter(c => c.name !== 'Shutdown')
455
+ .map(c => this.generateApiMethod(c))
456
+ .join('\n\n');
457
+
458
+ return `//! AUTOGENERATED - DO NOT EDIT
459
+ //! High-level Barretenberg API - msgpack details hidden
460
+
461
+ use crate::backend::Backend;
462
+ use crate::error::{BarretenbergError, Result};
463
+ use crate::generated_types::*;
464
+
465
+ /// High-level Barretenberg API
466
+ pub struct BarretenbergApi<B: Backend> {
467
+ backend: B,
468
+ }
469
+
470
+ impl<B: Backend> BarretenbergApi<B> {
471
+ /// Create API with custom backend
472
+ pub fn new(backend: B) -> Self {
473
+ Self { backend }
474
+ }
475
+
476
+ fn execute(&mut self, command: Command) -> Result<Response> {
477
+ let input_buffer = rmp_serde::to_vec_named(&vec![command])
478
+ .map_err(|e| BarretenbergError::Serialization(e.to_string()))?;
479
+
480
+ let output_buffer = self.backend.call(&input_buffer)?;
481
+
482
+ let response: Response = rmp_serde::from_slice(&output_buffer)
483
+ .map_err(|e| BarretenbergError::Deserialization(e.to_string()))?;
484
+
485
+ Ok(response)
486
+ }
487
+
488
+ ${apiMethods}
489
+
490
+ /// Shutdown backend gracefully
491
+ pub fn shutdown(&mut self) -> Result<()> {
492
+ let cmd = Command::Shutdown(Shutdown::new());
493
+ let _ = self.execute(cmd)?;
494
+ self.backend.destroy()
495
+ }
496
+
497
+ /// Destroy backend without shutdown command
498
+ pub fn destroy(&mut self) -> Result<()> {
499
+ self.backend.destroy()
500
+ }
501
+ }
502
+ `;
503
+ }
504
+ }