1use crate::{Interface, MessageGroup, NoMessage};
3
4use std::cmp::Ordering;
5
6pub const SERVER_ID_LIMIT: u32 = 0xFF00_0000;
8
9pub trait ObjectMetadata: Clone {
12 fn child(&self) -> Self;
16}
17
18impl ObjectMetadata for () {
19 fn child(&self) {}
20}
21
22#[derive(Clone)]
24pub struct Object<Meta: ObjectMetadata> {
25 pub interface: &'static str,
27 pub version: u32,
29 pub requests: &'static [crate::wire::MessageDesc],
31 pub events: &'static [crate::wire::MessageDesc],
33 pub meta: Meta,
35 pub childs_from_events: fn(u16, u32, &Meta) -> Option<Object<Meta>>,
38 pub childs_from_requests: fn(u16, u32, &Meta) -> Option<Object<Meta>>,
41}
42
43impl<Meta: ObjectMetadata + std::fmt::Debug> std::fmt::Debug for Object<Meta> {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 f.debug_struct("Object")
46 .field("interface", &self.interface)
47 .field("version", &self.version)
48 .field("requests", &self.requests)
49 .field("events", &self.events)
50 .field("meta", &self.meta)
51 .finish()
52 }
53}
54
55impl<Meta: ObjectMetadata> Object<Meta> {
56 pub fn from_interface<I: Interface>(version: u32, meta: Meta) -> Object<Meta> {
58 Object {
59 interface: I::NAME,
60 version,
61 requests: I::Request::MESSAGES,
62 events: I::Event::MESSAGES,
63 meta,
64 childs_from_events: childs_from::<I::Event, Meta>,
65 childs_from_requests: childs_from::<I::Request, Meta>,
66 }
67 }
68
69 pub fn event_child(&self, opcode: u16) -> Option<Object<Meta>> {
72 (self.childs_from_events)(opcode, self.version, &self.meta)
73 }
74
75 pub fn request_child(&self, opcode: u16) -> Option<Object<Meta>> {
78 (self.childs_from_requests)(opcode, self.version, &self.meta)
79 }
80
81 pub fn is_interface<I: Interface>(&self) -> bool {
83 self.interface == I::NAME
85 }
86
87 pub fn placeholder(meta: Meta) -> Object<Meta> {
89 Object {
90 interface: "",
91 version: 0,
92 requests: &[],
93 events: &[],
94 meta,
95 childs_from_events: childs_from::<NoMessage, Meta>,
96 childs_from_requests: childs_from::<NoMessage, Meta>,
97 }
98 }
99}
100
101fn childs_from<M: MessageGroup, Meta: ObjectMetadata>(
102 opcode: u16,
103 version: u32,
104 meta: &Meta,
105) -> Option<Object<Meta>> {
106 M::child(opcode, version, meta)
107}
108
109#[derive(Default, Debug)]
114pub struct ObjectMap<Meta: ObjectMetadata> {
115 client_objects: Vec<Option<Object<Meta>>>,
116 server_objects: Vec<Option<Object<Meta>>>,
117}
118
119impl<Meta: ObjectMetadata> ObjectMap<Meta> {
120 pub fn new() -> ObjectMap<Meta> {
122 ObjectMap { client_objects: Vec::new(), server_objects: Vec::new() }
123 }
124
125 pub fn find(&self, id: u32) -> Option<Object<Meta>> {
127 if id == 0 {
128 None
129 } else if id >= SERVER_ID_LIMIT {
130 self.server_objects.get((id - SERVER_ID_LIMIT) as usize).and_then(Clone::clone)
131 } else {
132 self.client_objects.get((id - 1) as usize).and_then(Clone::clone)
133 }
134 }
135
136 pub fn remove(&mut self, id: u32) {
140 if id == 0 {
141 } else if id >= SERVER_ID_LIMIT {
143 if let Some(place) = self.server_objects.get_mut((id - SERVER_ID_LIMIT) as usize) {
144 *place = None;
145 }
146 } else if let Some(place) = self.client_objects.get_mut((id - 1) as usize) {
147 *place = None;
148 }
149 }
150
151 #[allow(clippy::result_unit_err)]
157 pub fn insert_at(&mut self, id: u32, object: Object<Meta>) -> Result<(), ()> {
158 if id == 0 {
159 Err(())
160 } else if id >= SERVER_ID_LIMIT {
161 insert_in_at(&mut self.server_objects, (id - SERVER_ID_LIMIT) as usize, object)
162 } else {
163 insert_in_at(&mut self.client_objects, (id - 1) as usize, object)
164 }
165 }
166
167 pub fn client_insert_new(&mut self, object: Object<Meta>) -> u32 {
169 insert_in(&mut self.client_objects, object) + 1
170 }
171
172 pub fn server_insert_new(&mut self, object: Object<Meta>) -> u32 {
174 insert_in(&mut self.server_objects, object) + SERVER_ID_LIMIT
175 }
176
177 #[allow(clippy::result_unit_err)]
180 pub fn with<T, F: FnOnce(&mut Object<Meta>) -> T>(&mut self, id: u32, f: F) -> Result<T, ()> {
181 if id == 0 {
182 Err(())
183 } else if id >= SERVER_ID_LIMIT {
184 if let Some(&mut Some(ref mut obj)) =
185 self.server_objects.get_mut((id - SERVER_ID_LIMIT) as usize)
186 {
187 Ok(f(obj))
188 } else {
189 Err(())
190 }
191 } else if let Some(&mut Some(ref mut obj)) = self.client_objects.get_mut((id - 1) as usize)
192 {
193 Ok(f(obj))
194 } else {
195 Err(())
196 }
197 }
198
199 pub fn with_all<F: FnMut(u32, &mut Object<Meta>)>(&mut self, mut f: F) {
201 for (id, place) in self.client_objects.iter_mut().enumerate() {
202 if let Some(ref mut obj) = *place {
203 f(id as u32 + 1, obj);
204 }
205 }
206 for (id, place) in self.server_objects.iter_mut().enumerate() {
207 if let Some(ref mut obj) = *place {
208 f(id as u32 + SERVER_ID_LIMIT, obj);
209 }
210 }
211 }
212}
213
214fn insert_in<Meta: ObjectMetadata>(
216 store: &mut Vec<Option<Object<Meta>>>,
217 object: Object<Meta>,
218) -> u32 {
219 match store.iter().position(Option::is_none) {
220 Some(id) => {
221 store[id] = Some(object);
222 id as u32
223 }
224 None => {
225 store.push(Some(object));
226 (store.len() - 1) as u32
227 }
228 }
229}
230
231fn insert_in_at<Meta: ObjectMetadata>(
233 store: &mut Vec<Option<Object<Meta>>>,
234 id: usize,
235 object: Object<Meta>,
236) -> Result<(), ()> {
237 match id.cmp(&store.len()) {
238 Ordering::Greater => Err(()),
239 Ordering::Equal => {
240 store.push(Some(object));
241 Ok(())
242 }
243 Ordering::Less => {
244 let previous = &mut store[id];
245 if !previous.is_none() {
246 return Err(());
247 }
248 *previous = Some(object);
249 Ok(())
250 }
251 }
252}