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