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
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use anyhow::Error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::marker::PhantomData;
use thiserror::Error;

mod fixed;
pub use crate::fixed::*;
mod message;
pub use crate::message::*;

pub type ObjectId = u32;
pub type NewId = u32;

/// Common base trait for all rust types that model wayland Requests or Events.
pub trait MessageType {
    /// Generates a string suitable for protocol logging this message.
    fn log(&self, this: ObjectId) -> String;

    /// Returns a static CStr reference that describes the interface/method of
    /// this message.
    ///
    /// Ex: 'wl_interface::method_name'
    fn message_name(&self) -> &'static std::ffi::CStr;
}

/// Trait to be implemented by any type used as an interface 'event'.
pub trait IntoMessage: Sized + MessageType {
    type Error: std::error::Error + std::marker::Sync;
    /// Consumes |self| and serializes into a |Message|.
    fn into_message(self, id: u32) -> Result<Message, Self::Error>;
}

/// Trait to be implemented by any type used as an interface 'request'.
pub trait FromArgs: Sized + MessageType {
    /// Consumes |args| creates an instance of self.
    fn from_args(op: u16, args: Vec<Arg>) -> Result<Self, Error>;
}

/// An array of |ArgKind|s for a single request or event message.
pub struct MessageSpec(pub &'static [ArgKind]);

/// An array of |MessageSpec|s for either a set of requests or events.
///
/// The slice is indexed by message opcode.
pub struct MessageGroupSpec(pub &'static [MessageSpec]);

pub trait Interface {
    /// The name of this interface. This will correspond to the 'name' attribute
    /// on the 'interface' element in the wayland protocol XML.
    const NAME: &'static str;

    /// The version of this interface. This will correspond to the 'version'
    /// attribute on the 'interface' element in the wayland protocol XML.
    const VERSION: u32;

    /// A description of the structure of request messages.
    const REQUESTS: MessageGroupSpec;

    /// A description of the structure of event messages.
    const EVENTS: MessageGroupSpec;

    /// The rust type that can hold the decoded incoming messages.
    type Incoming: FromArgs;

    /// The rust type that can be decoded into outgoing messages.
    type Outgoing: IntoMessage;
}

#[derive(Debug, Error)]
pub enum DecodeError {
    #[error("invalid message opcode: {}", _0)]
    InvalidOpcode(u16),
    #[error("end of argument list occurred while decoding")]
    InsufficientArgs,
    #[error("{}", _0)]
    IoError(io::Error),
}

impl From<io::Error> for DecodeError {
    fn from(e: io::Error) -> Self {
        DecodeError::IoError(e)
    }
}

#[derive(Debug, Error)]
pub enum EncodeError {
    #[error("{}", _0)]
    IoError(io::Error),
}

impl From<io::Error> for EncodeError {
    fn from(e: io::Error) -> Self {
        EncodeError::IoError(e)
    }
}

#[derive(Debug, Error)]
#[error("Unknown enum value {}", _0)]
pub struct UnknownEnumValue(u32);

impl UnknownEnumValue {
    pub fn value(&self) -> u32 {
        self.0
    }
}

/// Thin wrapper around the typed enum values that allow us to transport
/// unknown enum values.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Enum<E: Copy + PartialEq> {
    Recognized(E),
    Unrecognized(u32),
}

impl<E: Copy + PartialEq> Enum<E> {
    /// Extract the inner enum type as a result.
    ///
    /// Ex:
    ///   let inner = some_argument.as_enum()?;
    pub fn as_enum(&self) -> Result<E, UnknownEnumValue> {
        match *self {
            Enum::Recognized(e) => Ok(e),
            Enum::Unrecognized(i) => Err(UnknownEnumValue(i)),
        }
    }
}

impl<E: Copy + PartialEq + Display> Display for Enum<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            Enum::Recognized(e) => write!(f, "{}", e),
            Enum::Unrecognized(v) => write!(f, "{}", v),
        }
    }
}

/// A `NewObject` is a type-safe wrapper around a 'new_id' argument that has
/// a static wayland interface. This wrapper will enforce that the object is
/// only implemented by types that can receive wayland messages for the
/// expected interface.
pub struct NewObject<I: Interface + 'static>(PhantomData<I>, ObjectId);
impl<I: Interface + 'static> Display for NewObject<I> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(f, "NewObject<{}>({})", I::NAME, self.1)
    }
}
impl<I: Interface + 'static> Debug for NewObject<I> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(f, "{}", self)
    }
}

/// Support turning raw `ObjectId`s into `NewObject`s.
///
/// Ex:
///   let id: ObjectId = 3;
///   let new_object: NewObject<MyInterface> = id.into();
impl<I: Interface + 'static> From<ObjectId> for NewObject<I> {
    fn from(id: ObjectId) -> Self {
        Self::from_id(id)
    }
}

impl<I: Interface + 'static> NewObject<I> {
    pub fn from_id(id: ObjectId) -> Self {
        NewObject(PhantomData, id)
    }

    pub fn id(&self) -> ObjectId {
        self.1
    }
}