capnweb_core/protocol/
ids.rs1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(transparent)]
10pub struct ImportId(pub i64);
11
12impl ImportId {
13 pub fn main() -> Self {
15 ImportId(0)
16 }
17
18 pub fn is_main(&self) -> bool {
20 self.0 == 0
21 }
22
23 pub fn is_local(&self) -> bool {
25 self.0 > 0
26 }
27
28 pub fn is_remote(&self) -> bool {
30 self.0 < 0
31 }
32
33 pub fn to_export_id(&self) -> ExportId {
35 ExportId(-self.0)
36 }
37}
38
39impl fmt::Display for ImportId {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 write!(f, "Import#{}", self.0)
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
50#[serde(transparent)]
51pub struct ExportId(pub i64);
52
53impl ExportId {
54 pub fn main() -> Self {
56 ExportId(0)
57 }
58
59 pub fn is_main(&self) -> bool {
61 self.0 == 0
62 }
63
64 pub fn is_local(&self) -> bool {
66 self.0 < 0
67 }
68
69 pub fn is_remote(&self) -> bool {
71 self.0 > 0
72 }
73
74 pub fn to_import_id(&self) -> ImportId {
76 ImportId(-self.0)
77 }
78}
79
80impl fmt::Display for ExportId {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "Export#{}", self.0)
83 }
84}
85
86#[derive(Debug)]
88pub struct IdAllocator {
89 next_positive: std::sync::atomic::AtomicI64,
90 next_negative: std::sync::atomic::AtomicI64,
91}
92
93impl IdAllocator {
94 pub fn new() -> Self {
96 Self {
97 next_positive: std::sync::atomic::AtomicI64::new(1),
98 next_negative: std::sync::atomic::AtomicI64::new(-1),
99 }
100 }
101
102 pub fn allocate_import(&self) -> ImportId {
104 let id = self
105 .next_positive
106 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
107 ImportId(id)
108 }
109
110 pub fn allocate_export(&self) -> ExportId {
112 let id = self
113 .next_negative
114 .fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
115 ExportId(id)
116 }
117
118 pub fn register_remote_import(&self, id: i64) -> ImportId {
120 ImportId(id)
122 }
123
124 pub fn register_remote_export(&self, id: i64) -> ExportId {
126 ExportId(id)
128 }
129}
130
131impl Default for IdAllocator {
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_main_ids() {
143 let import = ImportId::main();
144 let export = ExportId::main();
145
146 assert!(import.is_main());
147 assert!(export.is_main());
148 assert_eq!(import.0, 0);
149 assert_eq!(export.0, 0);
150 }
151
152 #[test]
153 fn test_local_remote_detection() {
154 let local_import = ImportId(5);
155 let remote_import = ImportId(-3);
156 let local_export = ExportId(-2);
157 let remote_export = ExportId(4);
158
159 assert!(local_import.is_local());
160 assert!(!local_import.is_remote());
161
162 assert!(!remote_import.is_local());
163 assert!(remote_import.is_remote());
164
165 assert!(local_export.is_local());
166 assert!(!local_export.is_remote());
167
168 assert!(!remote_export.is_local());
169 assert!(remote_export.is_remote());
170 }
171
172 #[test]
173 fn test_id_conversion() {
174 let import = ImportId(5);
175 let export = import.to_export_id();
176 assert_eq!(export, ExportId(-5));
177
178 let import2 = export.to_import_id();
179 assert_eq!(import2, ImportId(5));
180 }
181
182 #[test]
183 fn test_id_allocator() {
184 let allocator = IdAllocator::new();
185
186 let import1 = allocator.allocate_import();
188 let import2 = allocator.allocate_import();
189 assert_eq!(import1, ImportId(1));
190 assert_eq!(import2, ImportId(2));
191
192 let export1 = allocator.allocate_export();
194 let export2 = allocator.allocate_export();
195 assert_eq!(export1, ExportId(-1));
196 assert_eq!(export2, ExportId(-2));
197
198 let remote_import = allocator.register_remote_import(-5);
200 let remote_export = allocator.register_remote_export(7);
201 assert_eq!(remote_import, ImportId(-5));
202 assert_eq!(remote_export, ExportId(7));
203 }
204
205 #[test]
206 fn test_display() {
207 let import = ImportId(42);
208 let export = ExportId(-17);
209
210 assert_eq!(format!("{}", import), "Import#42");
211 assert_eq!(format!("{}", export), "Export#-17");
212 }
213}