1use std::future::Future;
2use std::num::NonZeroU64;
3use std::pin::Pin;
4
5use bitflags::bitflags;
6use rmpv::Value;
7use rpc_runtime_errors::RuntimeError;
8use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10
11pub const RUNTIME_PROTOCOL_VERSION: u32 = 1;
12
13pub type BoxRpcFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
16#[repr(u8)]
17pub enum MessageKind {
18 Hello = 1,
19 HelloAck = 2,
20 Request = 3,
21 ResponseOk = 4,
22 ResponseError = 5,
23 Notification = 6,
24 Cancel = 7,
25 Goodbye = 8,
26}
27
28impl MessageKind {
29 pub const fn as_u8(self) -> u8 {
30 self as u8
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
35#[repr(u8)]
36pub enum Role {
37 Client = 1,
38 Server = 2,
39 Peer = 3,
40}
41
42impl Role {
43 pub const fn as_u8(self) -> u8 {
44 self as u8
45 }
46}
47
48bitflags! {
49 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
50 pub struct CapabilityFlags: u64 {
51 const SERVER_TO_CLIENT_NOTIFICATION = 1 << 0;
52 const NAMED_INSTANCE_RESOLUTION = 1 << 1;
53 const SERVICE_ACTIVATION = 1 << 2;
54 const GOODBYE = 1 << 3;
55 const CANCEL_RESERVED = 1 << 4;
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
60pub struct RequestId(u64);
61
62impl RequestId {
63 pub const fn new(value: u64) -> Self {
64 Self(value)
65 }
66
67 pub const fn get(self) -> u64 {
68 self.0
69 }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
73pub struct InstanceId(NonZeroU64);
74
75impl InstanceId {
76 pub fn new(value: u64) -> Option<Self> {
77 NonZeroU64::new(value).map(Self)
78 }
79
80 pub const fn get(self) -> u64 {
81 self.0.get()
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
86pub struct MethodId(u32);
87
88impl MethodId {
89 pub const fn new(value: u32) -> Self {
90 Self(value)
91 }
92
93 pub const fn get(self) -> u32 {
94 self.0
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
99pub struct NotificationId(u32);
100
101impl NotificationId {
102 pub const fn new(value: u32) -> Self {
103 Self(value)
104 }
105
106 pub const fn get(self) -> u32 {
107 self.0
108 }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
112pub struct ServiceGuid(Uuid);
113
114impl ServiceGuid {
115 pub const fn new(value: Uuid) -> Self {
116 Self(value)
117 }
118
119 pub const fn get(self) -> Uuid {
120 self.0
121 }
122}
123
124#[derive(Debug, Clone, PartialEq)]
125pub enum Envelope {
126 Hello(Hello),
127 HelloAck(HelloAck),
128 Request(Request),
129 ResponseOk(ResponseOk),
130 ResponseError(ResponseError),
131 Notification(Notification),
132 Goodbye(Goodbye),
133}
134
135pub type Options = Vec<(String, Value)>;
136pub type Payload = Value;
137
138#[derive(Debug, Clone, PartialEq)]
139pub struct Hello {
140 pub protocol_version: u32,
141 pub role: Role,
142 pub capability_bits: CapabilityFlags,
143 pub max_message_size: u64,
144 pub options: Options,
145}
146
147#[derive(Debug, Clone, PartialEq)]
148pub struct HelloAck {
149 pub protocol_version: u32,
150 pub accepted_capability_bits: CapabilityFlags,
151 pub max_message_size: u64,
152 pub options: Options,
153}
154
155#[derive(Debug, Clone, PartialEq)]
156pub struct Request {
157 pub request_id: RequestId,
158 pub instance_id: InstanceId,
159 pub method_id: MethodId,
160 pub payload: Payload,
161}
162
163#[derive(Debug, Clone, PartialEq)]
164pub struct ResponseOk {
165 pub request_id: RequestId,
166 pub payload: Payload,
167}
168
169#[derive(Debug, Clone, PartialEq)]
170pub struct ResponseError {
171 pub request_id: RequestId,
172 pub error_code: i32,
173 pub error_kind: u8,
174 pub error_message: Option<String>,
175 pub error_details: Payload,
176}
177
178#[derive(Debug, Clone, PartialEq)]
179pub struct Notification {
180 pub instance_id: Option<InstanceId>,
181 pub notification_id: NotificationId,
182 pub payload: Payload,
183}
184
185#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct Goodbye {
187 pub reason_code: u32,
188 pub message: Option<String>,
189}
190
191pub trait Dispatcher: Send + Sync {
192 fn dispatch<'a>(
193 &'a self,
194 request: Request,
195 ) -> BoxRpcFuture<'a, Result<ResponseOk, RuntimeError>>;
196}
197
198pub trait NotificationSink: Send + Sync {
199 fn notify<'a>(
200 &'a self,
201 notification: Notification,
202 ) -> BoxRpcFuture<'a, Result<(), RuntimeError>>;
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn message_kind_values_are_stable() {
211 assert_eq!(MessageKind::Hello.as_u8(), 1);
212 assert_eq!(MessageKind::HelloAck.as_u8(), 2);
213 assert_eq!(MessageKind::Request.as_u8(), 3);
214 assert_eq!(MessageKind::ResponseOk.as_u8(), 4);
215 assert_eq!(MessageKind::ResponseError.as_u8(), 5);
216 assert_eq!(MessageKind::Notification.as_u8(), 6);
217 assert_eq!(MessageKind::Cancel.as_u8(), 7);
218 assert_eq!(MessageKind::Goodbye.as_u8(), 8);
219 }
220
221 #[test]
222 fn role_values_are_stable() {
223 assert_eq!(Role::Client.as_u8(), 1);
224 assert_eq!(Role::Server.as_u8(), 2);
225 assert_eq!(Role::Peer.as_u8(), 3);
226 }
227
228 #[test]
229 fn capability_bit_values_are_stable() {
230 assert_eq!(CapabilityFlags::SERVER_TO_CLIENT_NOTIFICATION.bits(), 1);
231 assert_eq!(CapabilityFlags::NAMED_INSTANCE_RESOLUTION.bits(), 2);
232 assert_eq!(CapabilityFlags::SERVICE_ACTIVATION.bits(), 4);
233 assert_eq!(CapabilityFlags::GOODBYE.bits(), 8);
234 assert_eq!(CapabilityFlags::CANCEL_RESERVED.bits(), 16);
235 }
236
237 #[test]
238 fn instance_id_rejects_zero() {
239 assert_eq!(InstanceId::new(0), None);
240 assert_eq!(InstanceId::new(7).map(InstanceId::get), Some(7));
241 }
242}