fuchsia_wayland_core/
lib.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::Error;
6use std::fmt::{self, Debug, Display};
7use std::io;
8use std::marker::PhantomData;
9use thiserror::Error;
10
11mod fixed;
12pub use crate::fixed::*;
13mod message;
14pub use crate::message::*;
15
16pub type ObjectId = u32;
17pub type NewId = u32;
18
19/// Common base trait for all rust types that model wayland Requests or Events.
20pub trait MessageType {
21    /// Generates a string suitable for protocol logging this message.
22    fn log(&self, this: ObjectId) -> String;
23
24    /// Returns a static CStr reference that describes the interface/method of
25    /// this message.
26    ///
27    /// Ex: 'wl_interface::method_name'
28    fn message_name(&self) -> &'static std::ffi::CStr;
29}
30
31/// Trait to be implemented by any type used as an interface 'event'.
32pub trait IntoMessage: Sized + MessageType {
33    type Error: std::error::Error + std::marker::Sync;
34    /// Consumes |self| and serializes into a |Message|.
35    fn into_message(self, id: u32) -> Result<Message, Self::Error>;
36}
37
38/// Trait to be implemented by any type used as an interface 'request'.
39pub trait FromArgs: Sized + MessageType {
40    /// Consumes |args| creates an instance of self.
41    fn from_args(op: u16, args: Vec<Arg>) -> Result<Self, Error>;
42}
43
44/// An array of |ArgKind|s for a single request or event message.
45pub struct MessageSpec(pub &'static [ArgKind]);
46
47/// An array of |MessageSpec|s for either a set of requests or events.
48///
49/// The slice is indexed by message opcode.
50pub struct MessageGroupSpec(pub &'static [MessageSpec]);
51
52pub trait Interface {
53    /// The name of this interface. This will correspond to the 'name' attribute
54    /// on the 'interface' element in the wayland protocol XML.
55    const NAME: &'static str;
56
57    /// The version of this interface. This will correspond to the 'version'
58    /// attribute on the 'interface' element in the wayland protocol XML.
59    const VERSION: u32;
60
61    /// A description of the structure of request messages.
62    const REQUESTS: MessageGroupSpec;
63
64    /// A description of the structure of event messages.
65    const EVENTS: MessageGroupSpec;
66
67    /// The rust type that can hold the decoded incoming messages.
68    type Incoming: FromArgs;
69
70    /// The rust type that can be decoded into outgoing messages.
71    type Outgoing: IntoMessage;
72}
73
74#[derive(Debug, Error)]
75pub enum DecodeError {
76    #[error("invalid message opcode: {}", _0)]
77    InvalidOpcode(u16),
78    #[error("end of argument list occurred while decoding")]
79    InsufficientArgs,
80    #[error("{}", _0)]
81    IoError(io::Error),
82}
83
84impl From<io::Error> for DecodeError {
85    fn from(e: io::Error) -> Self {
86        DecodeError::IoError(e)
87    }
88}
89
90#[derive(Debug, Error)]
91pub enum EncodeError {
92    #[error("{}", _0)]
93    IoError(io::Error),
94}
95
96impl From<io::Error> for EncodeError {
97    fn from(e: io::Error) -> Self {
98        EncodeError::IoError(e)
99    }
100}
101
102#[derive(Debug, Error)]
103#[error("Unknown enum value {}", _0)]
104pub struct UnknownEnumValue(u32);
105
106impl UnknownEnumValue {
107    pub fn value(&self) -> u32 {
108        self.0
109    }
110}
111
112/// Thin wrapper around the typed enum values that allow us to transport
113/// unknown enum values.
114#[derive(Copy, Clone, Debug, PartialEq)]
115pub enum Enum<E: Copy + PartialEq> {
116    Recognized(E),
117    Unrecognized(u32),
118}
119
120impl<E: Copy + PartialEq> Enum<E> {
121    /// Extract the inner enum type as a result.
122    ///
123    /// Ex:
124    ///   let inner = some_argument.as_enum()?;
125    pub fn as_enum(&self) -> Result<E, UnknownEnumValue> {
126        match *self {
127            Enum::Recognized(e) => Ok(e),
128            Enum::Unrecognized(i) => Err(UnknownEnumValue(i)),
129        }
130    }
131}
132
133impl<E: Copy + PartialEq + Display> Display for Enum<E> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
135        match self {
136            Enum::Recognized(e) => write!(f, "{}", e),
137            Enum::Unrecognized(v) => write!(f, "{}", v),
138        }
139    }
140}
141
142/// A `NewObject` is a type-safe wrapper around a 'new_id' argument that has
143/// a static wayland interface. This wrapper will enforce that the object is
144/// only implemented by types that can receive wayland messages for the
145/// expected interface.
146pub struct NewObject<I: Interface + 'static>(PhantomData<I>, ObjectId);
147impl<I: Interface + 'static> Display for NewObject<I> {
148    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
149        write!(f, "NewObject<{}>({})", I::NAME, self.1)
150    }
151}
152impl<I: Interface + 'static> Debug for NewObject<I> {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
154        write!(f, "{}", self)
155    }
156}
157
158/// Support turning raw `ObjectId`s into `NewObject`s.
159///
160/// Ex:
161///   let id: ObjectId = 3;
162///   let new_object: NewObject<MyInterface> = id.into();
163impl<I: Interface + 'static> From<ObjectId> for NewObject<I> {
164    fn from(id: ObjectId) -> Self {
165        Self::from_id(id)
166    }
167}
168
169impl<I: Interface + 'static> NewObject<I> {
170    pub fn from_id(id: ObjectId) -> Self {
171        NewObject(PhantomData, id)
172    }
173
174    pub fn id(&self) -> ObjectId {
175        self.1
176    }
177}