Skip to main content

vox_codegen/targets/
mod.rs

1pub mod java;
2pub mod swift;
3pub mod typescript;
4
5use facet_core::Shape;
6use vox_types::{ServiceDescriptor, ShapeKind, StructInfo, VariantKind, classify_shape};
7
8pub(crate) fn validate_no_fd_shapes(service: &ServiceDescriptor, target: &str) {
9    for method in service.methods {
10        for arg in method.args {
11            assert!(
12                !shape_contains_fd(arg.shape),
13                "{target} codegen does not support vox::Fd capabilities: {}.{} argument `{}` requires an fd-capable Rust/local transport",
14                method.service_name,
15                method.method_name,
16                arg.name
17            );
18            if let Some(element) = arg.channel_element {
19                assert!(
20                    !shape_contains_fd(element),
21                    "{target} codegen does not support vox::Fd channel items: {}.{} argument `{}` requires an fd-capable Rust/local transport",
22                    method.service_name,
23                    method.method_name,
24                    arg.name
25                );
26            }
27        }
28        assert!(
29            !shape_contains_fd(method.return_shape),
30            "{target} codegen does not support vox::Fd capabilities: {}.{} return type requires an fd-capable Rust/local transport",
31            method.service_name,
32            method.method_name
33        );
34    }
35}
36
37fn shape_contains_fd(shape: &'static Shape) -> bool {
38    let mut seen = std::collections::HashSet::new();
39    shape_contains_fd_inner(shape, &mut seen)
40}
41
42fn shape_contains_fd_inner(
43    shape: &'static Shape,
44    seen: &mut std::collections::HashSet<usize>,
45) -> bool {
46    if vox_types::is_fd(shape) {
47        return true;
48    }
49    if !seen.insert(shape as *const Shape as usize) {
50        return false;
51    }
52
53    match classify_shape(shape) {
54        ShapeKind::List { element }
55        | ShapeKind::Slice { element }
56        | ShapeKind::Option { inner: element }
57        | ShapeKind::Array { element, .. }
58        | ShapeKind::Set { element }
59        | ShapeKind::Tx { inner: element }
60        | ShapeKind::Rx { inner: element }
61        | ShapeKind::Pointer { pointee: element } => shape_contains_fd_inner(element, seen),
62        ShapeKind::Map { key, value } => {
63            shape_contains_fd_inner(key, seen) || shape_contains_fd_inner(value, seen)
64        }
65        ShapeKind::Tuple { elements } => elements
66            .iter()
67            .any(|param| shape_contains_fd_inner(param.shape, seen)),
68        ShapeKind::TupleStruct { fields } | ShapeKind::Struct(StructInfo { fields, .. }) => fields
69            .iter()
70            .any(|field| shape_contains_fd_inner(field.shape(), seen)),
71        ShapeKind::Enum(info) => {
72            info.variants
73                .iter()
74                .any(|variant| match vox_types::classify_variant(variant) {
75                    VariantKind::Unit => false,
76                    VariantKind::Newtype { inner } => shape_contains_fd_inner(inner, seen),
77                    VariantKind::Tuple { fields } | VariantKind::Struct { fields } => fields
78                        .iter()
79                        .any(|field| shape_contains_fd_inner(field.shape(), seen)),
80                })
81        }
82        ShapeKind::Result { ok, err } => {
83            shape_contains_fd_inner(ok, seen) || shape_contains_fd_inner(err, seen)
84        }
85        ShapeKind::Scalar(_) | ShapeKind::Opaque => false,
86    }
87}