| // 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. |
| ///! This module provides types for managing the set of wayland objects for a |
| ///! connection. The |ObjectMap| associates a numeric object id with a |
| ///! |MessageReceiver| that can interpret the message and provide the logic to |
| ///! implement the interface contract for that object. |
| ///! |
| ///! At a high level, the |RequestReceiver<I:Interface>| trait allows for a |
| ///! decoded request to be interacted with. In the middle we provide the |
| ///! |RequestDispatcher| struct that implements the |MessageReceiver| trait |
| ///! by decoding the |Message| into the concrete |Request| type for the |
| ///! |Interface|. |
| ///! |
| ///! Consumers should mostly have to only concern themselves with the |
| ///! |RequestReceiver<I:Interface>| trait, with the other types being mostly the |
| ///! glue and dispatch logic. |
| use std::any::Any; |
| use std::collections::hash_map::{Entry, HashMap}; |
| use std::fmt::{self, Debug}; |
| use std::marker::PhantomData; |
| |
| use failure::{format_err, Error, Fail}; |
| use fuchsia_wayland_core::{self as wl, FromArgs, MessageType}; |
| |
| use crate::client::Client; |
| |
| /// The |ObjectMap| holds the state of active objects for a single connection. |
| /// |
| /// When a new connection is established, the server should populate the |
| /// |ObjectMap| with the "wl_display" singleton object. From the client can |
| /// query the registry and bind new objects to the interfaces the client |
| /// understands. |
| pub(crate) struct ObjectMap { |
| /// The set of active objects. This holds the descriptors of supported |
| /// messages for each object, as well as the |MessageReceiver| that's |
| /// capable of handling the requests. |
| objects: HashMap<u32, ObjectMapEntry>, |
| } |
| |
| struct ObjectMapEntry { |
| /// The opcodes and method signatures accepted by this object. |
| request_spec: &'static wl::MessageGroupSpec, |
| /// The handler for this object. |
| receiver: Box<dyn MessageReceiver>, |
| } |
| |
| #[derive(Copy, Clone, Debug, Fail)] |
| pub enum ObjectMapError { |
| /// An error raised if a message is received with the 'sender' field set |
| /// to an unknown object (ex: either the object has not been created yet |
| /// or it has already been deleted). |
| #[fail(display = "Object with id {} is not found", _0)] |
| InvalidObjectId(u32), |
| |
| /// An error raised if a message is delivered to an object with an |
| /// unsupported or unknown opcode. |
| #[fail(display = "Opcode {} is not supported", _0)] |
| InvalidOpcode(u16), |
| } |
| |
| /// Errors generated when looking up objects from the map. |
| #[derive(Debug, Fail)] |
| pub enum ObjectLookupError { |
| #[fail(display = "Object with id does not exist")] |
| ObjectDoesNotExist, |
| #[fail(display = "Failed to downcast")] |
| DowncastFailed, |
| } |
| |
| impl ObjectMap { |
| pub fn new() -> Self { |
| ObjectMap { |
| objects: HashMap::new(), |
| } |
| } |
| |
| /// Looks up an object in the map and returns a downcasted reference to |
| /// the implementation. |
| pub fn get<T: Any>(&self, id: wl::ObjectId) -> Result<&T, ObjectLookupError> { |
| match self.objects.get(&id) { |
| Some(entry) => match entry.receiver.data().downcast_ref() { |
| Some(t) => Ok(t), |
| None => Err(ObjectLookupError::DowncastFailed), |
| }, |
| None => Err(ObjectLookupError::ObjectDoesNotExist), |
| } |
| } |
| |
| /// Looks up an object in the map and returns a downcasted mutable |
| /// reference to the implementation. |
| pub fn get_mut<T: Any>(&mut self, id: wl::ObjectId) -> Result<&mut T, ObjectLookupError> { |
| match self.objects.get_mut(&id) { |
| Some(entry) => match entry.receiver.data_mut().downcast_mut() { |
| Some(t) => Ok(t), |
| None => Err(ObjectLookupError::DowncastFailed), |
| }, |
| None => Err(ObjectLookupError::ObjectDoesNotExist), |
| } |
| } |
| |
| /// Looks up the receiver function and the message structure from the map. |
| pub(crate) fn lookup_internal( |
| &self, header: &wl::MessageHeader, |
| ) -> Result<(MessageReceiverFn, &'static wl::MessageSpec), Error> { |
| let ObjectMapEntry { |
| request_spec, |
| receiver, |
| } = self |
| .objects |
| .get(&header.sender) |
| .ok_or(ObjectMapError::InvalidObjectId(header.sender))?; |
| let spec = request_spec |
| .0 |
| .get(header.opcode as usize) |
| .ok_or(ObjectMapError::InvalidOpcode(header.opcode))?; |
| |
| Ok((receiver.receiver(), spec)) |
| } |
| |
| /// Adds a new object into the map that will handle messages with the sender |
| /// set to |id|. When a message is received with the corresponding |id|, the |
| /// message will be decoded and forwarded to the |RequestReceiver|. |
| /// |
| /// Returns Err if there is already an object for |id| in this |ObjectMap|. |
| pub fn add_object<I: wl::Interface + 'static, R: RequestReceiver<I> + 'static>( |
| &mut self, id: u32, receiver: R, |
| ) -> Result<ObjectRef<R>, Error> { |
| self.add_object_raw(id, Box::new(RequestDispatcher::new(receiver)), &I::REQUESTS)?; |
| Ok(ObjectRef::from_id(id)) |
| } |
| |
| /// Adds an object to the map using the low-level primitives. It's favorable |
| /// to use instead |add_object| if the wayland interface for the object is |
| /// statically known. |
| pub fn add_object_raw( |
| &mut self, id: wl::ObjectId, receiver: Box<MessageReceiver>, |
| request_spec: &'static wl::MessageGroupSpec, |
| ) -> Result<(), Error> { |
| if let Entry::Vacant(entry) = self.objects.entry(id) { |
| entry.insert(ObjectMapEntry { |
| receiver, |
| request_spec, |
| }); |
| Ok(()) |
| } else { |
| Err(format_err!("Can't add duplicate object with id {}. ", id)) |
| } |
| } |
| |
| pub fn delete(&mut self, id: wl::ObjectId) -> Result<(), Error> { |
| if self.objects.remove(&id).is_some() { |
| // TODO: Send wl_display::delete_id. |
| Ok(()) |
| } else { |
| Err(format_err!("Item {} does not exist", id)) |
| } |
| } |
| } |
| |
| /// When the concrete type of an object is known statically, we can provide |
| /// an ObjectRef wrapper around the ObjectId in order to make downcasting |
| /// simpler. |
| /// |
| /// This is primarily useful when vending self references to MessageReceviers. |
| pub struct ObjectRef<T: 'static>(PhantomData<T>, wl::ObjectId); |
| |
| // We cannot just derive these since that will place the corresponding trait |
| // bound on `T`. |
| impl<T: 'static> Copy for ObjectRef<T> {} |
| impl<T: 'static> Clone for ObjectRef<T> { |
| fn clone(&self) -> Self { |
| ObjectRef(PhantomData, self.1) |
| } |
| } |
| impl<T: 'static> Debug for ObjectRef<T> { |
| fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
| write!(f, "ObjectRef({})", self.1) |
| } |
| } |
| impl<T> From<wl::ObjectId> for ObjectRef<T> { |
| fn from(id: wl::ObjectId) -> Self { |
| Self::from_id(id) |
| } |
| } |
| |
| impl<T> ObjectRef<T> { |
| pub fn from_id(id: wl::ObjectId) -> Self { |
| ObjectRef(PhantomData, id) |
| } |
| |
| pub fn id(&self) -> wl::ObjectId { |
| self.1 |
| } |
| |
| /// Provides an immutable reference to an object, downcasted to |T|. |
| pub fn get<'a>(&self, client: &'a Client) -> Result<&'a T, ObjectLookupError> { |
| client.get_object(self.1) |
| } |
| |
| /// Provides a mutable reference to an object, downcasted to |T|. |
| pub fn get_mut<'a>(&self, client: &'a mut Client) -> Result<&'a mut T, ObjectLookupError> { |
| client.get_object_mut(self.1) |
| } |
| |
| /// Returns `true` iff the underlying object is still valid. |
| /// |
| /// Here 'valid' means that the object_id exists and refers to an object |
| /// of type `T`. This method will still return `true` if the associated |
| /// object_id has been deleted and recreated with the same type `T. If this |
| /// is not desirable then the caller must track instance with some state |
| /// embedded into `T`. |
| /// |
| /// This can be useful to verify prior to sending events using the |
| /// associated object_id but the host object itself is not required. |
| pub fn is_valid(&self, client: &mut Client) -> bool { |
| self.get(client).is_ok() |
| } |
| } |
| |
| pub trait NewObjectExt<I: wl::Interface> { |
| fn implement<R: RequestReceiver<I>>( |
| self, client: &mut Client, receiver: R, |
| ) -> Result<ObjectRef<R>, Error>; |
| } |
| |
| impl<I: wl::Interface> NewObjectExt<I> for wl::NewObject<I> { |
| fn implement<R: RequestReceiver<I>>( |
| self, client: &mut Client, receiver: R, |
| ) -> Result<ObjectRef<R>, Error> { |
| client.add_object(self.id(), receiver) |
| } |
| } |
| |
| /// A |MessageReceiver| is a type that can accept in-bound messages from a |
| /// client. |
| /// |
| /// The server will dispatch |Message|s to the appropriate |MessageReceiver| |
| /// by reading the sender field in the message header. |
| type MessageReceiverFn = |
| fn(this: wl::ObjectId, opcode: u16, args: Vec<wl::Arg>, client: &mut Client) |
| -> Result<(), Error>; |
| pub trait MessageReceiver { |
| /// Returns a function pointer that will be called to handle requests |
| /// targeting this object. |
| fn receiver(&self) -> MessageReceiverFn; |
| |
| fn data(&self) -> &Any; |
| |
| fn data_mut(&mut self) -> &mut Any; |
| } |
| |
| /// The |RequestReceiver| trait is what high level code will use to work with |
| /// request messages for a given type. |
| pub trait RequestReceiver<I: wl::Interface>: Any + Sized { |
| /// Handle a decoded message for the associated |Interface|. |
| /// |
| /// |self| is not directly provided, but instead is provided as an |
| /// |ObjectId| that can be used to get a reference to self. |
| /// |
| /// Ex: |
| /// struct MyReceiver; |
| /// |
| /// impl RequestReceiver<MyInterface> for MyReceiver { |
| /// fn receive(mut this: ObjectRef<Self>, |
| /// request: MyInterfaceRequest, |
| /// client: &mut Client |
| /// ) -> Result<(), Error> { |
| /// let this = self.get()?; |
| /// let this_mut = self.get_mut()?; |
| /// } |
| /// } |
| fn receive( |
| this: ObjectRef<Self>, request: I::Request, client: &mut Client, |
| ) -> Result<(), Error>; |
| } |
| |
| /// Implements a |MessageReceiver| that can decode a request into the |
| /// appropriate request type for an |Interface|, and then invoke an |
| /// |Implementation| |
| /// |
| /// This struct essentially is the glue that sits in between the generic |
| /// |MessageReceiver| trait that is used to dispatch raw message buffers and |
| /// the higher level |RequestReceiver| that operates on the decoded request |
| /// enums. |
| pub struct RequestDispatcher<I: wl::Interface, R: RequestReceiver<I>> { |
| _marker: PhantomData<I>, |
| receiver: R, |
| } |
| |
| impl<I: wl::Interface, R: RequestReceiver<I>> RequestDispatcher<I, R> { |
| pub fn new(receiver: R) -> Self { |
| RequestDispatcher { |
| receiver, |
| _marker: PhantomData, |
| } |
| } |
| } |
| |
| fn receive_message<I: wl::Interface, R: RequestReceiver<I>>( |
| this: wl::ObjectId, opcode: u16, args: Vec<wl::Arg>, client: &mut Client, |
| ) -> Result<(), Error> { |
| let request = I::Request::from_args(opcode, args)?; |
| if client.protocol_logging() { |
| println!("--r-> {}", request.log(this)); |
| } |
| R::receive(ObjectRef(PhantomData, this), request, client)?; |
| Ok(()) |
| } |
| |
| /// Convert the raw Message into the appropriate request type by delegating |
| /// to the associated |Request| type of |Interface|, and then invoke the |
| /// receiver. |
| impl<I: wl::Interface, R: RequestReceiver<I>> MessageReceiver for RequestDispatcher<I, R> { |
| fn receiver(&self) -> MessageReceiverFn { |
| receive_message::<I, R> |
| } |
| |
| fn data(&self) -> &Any { |
| &self.receiver |
| } |
| |
| fn data_mut(&mut self) -> &mut Any { |
| &mut self.receiver |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| use fuchsia_async as fasync; |
| use fuchsia_wayland_core::IntoMessage; |
| use fuchsia_zircon as zx; |
| use parking_lot::Mutex; |
| use std::sync::Arc; |
| |
| use crate::registry::RegistryBuilder; |
| use crate::test_protocol::*; |
| |
| fn create_client() -> Result<Client, Error> { |
| let _executor = fasync::Executor::new(); |
| let registry = Arc::new(Mutex::new(RegistryBuilder::new().build())); |
| let (c1, _c2) = zx::Channel::create()?; |
| Ok(Client::new(fasync::Channel::from_channel(c1)?, registry)) |
| } |
| |
| #[test] |
| fn dispatch_message_to_request_receiver() -> Result<(), Error> { |
| let mut client = create_client()?; |
| client.add_object(0, TestReceiver::new())?; |
| |
| // Send a sync message; verify it's received. |
| client.receive_message(TestMessage::Message1.into_message(0)?)?; |
| assert_eq!(1, client.get_object::<TestReceiver>(0)?.count()); |
| Ok(()) |
| } |
| |
| #[test] |
| fn add_object_duplicate_id() -> Result<(), Error> { |
| let mut client = create_client()?; |
| assert!(client.add_object(0, TestReceiver::new()).is_ok()); |
| assert!(client.add_object(0, TestReceiver::new()).is_err()); |
| Ok(()) |
| } |
| |
| #[test] |
| fn dispatch_message_to_invalid_id() -> Result<(), Error> { |
| // Send a message to an empty map. |
| let mut client = create_client()?; |
| |
| assert!(client |
| .receive_message(TestMessage::Message1.into_message(0)?) |
| .is_err()); |
| Ok(()) |
| } |
| } |