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.
45use anyhow::Error;
6use std::fmt::{self, Debug, Display};
7use std::io;
8use std::marker::PhantomData;
9use thiserror::Error;
1011mod fixed;
12pub use crate::fixed::*;
13mod message;
14pub use crate::message::*;
1516pub type ObjectId = u32;
17pub type NewId = u32;
1819/// 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.
22fn log(&self, this: ObjectId) -> String;
2324/// Returns a static CStr reference that describes the interface/method of
25 /// this message.
26 ///
27 /// Ex: 'wl_interface::method_name'
28fn message_name(&self) -> &'static std::ffi::CStr;
29}
3031/// Trait to be implemented by any type used as an interface 'event'.
32pub trait IntoMessage: Sized + MessageType {
33type Error: std::error::Error + std::marker::Sync;
34/// Consumes |self| and serializes into a |Message|.
35fn into_message(self, id: u32) -> Result<Message, Self::Error>;
36}
3738/// 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.
41fn from_args(op: u16, args: Vec<Arg>) -> Result<Self, Error>;
42}
4344/// An array of |ArgKind|s for a single request or event message.
45pub struct MessageSpec(pub &'static [ArgKind]);
4647/// 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]);
5152pub 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.
55const NAME: &'static str;
5657/// The version of this interface. This will correspond to the 'version'
58 /// attribute on the 'interface' element in the wayland protocol XML.
59const VERSION: u32;
6061/// A description of the structure of request messages.
62const REQUESTS: MessageGroupSpec;
6364/// A description of the structure of event messages.
65const EVENTS: MessageGroupSpec;
6667/// The rust type that can hold the decoded incoming messages.
68type Incoming: FromArgs;
6970/// The rust type that can be decoded into outgoing messages.
71type Outgoing: IntoMessage;
72}
7374#[derive(Debug, Error)]
75pub enum DecodeError {
76#[error("invalid message opcode: {}", _0)]
77InvalidOpcode(u16),
78#[error("end of argument list occurred while decoding")]
79InsufficientArgs,
80#[error("{}", _0)]
81IoError(io::Error),
82}
8384impl From<io::Error> for DecodeError {
85fn from(e: io::Error) -> Self {
86 DecodeError::IoError(e)
87 }
88}
8990#[derive(Debug, Error)]
91pub enum EncodeError {
92#[error("{}", _0)]
93IoError(io::Error),
94}
9596impl From<io::Error> for EncodeError {
97fn from(e: io::Error) -> Self {
98 EncodeError::IoError(e)
99 }
100}
101102#[derive(Debug, Error)]
103#[error("Unknown enum value {}", _0)]
104pub struct UnknownEnumValue(u32);
105106impl UnknownEnumValue {
107pub fn value(&self) -> u32 {
108self.0
109}
110}
111112/// 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}
119120impl<E: Copy + PartialEq> Enum<E> {
121/// Extract the inner enum type as a result.
122 ///
123 /// Ex:
124 /// let inner = some_argument.as_enum()?;
125pub fn as_enum(&self) -> Result<E, UnknownEnumValue> {
126match *self {
127 Enum::Recognized(e) => Ok(e),
128 Enum::Unrecognized(i) => Err(UnknownEnumValue(i)),
129 }
130 }
131}
132133impl<E: Copy + PartialEq + Display> Display for Enum<E> {
134fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
135match self {
136 Enum::Recognized(e) => write!(f, "{}", e),
137 Enum::Unrecognized(v) => write!(f, "{}", v),
138 }
139 }
140}
141142/// 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> {
148fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
149write!(f, "NewObject<{}>({})", I::NAME, self.1)
150 }
151}
152impl<I: Interface + 'static> Debug for NewObject<I> {
153fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
154write!(f, "{}", self)
155 }
156}
157158/// 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> {
164fn from(id: ObjectId) -> Self {
165Self::from_id(id)
166 }
167}
168169impl<I: Interface + 'static> NewObject<I> {
170pub fn from_id(id: ObjectId) -> Self {
171 NewObject(PhantomData, id)
172 }
173174pub fn id(&self) -> ObjectId {
175self.1
176}
177}