1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
//! Per-client state
//!
//! A wayland compositor needs to maintain a set of states for each
//! connected wayland client. For example, each client could have a set of bound
//! objects. This module defines a common interface for such state types, so a
//! crate that implements different wayland protcol interfaces can rely on this
//! common interface and be generic over whatever state type the compositor
//! author chooses to use.
//!
//! See [`traits`] for definition of the interface. The rest of this module
//! provides some reference implementations of these interfaces.
//!
//! The documentation on [`traits::Client`] should give you a good idea of how
//! most of the stuffs fit together.
//!
//! See also the crate level documentation for how `Client` fits into the
//! overall picture.

/// Wayland divides the ID space into a client portion and a server portion. The
/// client is only allowed to allocate IDs up to this number, above this number
/// are reserved for the the server.
const CLIENT_MAX_ID: u32 = 0xfeffffff;

pub mod event_dispatcher;
pub mod store;
pub mod traits;

use std::{future::Future, os::fd::RawFd, pin::Pin};

#[doc(inline)]
pub use event_dispatcher::EventDispatcher;
#[doc(inline)]
pub use store::Store;

/// Type of future returned by [`dispatch_to`].
pub type Dispatch<'a, Ctx, R>
where
    Ctx: traits::Client + 'a,
    Ctx::Object: for<'b> crate::objects::Object<Ctx, Request<'b> = (&'b [u8], &'b [RawFd])>,
    R: runa_io::traits::buf::AsyncBufReadWithFd + 'a,
= impl Future<Output = bool> + 'a;

/// Reference implementation of the [`traits::Client::dispatch`] method.
///
/// This function reads a message from `reader`, looks up the corresponding
/// object, and then calls the object's `dispatch` method to handle the message.
/// It then checks if the `dispatch` method returned an error, and if so, sends
/// the error to the client. The returned future resolves to a boolean, which
/// indicates whether the client should be disconnected.
///
/// You can simply call this function as the implementation of your own
/// `dispatch` method.
///
/// Notice there is a type bound requiring `Ctx::Object` to accept a `(&[u8],
/// &[RawFd])` as its request type. This would be the case if you use
/// [`#[derive(Object)`](crate::objects::Object) to generate you object type. If
/// not, you are supposed to deserialize a wayland message from a
/// `(&[u8], &[RawFd])` tuple yourself and then dispatch the deserialized
/// message properly.
pub fn dispatch_to<'a, Ctx, R>(ctx: &'a mut Ctx, mut reader: Pin<&'a mut R>) -> Dispatch<'a, Ctx, R>
where
    R: runa_io::traits::buf::AsyncBufReadWithFd,
    Ctx: traits::Client,
    Ctx::Object: for<'b> crate::objects::Object<Ctx, Request<'b> = (&'b [u8], &'b [RawFd])>,
{
    async move {
        use runa_io::traits::{buf::Message, WriteMessage};
        use runa_wayland_protocols::wayland::wl_display::v1 as wl_display;
        use runa_wayland_types as types;
        use traits::Store;

        use crate::{error::ProtocolError, objects::AnyObject};
        let Message {
            object_id,
            len,
            data,
            fds,
        } = match R::next_message(reader.as_mut()).await {
            Ok(v) => v,
            // I/O error, no point sending the error to the client
            Err(_) => return true,
        };
        let (ret, bytes_read, fds_read) =
            <<Ctx as traits::Client>::Object as crate::objects::Object<Ctx>>::dispatch(
                ctx,
                object_id,
                (data, fds),
            )
            .await;
        let (mut fatal, error) = match ret {
            Ok(_) => (false, None),
            Err(e) => (
                e.fatal(),
                e.wayland_error()
                    .map(|(object_id, error_code)| (object_id, error_code, e.to_string())),
            ),
        };
        if let Some((object_id, error_code, msg)) = error {
            // We are going to disconnect the client so we don't care about the
            // error.
            fatal |= ctx
                .connection_mut()
                .send(crate::objects::DISPLAY_ID, wl_display::events::Error {
                    object_id: types::Object(object_id),
                    code:      error_code,
                    message:   types::Str(msg.as_bytes()),
                })
                .await
                .is_err();
        }
        if !fatal {
            if bytes_read != len {
                let len_opcode = u32::from_ne_bytes(data[0..4].try_into().unwrap());
                let opcode = len_opcode & 0xffff;
                tracing::error!(
                    "unparsed bytes in buffer, read ({bytes_read}) != received ({len}). \
                     object_id: {}@{object_id}, opcode: {opcode}",
                    ctx.objects()
                        .get::<Ctx::Object>(object_id)
                        .map(|o| o.interface())
                        .unwrap_or("unknown")
                );
                fatal = true;
            }
            reader.consume(bytes_read, fds_read);
        }
        fatal
    }
}

#[doc(hidden)] // not ready for use yet
pub mod serial {
    use hashbrown::HashMap;

    #[derive(Debug)]
    pub struct EventSerial<D> {
        serials:     HashMap<u32, (D, std::time::Instant)>,
        last_serial: u32,
        expire:      std::time::Duration,
    }

    /// A serial allocator for event serials. Serials are automatically
    /// forgotten after a set amount of time.
    impl<D> EventSerial<D> {
        pub fn new(expire: std::time::Duration) -> Self {
            Self {
                serials: HashMap::new(),
                last_serial: 0,
                expire,
            }
        }

        fn clean_up(&mut self) {
            let now = std::time::Instant::now();
            self.serials.retain(|_, (_, t)| *t + self.expire > now);
        }
    }

    impl<D: 'static> crate::Serial for EventSerial<D> {
        type Data = D;
        type Iter<'a> = <&'a Self as IntoIterator>::IntoIter;

        fn next_serial(&mut self, data: Self::Data) -> u32 {
            self.last_serial += 1;

            self.clean_up();
            if self
                .serials
                .insert(self.last_serial, (data, std::time::Instant::now()))
                .is_some()
            {
                panic!(
                    "serial {} already in use, expiration duration too long?",
                    self.last_serial
                );
            }
            self.last_serial
        }

        fn get(&self, serial: u32) -> Option<&Self::Data> {
            let now = std::time::Instant::now();
            self.serials.get(&serial).and_then(|(d, timestamp)| {
                if *timestamp + self.expire > now {
                    Some(d)
                } else {
                    None
                }
            })
        }

        fn expire(&mut self, serial: u32) -> bool {
            self.clean_up();
            self.serials.remove(&serial).is_some()
        }

        fn iter(&self) -> Self::Iter<'_> {
            self.into_iter()
        }
    }
    impl<'a, D: 'a> IntoIterator for &'a EventSerial<D> {
        type Item = (u32, &'a D);

        type IntoIter = impl Iterator<Item = Self::Item> + 'a where Self: 'a;

        fn into_iter(self) -> Self::IntoIter {
            self.serials.iter().map(|(k, (d, _))| (*k, d))
        }
    }
}