Skip to main content

vox_types/
services.rs

1use facet::{Facet, Shape};
2
3/// Static descriptor for a vox RPC service.
4///
5/// Contains the service name and all method descriptors. Built once per service
6/// via OnceLock in macro-generated code.
7pub struct ServiceDescriptor {
8    /// Service name (e.g., "Calculator").
9    pub service_name: &'static str,
10
11    /// All methods in this service.
12    pub methods: &'static [&'static MethodDescriptor],
13
14    /// Documentation string, if any.
15    pub doc: Option<&'static str>,
16}
17
18impl ServiceDescriptor {
19    /// Look up a method descriptor by method ID.
20    pub fn by_id(&self, method_id: MethodId) -> Option<&'static MethodDescriptor> {
21        self.methods.iter().find(|m| m.id == method_id).copied()
22    }
23}
24
25/// Static descriptor for a single RPC method.
26///
27/// Contains static metadata needed for dispatching and calling this method.
28pub struct MethodDescriptor {
29    /// Method ID (hash of service name, method name, arg shapes, return shape).
30    pub id: MethodId,
31
32    /// Service name (e.g., "Calculator").
33    pub service_name: &'static str,
34
35    /// Method name (e.g., "add").
36    pub method_name: &'static str,
37
38    /// Args type shape
39    pub args_shape: &'static Shape,
40
41    /// Arguments in declaration order.
42    pub args: &'static [ArgDescriptor],
43
44    /// Return type shape.
45    pub return_shape: &'static Shape,
46
47    /// Whether `args_shape` reaches a channel (Tx/Rx) anywhere in its tree.
48    /// Computed once via `shape_contains_channel` when the descriptor is
49    /// built, so the driver's cancel/failure paths can short-circuit
50    /// instead of re-walking the shape per request.
51    pub args_have_channels: bool,
52
53    /// Static retry policy for this method.
54    pub retry: RetryPolicy,
55
56    /// Documentation string, if any.
57    pub doc: Option<&'static str>,
58}
59
60impl std::fmt::Debug for MethodDescriptor {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        f.debug_struct("MethodDescriptor")
63            .field("id", &self.id)
64            .field("service_name", &self.service_name)
65            .field("method_name", &self.method_name)
66            .field("retry", &self.retry)
67            .finish_non_exhaustive()
68    }
69}
70
71/// Static retry policy for a method.
72#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
73pub struct RetryPolicy {
74    /// Whether an admitted operation must persist once started.
75    pub persist: bool,
76
77    /// Whether re-executing the same logical operation is semantically safe.
78    pub idem: bool,
79}
80
81impl RetryPolicy {
82    pub const VOLATILE: Self = Self {
83        persist: false,
84        idem: false,
85    };
86
87    pub const IDEM: Self = Self {
88        persist: false,
89        idem: true,
90    };
91
92    pub const PERSIST: Self = Self {
93        persist: true,
94        idem: false,
95    };
96
97    pub const PERSIST_IDEM: Self = Self {
98        persist: true,
99        idem: true,
100    };
101}
102
103declare_id!(
104    /// A unique method identifier — hash of service name, method name, arg shapes, return shape
105    MethodId, u64
106);
107
108/// Descriptor for a single RPC method argument.
109///
110/// Contains metadata about an argument including its name, shape, and
111/// whether it's a channel type (Rx/Tx).
112#[derive(Debug)]
113pub struct ArgDescriptor {
114    /// Argument name (e.g., "user_id", "stream").
115    pub name: &'static str,
116
117    /// Argument type shape.
118    pub shape: &'static Shape,
119}
120
121impl ServiceDescriptor {
122    /// An empty service descriptor for dispatchers that don't serve any methods.
123    pub const EMPTY: ServiceDescriptor = ServiceDescriptor {
124        service_name: "<Empty>",
125        methods: &[],
126        doc: None,
127    };
128}