Skip to main content

moonpool_transport/rpc/
interface.rs

1//! FDB-style Interface pattern support.
2//!
3//! This module provides traits and helpers for working with interfaces
4//! generated by `#[derive(Interface)]`.
5//!
6//! # Overview
7//!
8//! The Interface pattern bundles multiple RPC methods into a single unit:
9//!
10//! - **Server-side**: `{Name}Server<C>` struct with `RequestStream` fields
11//! - **Client-side**: `{Name}Client` struct with method accessors
12//!
13//! # Example
14//!
15//! ```rust,ignore
16//! use moonpool_transport::Interface;
17//!
18//! #[derive(Interface)]
19//! #[interface(id = 0xCA1C_0000)]
20//! struct Calculator {
21//!     add: (AddRequest, AddResponse),
22//!     sub: (SubRequest, SubResponse),
23//! }
24//!
25//! // Server
26//! let calc = CalculatorServer::init(&transport, JsonCodec);
27//!
28//! // Client
29//! let calc = CalculatorClient::new(server_addr);
30//! send_request(&transport, &calc.add(), request, JsonCodec)?;
31//! ```
32//!
33//! # Serialization
34//!
35//! Client interfaces serialize only the base endpoint. Method endpoints
36//! are derived using `Endpoint::adjusted()`, following FoundationDB's pattern.
37
38use crate::{Endpoint, UID};
39
40/// Generate method endpoint from base endpoint and index.
41///
42/// Uses FDB's adjustment pattern via `Endpoint::adjusted()`.
43///
44/// # Example
45///
46/// ```rust,ignore
47/// let base = Endpoint::new(addr, UID::new(0xCA1C, 0));
48/// let add_endpoint = method_endpoint(&base, 0);
49/// let sub_endpoint = method_endpoint(&base, 1);
50/// ```
51pub fn method_endpoint(base: &Endpoint, method_index: u32) -> Endpoint {
52    base.adjusted(method_index)
53}
54
55/// Generate UID for a specific interface method.
56///
57/// # Example
58///
59/// ```rust,ignore
60/// let add_uid = method_uid(0xCA1C_0000, 0);
61/// let sub_uid = method_uid(0xCA1C_0000, 1);
62/// ```
63pub const fn method_uid(interface_id: u64, method_index: u32) -> UID {
64    UID::new(interface_id, method_index as u64)
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use crate::NetworkAddress;
71    use std::net::{IpAddr, Ipv4Addr};
72
73    #[test]
74    fn test_method_endpoint() {
75        let addr = NetworkAddress::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4500);
76        let base = Endpoint::new(addr, UID::new(0xCA1C_0000, 0));
77
78        let e0 = method_endpoint(&base, 0);
79        let e1 = method_endpoint(&base, 1);
80        let e2 = method_endpoint(&base, 2);
81
82        // All should have same address
83        assert_eq!(base.address, e0.address);
84        assert_eq!(base.address, e1.address);
85        assert_eq!(base.address, e2.address);
86
87        // Tokens should be different
88        assert_ne!(e0.token, e1.token);
89        assert_ne!(e1.token, e2.token);
90        assert_ne!(e0.token, e2.token);
91
92        // Method 0 should match base
93        assert_eq!(base.token, e0.token);
94    }
95
96    #[test]
97    fn test_method_uid() {
98        let interface_id = 0xCA1C_0000_u64;
99
100        let uid0 = method_uid(interface_id, 0);
101        let uid1 = method_uid(interface_id, 1);
102        let uid2 = method_uid(interface_id, 2);
103
104        assert_eq!(uid0, UID::new(interface_id, 0));
105        assert_eq!(uid1, UID::new(interface_id, 1));
106        assert_eq!(uid2, UID::new(interface_id, 2));
107
108        // All unique
109        assert_ne!(uid0, uid1);
110        assert_ne!(uid1, uid2);
111    }
112}