fuchsia_wayland_core/lib.rs
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
}
}