Skip to main content

rpc_runtime_core/
lib.rs

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}