blob: 4f593a6e7b93519b0519c6c9af8c36401172093c [file] [log] [blame]
// 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.
//! Wrapper types for the endpoints of a connection.
use {
crate::{Error, ServeInner},
fuchsia_async as fasync,
fuchsia_zircon as zx,
std::marker::PhantomData,
std::sync::Arc,
};
/// A marker for a particular FIDL service.
///
/// Implementations of this trait can be used to manufacture instances of a FIDL service
/// and get metadata about a particular service.
pub trait ServiceMarker: Sized + Send + Sync + 'static {
/// The type of the structure against which FIDL requests are made.
/// Queries made against the proxy are sent to the paired `ServerEnd`.
type Proxy: Proxy;
/// The type of the stream of requests coming into a server.
type RequestStream: RequestStream;
/// The name of the service (to be used for service lookup and discovery).
const NAME: &'static str;
}
/// A type which allows querying a remote FIDL server over a channel.
pub trait Proxy: Sized {
/// Create a proxy over the given channel.
fn from_channel(inner: fasync::Channel) -> Self;
}
/// A stream of requests coming into a FIDL server over a channel.
pub trait RequestStream: Sized {
/// A type that can be used to send events and shut down the request stream.
type ControlHandle;
/// Returns a copy of the `ControlHandle` for the given stream.
/// This handle can be used to send events and shut down the request stream.
fn control_handle(&self) -> Self::ControlHandle;
/// Create a request stream from the given channel.
fn from_channel(inner: fasync::Channel) -> Self;
/// Convert this channel into its underlying components.
fn into_inner(self) -> (Arc<ServeInner>, Option<zx::MessageBuf>);
/// Create this channel from its underlying components.
fn from_inner(inner: Arc<ServeInner>, msg_buf: Option<zx::MessageBuf>) -> Self;
/// Convert this FIDL request stream into a request stream of another FIDL protocol.
fn cast_stream<T: RequestStream>(self) -> T {
let inner = self.into_inner();
T::from_inner(inner.0, inner.1)
}
}
/// The `Client` end of a FIDL connection.
#[derive(Eq, PartialEq, Hash)]
pub struct ClientEnd<T> {
inner: zx::Channel,
phantom: PhantomData<T>,
}
impl<T> ClientEnd<T> {
/// Create a new client from the provided channel.
pub fn new(inner: zx::Channel) -> Self {
ClientEnd { inner, phantom: PhantomData }
}
/// Extract the inner channel.
pub fn into_channel(self) -> zx::Channel {
self.inner
}
}
impl<T: ServiceMarker> ClientEnd<T> {
/// Convert the `ClientEnd` into a `Proxy` through which FIDL calls may be made.
pub fn into_proxy(self) -> Result<T::Proxy, Error> {
Ok(T::Proxy::from_channel(
fasync::Channel::from_channel(self.inner)
.map_err(Error::AsyncChannel)?))
}
}
impl<T> zx::AsHandleRef for ClientEnd<T> {
fn as_handle_ref(&self) -> zx::HandleRef {
self.inner.as_handle_ref()
}
}
impl<T> From<ClientEnd<T>> for zx::Handle {
fn from(client: ClientEnd<T>) -> zx::Handle {
client.into_channel().into()
}
}
impl<T> From<zx::Handle> for ClientEnd<T> {
fn from(handle: zx::Handle) -> Self {
ClientEnd {
inner: handle.into(),
phantom: PhantomData,
}
}
}
impl<T> From<zx::Channel> for ClientEnd<T> {
fn from(chan: zx::Channel) -> Self {
ClientEnd {
inner: chan,
phantom: PhantomData,
}
}
}
impl<T: ServiceMarker> ::std::fmt::Debug for ClientEnd<T> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "ClientEnd(name={}, channel={:?})", T::NAME, self.inner)
}
}
impl<T> zx::HandleBased for ClientEnd<T> {}
/// The `Server` end of a FIDL connection.
#[derive(Eq, PartialEq, Hash)]
pub struct ServerEnd<T> {
inner: zx::Channel,
phantom: PhantomData<T>,
}
impl<T> ServerEnd<T> {
/// Create a new `ServerEnd` from the provided channel.
pub fn new(inner: zx::Channel) -> ServerEnd<T> {
ServerEnd { inner, phantom: PhantomData }
}
/// Extract the inner channel.
pub fn into_channel(self) -> zx::Channel {
self.inner
}
/// Create a stream of requests off of the channel.
pub fn into_stream(self) -> Result<T::RequestStream, Error>
where T: ServiceMarker,
{
Ok(T::RequestStream::from_channel(
fasync::Channel::from_channel(self.inner)
.map_err(Error::AsyncChannel)?))
}
/// Create a stream of requests and an event-sending handle
/// from the channel.
pub fn into_stream_and_control_handle(self)
-> Result<(T::RequestStream, <T::RequestStream as RequestStream>::ControlHandle), Error>
where T: ServiceMarker,
{
let stream = self.into_stream()?;
let control_handle = stream.control_handle();
Ok((stream, control_handle))
}
}
impl<T> zx::AsHandleRef for ServerEnd<T> {
fn as_handle_ref(&self) -> zx::HandleRef {
self.inner.as_handle_ref()
}
}
impl<T> From<ServerEnd<T>> for zx::Handle {
fn from(server: ServerEnd<T>) -> zx::Handle {
server.into_channel().into()
}
}
impl<T> From<zx::Handle> for ServerEnd<T> {
fn from(handle: zx::Handle) -> Self {
ServerEnd {
inner: handle.into(),
phantom: PhantomData,
}
}
}
impl<T> From<zx::Channel> for ServerEnd<T> {
fn from(chan: zx::Channel) -> Self {
ServerEnd {
inner: chan,
phantom: PhantomData,
}
}
}
impl<T: ServiceMarker> ::std::fmt::Debug for ServerEnd<T> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "ServerEnd(name={}, channel={:?})", T::NAME, self.inner)
}
}
impl<T> zx::HandleBased for ServerEnd<T> {}
handle_based_codable![ClientEnd :- <T,>, ServerEnd :- <T,>,];
/// Creates client and server endpoints connected to by a channel.
pub fn create_endpoints<T: ServiceMarker>() -> Result<(ClientEnd<T>, ServerEnd<T>), Error> {
let (client, server) = zx::Channel::create().map_err(Error::ChannelPairCreate)?;
let client_end = ClientEnd::<T>::new(client);
let server_end = ServerEnd::new(server);
Ok((client_end, server_end))
}
/// Create a client proxy and a server endpoint connected to it by a channel.
///
/// Useful for sending channel handles to calls that take arguments
/// of type `request<SomeInterface>`
pub fn create_proxy<T: ServiceMarker>() -> Result<(T::Proxy, ServerEnd<T>), Error> {
let (client, server) = create_endpoints()?;
Ok((client.into_proxy()?, server))
}
/// Create a request stream and a client endpoint connected to it by a channel.
///
/// Useful for sending channel handles to calls that take arguments
/// of type `SomeInterface`
pub fn create_request_stream<T: ServiceMarker>() -> Result<(ClientEnd<T>, T::RequestStream), Error> {
let (client, server) = create_endpoints()?;
Ok((client, server.into_stream()?))
}