wayrs_client/
object.rs

1//! Client side object representation
2
3use std::borrow::Borrow;
4use std::cmp;
5use std::fmt::{self, Debug};
6use std::hash::{Hash, Hasher};
7use std::num::NonZeroU32;
8
9use crate::connection::GenericCallback;
10use crate::protocol::WlDisplay;
11
12pub use wayrs_core::ObjectId;
13use wayrs_core::{Interface, Message, MessageBuffersPool};
14
15/// A Wayland object.
16///
17/// The [`Debug`] representation is `<interface>@<id>v<version>`.
18///
19/// [`Eq`], [`Ord`] and [`Hash`] implementations are delegated to the object's ID for performance
20/// reasons. This is fine because two different objects with the same ID must not exist at the same
21/// time.
22#[derive(Clone, Copy)]
23pub struct Object {
24    pub id: ObjectId,
25    pub interface: &'static Interface,
26    pub version: u32,
27}
28
29impl PartialEq for Object {
30    #[inline]
31    fn eq(&self, other: &Self) -> bool {
32        self.id == other.id
33    }
34}
35
36impl Eq for Object {}
37
38impl PartialEq<ObjectId> for Object {
39    #[inline]
40    fn eq(&self, other: &ObjectId) -> bool {
41        self.id == *other
42    }
43}
44
45impl PartialEq<Object> for ObjectId {
46    #[inline]
47    fn eq(&self, other: &Object) -> bool {
48        *self == other.id
49    }
50}
51
52impl PartialOrd for Object {
53    #[inline]
54    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
55        Some(self.cmp(other))
56    }
57}
58
59impl Ord for Object {
60    #[inline]
61    fn cmp(&self, other: &Self) -> cmp::Ordering {
62        self.id.cmp(&other.id)
63    }
64}
65
66impl Hash for Object {
67    #[inline]
68    fn hash<H: Hasher>(&self, state: &mut H) {
69        self.id.hash(state);
70    }
71}
72
73impl Borrow<ObjectId> for Object {
74    #[inline]
75    fn borrow(&self) -> &ObjectId {
76        &self.id
77    }
78}
79
80impl Debug for Object {
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        write!(
83            f,
84            "{}@{}v{}",
85            self.interface.name.to_string_lossy(),
86            self.id.0,
87            self.version
88        )
89    }
90}
91
92pub(crate) struct ObjectManager<D> {
93    vacant_ids: Vec<ObjectId>,
94    client_objects: Vec<Option<ObjectState<D>>>,
95    server_objects: Vec<Option<ObjectState<D>>>,
96}
97
98pub(crate) struct ObjectState<D> {
99    pub object: Object,
100    pub is_alive: bool,
101    pub cb: Option<GenericCallback<D>>,
102}
103
104#[doc(hidden)]
105#[derive(Debug)]
106pub struct BadMessage;
107
108/// Error which may occur in `Proxy: TryFrom<Object>` conversion.
109#[derive(Debug)]
110pub struct WrongObject;
111
112/// A Wayland object proxy.
113///
114/// This trait is implemented automatically for generated proxies, do not implement it yourself.
115pub trait Proxy: TryFrom<Object, Error = WrongObject> + Copy {
116    type Event;
117
118    const INTERFACE: &'static Interface;
119
120    #[doc(hidden)]
121    fn new(id: ObjectId, version: u32) -> Self;
122
123    #[doc(hidden)]
124    fn parse_event(
125        event: Message,
126        version: u32,
127        pool: &mut MessageBuffersPool,
128    ) -> Result<Self::Event, BadMessage>;
129
130    fn id(&self) -> ObjectId;
131
132    fn version(&self) -> u32;
133}
134
135impl<P: Proxy> From<P> for Object {
136    fn from(value: P) -> Self {
137        Self {
138            id: value.id(),
139            interface: P::INTERFACE,
140            version: value.version(),
141        }
142    }
143}
144
145impl<D> ObjectManager<D> {
146    pub fn new() -> Self {
147        let mut this = Self {
148            vacant_ids: Vec::new(),
149            client_objects: Vec::with_capacity(16),
150            server_objects: Vec::new(),
151        };
152
153        // Dummy NULL object
154        this.client_objects.push(None);
155
156        // Display
157        this.client_objects.push(Some(ObjectState {
158            object: WlDisplay::INSTANCE.into(),
159            is_alive: true,
160            cb: None,
161        }));
162
163        this
164    }
165
166    pub fn clear_callbacks<D2>(self) -> ObjectManager<D2> {
167        let map = |x: ObjectState<D>| ObjectState {
168            object: x.object,
169            is_alive: x.is_alive,
170            cb: None,
171        };
172        ObjectManager {
173            vacant_ids: self.vacant_ids,
174            client_objects: self
175                .client_objects
176                .into_iter()
177                .map(|x| x.map(map))
178                .collect(),
179            server_objects: self
180                .server_objects
181                .into_iter()
182                .map(|x| x.map(map))
183                .collect(),
184        }
185    }
186
187    pub fn alloc_client_object(
188        &mut self,
189        interface: &'static Interface,
190        version: u32,
191    ) -> &mut ObjectState<D> {
192        let id = self.vacant_ids.pop().unwrap_or_else(|| {
193            let id = self.client_objects.len() as u32;
194            self.client_objects.push(None);
195            ObjectId(NonZeroU32::new(id).unwrap())
196        });
197
198        assert!(id.created_by_client());
199        let obj = self.client_objects.get_mut(id.0.get() as usize).unwrap();
200        assert!(obj.is_none());
201
202        obj.insert(ObjectState {
203            object: Object {
204                id,
205                interface,
206                version,
207            },
208            is_alive: true,
209            cb: None,
210        })
211    }
212
213    pub fn register_server_object(&mut self, object: Object) -> &mut ObjectState<D> {
214        assert!(object.id.created_by_server());
215
216        let index = (object.id.as_u32() - ObjectId::MIN_SERVER.as_u32()) as usize;
217
218        while index >= self.server_objects.len() {
219            self.server_objects.push(None);
220        }
221
222        self.server_objects[index].insert(ObjectState {
223            object,
224            is_alive: true,
225            cb: None,
226        })
227    }
228
229    pub fn get_object_mut(&mut self, id: ObjectId) -> Option<&mut ObjectState<D>> {
230        if id.created_by_client() {
231            self.client_objects
232                .get_mut(id.as_u32() as usize)
233                .and_then(Option::as_mut)
234        } else {
235            self.server_objects
236                .get_mut((id.as_u32() - ObjectId::MIN_SERVER.as_u32()) as usize)
237                .and_then(Option::as_mut)
238        }
239    }
240
241    /// Call it only on client-created objects in response to `wl_display.delete_id`.
242    pub fn delete_client_object(&mut self, id: ObjectId) {
243        assert!(id.created_by_client());
244        *self.client_objects.get_mut(id.as_u32() as usize).unwrap() = None;
245        self.vacant_ids.push(id);
246    }
247}