1use facet_core::{ScalarType, Shape, StructKind};
6use roam_schema::{
7 EnumInfo, ShapeKind, StructInfo, VariantKind, classify_shape, classify_variant, is_bytes,
8};
9
10use super::types::{ts_type_base_named, ts_type_client_return, ts_type_server_arg};
11
12pub fn generate_decode_stmt_client(
15 shape: &'static Shape,
16 var_name: &str,
17 offset_var: &str,
18) -> String {
19 match classify_shape(shape) {
20 ShapeKind::Tx { inner } => {
21 let inner_type = ts_type_client_return(inner);
25 format!(
26 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = {{ channelId: _{var_name}_r.value }} as Tx<{inner_type}>; {offset_var} = _{var_name}_r.next; /* TODO: create real Tx handle */"
27 )
28 }
29 ShapeKind::Rx { inner } => {
30 let inner_type = ts_type_client_return(inner);
34 format!(
35 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = {{ channelId: _{var_name}_r.value }} as Rx<{inner_type}>; {offset_var} = _{var_name}_r.next; /* TODO: create real Rx handle */"
36 )
37 }
38 _ => generate_decode_stmt(shape, var_name, offset_var),
40 }
41}
42
43pub fn generate_decode_stmt_server(
48 shape: &'static Shape,
49 var_name: &str,
50 offset_var: &str,
51) -> String {
52 match classify_shape(shape) {
53 ShapeKind::Tx { inner } => {
54 let inner_type = ts_type_server_arg(inner);
57 format!(
58 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = {{ channelId: _{var_name}_r.value }} as Tx<{inner_type}>; {offset_var} = _{var_name}_r.next; /* TODO: create real Tx handle */"
59 )
60 }
61 ShapeKind::Rx { inner } => {
62 let inner_type = ts_type_server_arg(inner);
65 format!(
66 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = {{ channelId: _{var_name}_r.value }} as Rx<{inner_type}>; {offset_var} = _{var_name}_r.next; /* TODO: create real Rx handle */"
67 )
68 }
69 _ => generate_decode_stmt(shape, var_name, offset_var),
71 }
72}
73
74pub fn generate_decode_stmt_server_streaming(
77 shape: &'static Shape,
78 var_name: &str,
79 offset_var: &str,
80 registry_var: &str,
81 task_sender_var: &str,
82) -> String {
83 match classify_shape(shape) {
84 ShapeKind::Tx { inner } => {
85 let inner_type = ts_type_server_arg(inner);
88 let encode_fn = super::encode::generate_encode_fn_inline(inner);
89 format!(
90 "const _{var_name}_r = decodeU64(buf, {offset_var}); \
91 const {var_name} = createServerTx<{inner_type}>(_{var_name}_r.value, {task_sender_var}, {encode_fn}); \
92 {offset_var} = _{var_name}_r.next;"
93 )
94 }
95 ShapeKind::Rx { inner } => {
96 let inner_type = ts_type_server_arg(inner);
99 let decode_fn = generate_decode_fn_inline(inner);
100 format!(
101 "const _{var_name}_r = decodeU64(buf, {offset_var}); \
102 const _{var_name}_receiver = {registry_var}.registerIncoming(_{var_name}_r.value); \
103 const {var_name} = createServerRx<{inner_type}>(_{var_name}_r.value, _{var_name}_receiver, {decode_fn}); \
104 {offset_var} = _{var_name}_r.next;"
105 )
106 }
107 _ => generate_decode_stmt(shape, var_name, offset_var),
109 }
110}
111
112pub fn generate_decode_stmt(shape: &'static Shape, var_name: &str, offset_var: &str) -> String {
117 if is_bytes(shape) {
119 return format!(
120 "const _{var_name}_r = decodeBytes(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
121 );
122 }
123
124 match classify_shape(shape) {
125 ShapeKind::Scalar(scalar) => decode_scalar_stmt(scalar, var_name, offset_var),
126 ShapeKind::List { element } => {
127 let decode_fn = generate_decode_fn(element, "item");
128 format!(
129 "const _{var_name}_r = decodeVec(buf, {offset_var}, {decode_fn}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
130 )
131 }
132 ShapeKind::Option { inner } => {
133 let decode_fn = generate_decode_fn(inner, "inner");
134 format!(
135 "const _{var_name}_r = decodeOption(buf, {offset_var}, {decode_fn}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
136 )
137 }
138 ShapeKind::Array { element, .. } | ShapeKind::Slice { element } => {
139 let decode_fn = generate_decode_fn(element, "item");
140 format!(
141 "const _{var_name}_r = decodeVec(buf, {offset_var}, {decode_fn}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
142 )
143 }
144 ShapeKind::Tuple { elements } if elements.len() == 2 => {
145 let decode_a = generate_decode_fn(elements[0].shape, "a");
146 let decode_b = generate_decode_fn(elements[1].shape, "b");
147 format!(
148 "const _{var_name}_r = decodeTuple2(buf, {offset_var}, {decode_a}, {decode_b}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
149 )
150 }
151 ShapeKind::Tuple { elements } if elements.len() == 3 => {
152 let decode_a = generate_decode_fn(elements[0].shape, "a");
153 let decode_b = generate_decode_fn(elements[1].shape, "b");
154 let decode_c = generate_decode_fn(elements[2].shape, "c");
155 format!(
156 "const _{var_name}_r = decodeTuple3(buf, {offset_var}, {decode_a}, {decode_b}, {decode_c}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
157 )
158 }
159 ShapeKind::Tuple { elements } => {
160 if elements.is_empty() {
161 return format!("const {var_name} = undefined;");
162 }
163 let mut code = format!("const {var_name}: [");
165 code.push_str(
166 &elements
167 .iter()
168 .map(|p| ts_type_base_named(p.shape))
169 .collect::<Vec<_>>()
170 .join(", "),
171 );
172 code.push_str("] = [] as any;\n");
173 for (i, param) in elements.iter().enumerate() {
174 let item_var = format!("{var_name}_{i}");
175 code.push_str(&generate_decode_stmt(param.shape, &item_var, offset_var));
176 code.push_str(&format!(" {var_name}[{i}] = {item_var};\n"));
177 }
178 code
179 }
180 ShapeKind::Struct(StructInfo { fields, kind, .. }) => {
181 if fields.is_empty() || kind == StructKind::Unit {
182 return format!("const {var_name} = undefined;");
183 }
184 let mut code = String::new();
185 for (i, field) in fields.iter().enumerate() {
186 let field_var = format!("{var_name}_f{i}");
187 code.push_str(&generate_decode_stmt(field.shape(), &field_var, offset_var));
188 code.push('\n');
189 }
190 code.push_str(&format!("const {var_name} = {{ "));
191 for (i, field) in fields.iter().enumerate() {
192 let field_var = format!("{var_name}_f{i}");
193 if i > 0 {
194 code.push_str(", ");
195 }
196 code.push_str(&format!("{}: {field_var}", field.name));
197 }
198 code.push_str(" };");
199 code
200 }
201 ShapeKind::Enum(EnumInfo { variants, .. }) => {
202 let mut code = format!(
203 "const _{var_name}_disc = decodeEnumVariant(buf, {offset_var}); {offset_var} = _{var_name}_disc.next;\n"
204 );
205 code.push_str(&format!("let {var_name}: {};\n", ts_type_base_named(shape)));
206 code.push_str(&format!("switch (_{var_name}_disc.value) {{\n"));
207 for (i, v) in variants.iter().enumerate() {
208 code.push_str(&format!(" case {i}: {{\n"));
209 match classify_variant(v) {
210 VariantKind::Unit => {
211 code.push_str(&format!(" {var_name} = {{ tag: '{}' }};\n", v.name));
212 }
213 VariantKind::Newtype { inner } => {
214 let inner_var = format!("{var_name}_inner");
215 code.push_str(&format!(
216 " {}\n",
217 generate_decode_stmt(inner, &inner_var, offset_var)
218 ));
219 code.push_str(&format!(
220 " {var_name} = {{ tag: '{}', value: {inner_var} }};\n",
221 v.name
222 ));
223 }
224 VariantKind::Tuple { fields } | VariantKind::Struct { fields } => {
225 for (fi, field) in fields.iter().enumerate() {
226 let field_var = format!("{var_name}_f{fi}");
227 code.push_str(&format!(
228 " {}\n",
229 generate_decode_stmt(field.shape(), &field_var, offset_var)
230 ));
231 }
232 code.push_str(&format!(" {var_name} = {{ tag: '{}'", v.name));
233 for (fi, field) in fields.iter().enumerate() {
234 let field_var = format!("{var_name}_f{fi}");
235 code.push_str(&format!(", {}: {field_var}", field.name));
236 }
237 code.push_str(" };\n");
238 }
239 }
240 code.push_str(" break;\n }\n");
241 }
242 code.push_str(&format!(
243 " default: throw new Error(`unknown enum variant ${{_{var_name}_disc.value}}`);\n}}"
244 ));
245 code
246 }
247 ShapeKind::Map { key, value } => {
248 let decode_k = generate_decode_fn(key, "k");
249 let decode_v = generate_decode_fn(value, "v");
250 format!(
251 "const _{var_name}_r = decodeVec(buf, {offset_var}, (buf, off) => {{ \
252 const kr = ({decode_k})(buf, off); \
253 const vr = ({decode_v})(buf, kr.next); \
254 return {{ value: [kr.value, vr.value] as [any, any], next: vr.next }}; \
255 }}); const {var_name} = new Map(_{var_name}_r.value); {offset_var} = _{var_name}_r.next;"
256 )
257 }
258 ShapeKind::Set { element } => {
259 let decode_fn = generate_decode_fn(element, "item");
260 format!(
261 "const _{var_name}_r = decodeVec(buf, {offset_var}, {decode_fn}); const {var_name} = new Set(_{var_name}_r.value); {offset_var} = _{var_name}_r.next;"
262 )
263 }
264 ShapeKind::Tx { inner } => {
265 let inner_type = ts_type_base_named(inner);
266 format!(
267 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = {{ channelId: _{var_name}_r.value }} as Tx<{inner_type}>; {offset_var} = _{var_name}_r.next;"
268 )
269 }
270 ShapeKind::Rx { inner } => {
271 let inner_type = ts_type_base_named(inner);
272 format!(
273 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = {{ channelId: _{var_name}_r.value }} as Rx<{inner_type}>; {offset_var} = _{var_name}_r.next;"
274 )
275 }
276 ShapeKind::Pointer { pointee } => generate_decode_stmt(pointee, var_name, offset_var),
277 ShapeKind::Result { .. } => {
278 format!("const {var_name} = undefined; /* Result type decoding not yet implemented */")
279 }
280 ShapeKind::TupleStruct { fields } => {
281 let mut stmts = Vec::new();
282 for (i, f) in fields.iter().enumerate() {
283 stmts.push(generate_decode_stmt(
284 f.shape(),
285 &format!("{var_name}_{i}"),
286 offset_var,
287 ));
288 }
289 let tuple_elements: Vec<String> = (0..fields.len())
290 .map(|i| format!("{var_name}_{i}"))
291 .collect();
292 let tuple_types: Vec<String> = fields
294 .iter()
295 .map(|f| ts_type_base_named(f.shape()))
296 .collect();
297 stmts.push(format!(
298 "const {var_name} = [{}] as [{}];",
299 tuple_elements.join(", "),
300 tuple_types.join(", ")
301 ));
302 stmts.join("\n")
303 }
304 ShapeKind::Opaque => format!("const {var_name} = undefined; /* unsupported type */"),
305 }
306}
307
308fn decode_scalar_stmt(scalar: ScalarType, var_name: &str, offset_var: &str) -> String {
310 match scalar {
311 ScalarType::Bool => format!(
312 "const _{var_name}_r = decodeBool(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
313 ),
314 ScalarType::U8 => format!(
315 "const _{var_name}_r = decodeU8(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
316 ),
317 ScalarType::I8 => format!(
318 "const _{var_name}_r = decodeI8(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
319 ),
320 ScalarType::U16 => format!(
321 "const _{var_name}_r = decodeU16(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
322 ),
323 ScalarType::I16 => format!(
324 "const _{var_name}_r = decodeI16(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
325 ),
326 ScalarType::U32 => format!(
327 "const _{var_name}_r = decodeU32(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
328 ),
329 ScalarType::I32 => format!(
330 "const _{var_name}_r = decodeI32(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
331 ),
332 ScalarType::U64 | ScalarType::USize => format!(
333 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
334 ),
335 ScalarType::I64 | ScalarType::ISize => format!(
336 "const _{var_name}_r = decodeI64(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
337 ),
338 ScalarType::U128 => format!(
339 "const _{var_name}_r = decodeU64(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
340 ),
341 ScalarType::I128 => format!(
342 "const _{var_name}_r = decodeI64(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
343 ),
344 ScalarType::F32 => format!(
345 "const _{var_name}_r = decodeF32(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
346 ),
347 ScalarType::F64 => format!(
348 "const _{var_name}_r = decodeF64(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
349 ),
350 ScalarType::Char | ScalarType::Str | ScalarType::String | ScalarType::CowStr => format!(
351 "const _{var_name}_r = decodeString(buf, {offset_var}); const {var_name} = _{var_name}_r.value; {offset_var} = _{var_name}_r.next;"
352 ),
353 ScalarType::Unit => format!("const {var_name} = undefined;"),
354 _ => format!("const {var_name} = undefined; /* unsupported scalar */"),
355 }
356}
357
358pub fn generate_decode_fn(shape: &'static Shape, _var_hint: &str) -> String {
360 if is_bytes(shape) {
362 return "(buf, off) => decodeBytes(buf, off)".into();
363 }
364
365 match classify_shape(shape) {
366 ShapeKind::Scalar(scalar) => decode_scalar_fn(scalar),
367 ShapeKind::List { element } => {
368 let inner_fn = generate_decode_fn(element, "item");
369 format!("(buf, off) => decodeVec(buf, off, {inner_fn})")
370 }
371 ShapeKind::Option { inner } => {
372 let inner_fn = generate_decode_fn(inner, "inner");
373 format!("(buf, off) => decodeOption(buf, off, {inner_fn})")
374 }
375 ShapeKind::Array { element, .. } | ShapeKind::Slice { element } => {
376 let inner_fn = generate_decode_fn(element, "item");
377 format!("(buf, off) => decodeVec(buf, off, {inner_fn})")
378 }
379 ShapeKind::Tuple { elements } if elements.len() == 2 => {
380 let a_fn = generate_decode_fn(elements[0].shape, "a");
381 let b_fn = generate_decode_fn(elements[1].shape, "b");
382 format!("(buf, off) => decodeTuple2(buf, off, {a_fn}, {b_fn})")
383 }
384 ShapeKind::Tuple { elements } if elements.len() == 3 => {
385 let a_fn = generate_decode_fn(elements[0].shape, "a");
386 let b_fn = generate_decode_fn(elements[1].shape, "b");
387 let c_fn = generate_decode_fn(elements[2].shape, "c");
388 format!("(buf, off) => decodeTuple3(buf, off, {a_fn}, {b_fn}, {c_fn})")
389 }
390 ShapeKind::Tuple { elements: [] } => {
391 "(buf, off) => ({ value: undefined, next: off })".into()
392 }
393 ShapeKind::Struct(StructInfo { fields, kind, .. }) => {
394 if fields.is_empty() || kind == StructKind::Unit {
395 return "(buf, off) => ({ value: undefined, next: off })".into();
396 }
397 let mut code = "(buf: Uint8Array, off: number) => { let o = off;\n".to_string();
399 for (i, f) in fields.iter().enumerate() {
400 code.push_str(&format!(
401 " {}\n",
402 generate_decode_stmt(f.shape(), &format!("f{i}"), "o")
403 ));
404 }
405 code.push_str(" return { value: { ");
406 for (i, f) in fields.iter().enumerate() {
407 if i > 0 {
408 code.push_str(", ");
409 }
410 code.push_str(&format!("{}: f{i}", f.name));
411 }
412 code.push_str(" }, next: o };\n}");
413 code
414 }
415 ShapeKind::Enum(EnumInfo { variants, .. }) => {
416 let mut code =
418 "(buf: Uint8Array, off: number): DecodeResult<any> => { let o = off;\n".to_string();
419 code.push_str(" const disc = decodeEnumVariant(buf, o); o = disc.next;\n");
420 code.push_str(" switch (disc.value) {\n");
421 for (i, v) in variants.iter().enumerate() {
422 code.push_str(&format!(" case {i}: "));
423 match classify_variant(v) {
424 VariantKind::Unit => {
425 code.push_str(&format!(
426 "return {{ value: {{ tag: '{}' }}, next: o }};\n",
427 v.name
428 ));
429 }
430 VariantKind::Newtype { inner } => {
431 code.push_str("{\n");
432 code.push_str(&format!(
433 " {}\n",
434 generate_decode_stmt(inner, "val", "o")
435 ));
436 code.push_str(&format!(
437 " return {{ value: {{ tag: '{}', value: val }}, next: o }};\n",
438 v.name
439 ));
440 code.push_str(" }\n");
441 }
442 VariantKind::Tuple { fields } | VariantKind::Struct { fields } => {
443 code.push_str("{\n");
444 for (j, f) in fields.iter().enumerate() {
445 code.push_str(&format!(
446 " {}\n",
447 generate_decode_stmt(f.shape(), &format!("f{j}"), "o")
448 ));
449 }
450 code.push_str(&format!(" return {{ value: {{ tag: '{}', ", v.name));
451 for (j, f) in fields.iter().enumerate() {
452 if j > 0 {
453 code.push_str(", ");
454 }
455 code.push_str(&format!("{}: f{j}", f.name));
456 }
457 code.push_str(" }, next: o };\n }\n");
458 }
459 }
460 }
461 code.push_str(
462 " default: throw new Error(`unknown enum variant: ${disc.value}`);\n }\n}",
463 );
464 code
465 }
466 ShapeKind::Pointer { pointee } => generate_decode_fn(pointee, _var_hint),
467 _ => "(buf, off) => { throw new Error('unsupported type'); }".into(),
468 }
469}
470
471fn decode_scalar_fn(scalar: ScalarType) -> String {
473 match scalar {
474 ScalarType::Bool => "(buf, off) => decodeBool(buf, off)".into(),
475 ScalarType::U8 => "(buf, off) => decodeU8(buf, off)".into(),
476 ScalarType::I8 => "(buf, off) => decodeI8(buf, off)".into(),
477 ScalarType::U16 => "(buf, off) => decodeU16(buf, off)".into(),
478 ScalarType::I16 => "(buf, off) => decodeI16(buf, off)".into(),
479 ScalarType::U32 => "(buf, off) => decodeU32(buf, off)".into(),
480 ScalarType::I32 => "(buf, off) => decodeI32(buf, off)".into(),
481 ScalarType::U64 | ScalarType::USize => "(buf, off) => decodeU64(buf, off)".into(),
482 ScalarType::I64 | ScalarType::ISize => "(buf, off) => decodeI64(buf, off)".into(),
483 ScalarType::U128 => "(buf, off) => decodeU64(buf, off)".into(),
484 ScalarType::I128 => "(buf, off) => decodeI64(buf, off)".into(),
485 ScalarType::F32 => "(buf, off) => decodeF32(buf, off)".into(),
486 ScalarType::F64 => "(buf, off) => decodeF64(buf, off)".into(),
487 ScalarType::Char | ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
488 "(buf, off) => decodeString(buf, off)".into()
489 }
490 ScalarType::Unit => "(buf, off) => ({ value: undefined, next: off })".into(),
491 _ => "(buf, off) => { throw new Error('unsupported scalar'); }".into(),
492 }
493}
494
495pub fn generate_decode_fn_inline(shape: &'static Shape) -> String {
497 if is_bytes(shape) {
499 return "(bytes: Uint8Array) => bytes".into();
500 }
501
502 match classify_shape(shape) {
503 ShapeKind::Scalar(scalar) => decode_scalar_fn_inline(scalar),
504 _ => {
505 let decode_fn = generate_decode_fn(shape, "v");
507 format!("(bytes: Uint8Array) => ({decode_fn})(bytes, 0).value")
508 }
509 }
510}
511
512fn decode_scalar_fn_inline(scalar: ScalarType) -> String {
514 match scalar {
515 ScalarType::Bool => "(bytes: Uint8Array) => decodeBool(bytes, 0).value".into(),
516 ScalarType::U8 => "(bytes: Uint8Array) => decodeU8(bytes, 0).value".into(),
517 ScalarType::I8 => "(bytes: Uint8Array) => decodeI8(bytes, 0).value".into(),
518 ScalarType::U16 => "(bytes: Uint8Array) => decodeU16(bytes, 0).value".into(),
519 ScalarType::I16 => "(bytes: Uint8Array) => decodeI16(bytes, 0).value".into(),
520 ScalarType::U32 => "(bytes: Uint8Array) => decodeU32(bytes, 0).value".into(),
521 ScalarType::I32 => "(bytes: Uint8Array) => decodeI32(bytes, 0).value".into(),
522 ScalarType::U64 | ScalarType::USize => {
523 "(bytes: Uint8Array) => decodeU64(bytes, 0).value".into()
524 }
525 ScalarType::I64 | ScalarType::ISize => {
526 "(bytes: Uint8Array) => decodeI64(bytes, 0).value".into()
527 }
528 ScalarType::F32 => "(bytes: Uint8Array) => decodeF32(bytes, 0).value".into(),
529 ScalarType::F64 => "(bytes: Uint8Array) => decodeF64(bytes, 0).value".into(),
530 ScalarType::Char | ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
531 "(bytes: Uint8Array) => decodeString(bytes, 0).value".into()
532 }
533 ScalarType::Unit => "(bytes: Uint8Array) => undefined".into(),
534 _ => "(bytes: Uint8Array) => undefined".into(),
535 }
536}