Skip to content

Commit

Permalink
fix build for impl_trait_in_assoc_type
Browse files Browse the repository at this point in the history
TAIT is taking on a new direction, and a smaller scope, more restricted
feature gate - impl_trait_in_assoc_type - is added, which only allows
impl Trait for associated types. This breaks some of our code, and this
commit fixes that.

Signed-off-by: Yuxuan Shui <[email protected]>
  • Loading branch information
yshui committed Jun 13, 2023
1 parent 8dcb042 commit 1285951
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 156 deletions.
5 changes: 3 additions & 2 deletions crescent/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(type_alias_impl_trait)]
#![feature(impl_trait_in_assoc_type)]
use std::{
cell::RefCell,
os::{fd::OwnedFd, unix::net::UnixStream},
Expand Down Expand Up @@ -270,12 +270,13 @@ impl CrescentClient {

impl Client for CrescentClient {
type Connection = Connection<runa_io::WriteWithFd>;
type DispatchFut<'a, R> = runa_core::client::Dispatch<'a, Self, R> where R: runa_io::traits::buf::AsyncBufReadWithFd + 'a;
type EventDispatcher = EventDispatcher<Self>;
type Object = AnyObject;
type ObjectStore = Store<Self::Object>;
type ServerContext = Crescent;

type DispatchFut<'a, R> = impl std::future::Future<Output = bool> + 'a where R: runa_io::traits::buf::AsyncBufReadWithFd + 'a;

fn dispatch<'a, R>(&'a mut self, reader: Pin<&'a mut R>) -> Self::DispatchFut<'a, R>
where
R: runa_io::traits::buf::AsyncBufReadWithFd,
Expand Down
85 changes: 52 additions & 33 deletions runa-core/src/client/event_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,39 +18,59 @@ use futures_util::{
use super::traits;
use crate::utils::one_shot_signal;

type PairedEventHandlerFut<'a, H, Ctx>
where
H: traits::EventHandler<Ctx>,
Ctx: traits::Client,
= impl Future<Output = Result<(EventHandlerOutput, H), (H::Message, H)>> + 'a;

/// A helper function for storing the event handler's future.
/// Helper trait for implementing `paired_event_handler_driver`.
///
/// Event handler's generate a future that references the event handler itself,
/// if we store that directly in [`PairedEventHandler`] we would have a
/// self-referential struct, so we use this async fn to get around that.
///
/// The stop signal is needed so when the future can to be stopped early, for
/// example when a [`PendingEventFut`] is dropped.
fn paired_event_handler_driver<'ctx, H, Ctx: traits::Client>(
mut handler: H,
mut stop_signal: one_shot_signal::Receiver,
mut message: H::Message,
objects: &'ctx mut Ctx::ObjectStore,
connection: &'ctx mut Ctx::Connection,
server_context: &'ctx Ctx::ServerContext,
) -> PairedEventHandlerFut<'ctx, H, Ctx>
/// We need to name the type returned by `paired_event_handler_driver` so we can
/// store it. However the new `impl_trait_in_assoc_type` restricted TAIT to
/// associated types of traits only, so we have to use this helper trait to get
/// around that.
trait EventHandlerExt<Ctx: traits::Client>: traits::EventHandler<Ctx> + Sized {
type PairedEventHandlerFut<'a>: Future<Output = Result<(EventHandlerOutput, Self), (Self::Message, Self)>>
+ 'a;
fn paired_event_handler_driver<'ctx>(
self,
stop_signal: one_shot_signal::Receiver,
message: Self::Message,
objects: &'ctx mut Ctx::ObjectStore,
connection: &'ctx mut Ctx::Connection,
server_context: &'ctx Ctx::ServerContext,
) -> Self::PairedEventHandlerFut<'ctx>;
}

impl<Ctx, T> EventHandlerExt<Ctx> for T
where
H: traits::EventHandler<Ctx>,
Ctx: traits::Client,
T: traits::EventHandler<Ctx>,
{
async move {
use futures_util::{select, FutureExt};
select! {
() = stop_signal => {
Err((message, handler))
}
ret = handler.handle_event(objects, connection, server_context, &mut message).fuse() => {
Ok((ret, handler))
type PairedEventHandlerFut<'a> =
impl Future<Output = Result<(EventHandlerOutput, Self), (Self::Message, Self)>> + 'a;

/// A helper function for storing the event handler's future.
///
/// Event handler's generate a future that references the event handler
/// itself, if we store that directly in [`PairedEventHandler`] we would
/// have a self-referential struct, so we use this async fn to get
/// around that.
///
/// The stop signal is needed so when the future can to be stopped early,
/// for example when a [`PendingEventFut`] is dropped.
fn paired_event_handler_driver<'ctx>(
mut self,
mut stop_signal: one_shot_signal::Receiver,
mut message: Self::Message,
objects: &'ctx mut Ctx::ObjectStore,
connection: &'ctx mut Ctx::Connection,
server_context: &'ctx Ctx::ServerContext,
) -> Self::PairedEventHandlerFut<'ctx> {
async move {
use futures_util::{select, FutureExt};
select! {
() = stop_signal => {
Err((message, self))
}
ret = self.handle_event(objects, connection, server_context, &mut message).fuse() => {
Ok((ret, self))
}
}
}
}
Expand All @@ -66,7 +86,7 @@ struct PairedEventHandler<'fut, Ctx: traits::Client, ES: Stream, H: traits::Even
handler: Option<H>,
message: Option<ES::Item>,
#[pin]
fut: Option<PairedEventHandlerFut<'fut, H, Ctx>>,
fut: Option<<H as EventHandlerExt<Ctx>>::PairedEventHandlerFut<'fut>>,
stop_signal: Option<one_shot_signal::Sender>,
_ctx: PhantomData<Ctx>,
}
Expand Down Expand Up @@ -172,8 +192,7 @@ where
let (tx, stop_signal) = one_shot_signal::new_pair();
*this.stop_signal = Some(tx);

let new_fut = paired_event_handler_driver(
handler,
let new_fut = handler.paired_event_handler_driver(
stop_signal,
message,
objects,
Expand Down
129 changes: 58 additions & 71 deletions runa-core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,13 @@ pub mod event_dispatcher;
pub mod store;
pub mod traits;

use std::{future::Future, os::fd::RawFd, pin::Pin};
use std::{os::fd::RawFd, pin::Pin};

#[doc(inline)]
pub use event_dispatcher::EventDispatcher;
#[doc(inline)]
pub use store::Store;

/// Type of future returned by [`dispatch_to`].
pub type Dispatch<'a, Ctx, R>
where
Ctx: traits::Client + 'a,
Ctx::Object: for<'b> crate::objects::Object<Ctx, Request<'b> = (&'b [u8], &'b [RawFd])>,
R: runa_io::traits::buf::AsyncBufReadWithFd + 'a,
= impl Future<Output = bool> + 'a;

/// Reference implementation of the [`traits::Client::dispatch`] method.
///
/// This function reads a message from `reader`, looks up the corresponding
Expand All @@ -57,75 +49,70 @@ where
/// not, you are supposed to deserialize a wayland message from a
/// `(&[u8], &[RawFd])` tuple yourself and then dispatch the deserialized
/// message properly.
pub fn dispatch_to<'a, Ctx, R>(ctx: &'a mut Ctx, mut reader: Pin<&'a mut R>) -> Dispatch<'a, Ctx, R>
pub async fn dispatch_to<'a, Ctx, R>(ctx: &'a mut Ctx, mut reader: Pin<&'a mut R>) -> bool
where
R: runa_io::traits::buf::AsyncBufReadWithFd,
Ctx: traits::Client,
Ctx::Object: for<'b> crate::objects::Object<Ctx, Request<'b> = (&'b [u8], &'b [RawFd])>,
{
async move {
use runa_io::traits::{buf::Message, WriteMessage};
use runa_wayland_protocols::wayland::wl_display::v1 as wl_display;
use runa_wayland_types as types;
use traits::Store;

use crate::{error::ProtocolError, objects::AnyObject};
let Message {
object_id,
len,
data,
fds,
} = match R::next_message(reader.as_mut()).await {
Ok(v) => v,
// I/O error, no point sending the error to the client
Err(_) => return true,
};
let (ret, bytes_read, fds_read) =
<<Ctx as traits::Client>::Object as crate::objects::Object<Ctx>>::dispatch(
ctx,
object_id,
(data, fds),
)
.await;
let (mut fatal, error) = match ret {
Ok(_) => (false, None),
Err(e) => (
e.fatal(),
e.wayland_error()
.map(|(object_id, error_code)| (object_id, error_code, e.to_string())),
),
};
if let Some((object_id, error_code, msg)) = error {
// We are going to disconnect the client so we don't care about the
// error.
fatal |= ctx
.connection_mut()
.send(crate::objects::DISPLAY_ID, wl_display::events::Error {
object_id: types::Object(object_id),
code: error_code,
message: types::Str(msg.as_bytes()),
})
.await
.is_err();
}
if !fatal {
if bytes_read != len {
let len_opcode = u32::from_ne_bytes(data[0..4].try_into().unwrap());
let opcode = len_opcode & 0xffff;
tracing::error!(
"unparsed bytes in buffer, read ({bytes_read}) != received ({len}). \
object_id: {}@{object_id}, opcode: {opcode}",
ctx.objects()
.get::<Ctx::Object>(object_id)
.map(|o| o.interface())
.unwrap_or("unknown")
);
fatal = true;
}
reader.consume(bytes_read, fds_read);
use runa_io::traits::{buf::Message, WriteMessage};
use runa_wayland_protocols::wayland::wl_display::v1 as wl_display;
use runa_wayland_types as types;
use traits::Store;

use crate::{error::ProtocolError, objects::AnyObject};
let Message {
object_id,
len,
data,
fds,
} = match R::next_message(reader.as_mut()).await {
Ok(v) => v,
// I/O error, no point sending the error to the client
Err(_) => return true,
};
let (ret, bytes_read, fds_read) = <<Ctx as traits::Client>::Object as crate::objects::Object<
Ctx,
>>::dispatch(ctx, object_id, (data, fds))
.await;
let (mut fatal, error) = match ret {
Ok(_) => (false, None),
Err(e) => (
e.fatal(),
e.wayland_error()
.map(|(object_id, error_code)| (object_id, error_code, e.to_string())),
),
};
if let Some((object_id, error_code, msg)) = error {
// We are going to disconnect the client so we don't care about the
// error.
fatal |= ctx
.connection_mut()
.send(crate::objects::DISPLAY_ID, wl_display::events::Error {
object_id: types::Object(object_id),
code: error_code,
message: types::Str(msg.as_bytes()),
})
.await
.is_err();
}
if !fatal {
if bytes_read != len {
let len_opcode = u32::from_ne_bytes(data[0..4].try_into().unwrap());
let opcode = len_opcode & 0xffff;
tracing::error!(
"unparsed bytes in buffer, read ({bytes_read}) != received ({len}). object_id: \
{}@{object_id}, opcode: {opcode}",
ctx.objects()
.get::<Ctx::Object>(object_id)
.map(|o| o.interface())
.unwrap_or("unknown")
);
fatal = true;
}
fatal
reader.consume(bytes_read, fds_read);
}
fatal
}

#[doc(hidden)] // not ready for use yet
Expand Down
5 changes: 1 addition & 4 deletions runa-core/src/events/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ impl<E: Clone> Ring<E> {
}
}

/// Type of future returned by [`Broadcast::broadcast_owned`].
pub type BroadcastOwned<E: Clone + 'static> = impl Future<Output = ()> + 'static;

impl<E: Clone> Broadcast<E> {
/// Send a new event to all receivers
pub fn broadcast(&self, msg: E) -> impl Future<Output = ()> + '_ {
Expand All @@ -87,7 +84,7 @@ impl<E: Clone> Broadcast<E> {

/// Like [`Self::broadcast`], but the returned future doesn't borrow from
/// `self`.
pub fn broadcast_owned(&self, msg: E) -> BroadcastOwned<E>
pub fn broadcast_owned(&self, msg: E) -> impl Future<Output = ()>
where
E: 'static,
{
Expand Down
18 changes: 7 additions & 11 deletions runa-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
//! creating a new client context each time a new client connects. It also
//! provides access to the globals.
// We can drop trait_upcasting if necessary. `type_alias_impl_trait` is
// We can drop trait_upcasting if necessary. `impl_trait_in_assoc_type` is
// the indispensable feature here.
#![allow(incomplete_features)]
#![feature(type_alias_impl_trait, trait_upcasting)]
#![feature(impl_trait_in_assoc_type, trait_upcasting)]
#![warn(
missing_debug_implementations,
missing_copy_implementations,
Expand Down Expand Up @@ -266,7 +266,8 @@ impl<D> std::fmt::Debug for IdAlloc<D> {

impl<D> Serial for IdAlloc<D> {
type Data = D;
type Iter<'a> = <&'a Self as IntoIterator>::IntoIter where Self: 'a;

type Iter<'a> = impl Iterator<Item=(u32, &'a D)> where Self: 'a;

fn next_serial(&mut self, data: Self::Data) -> u32 {
loop {
Expand Down Expand Up @@ -299,17 +300,12 @@ impl<D> Serial for IdAlloc<D> {
}
}

#[doc(hidden)]
pub type IdIter<'a, D>
where
D: 'a,
= impl Iterator<Item = (u32, &'a D)> + 'a;

impl<'a, D: 'a> IntoIterator for &'a IdAlloc<D> {
type IntoIter = IdIter<'a, D> where Self: 'a;
type Item = (u32, &'a D);

fn into_iter(self) -> IdIter<'a, D> {
type IntoIter = impl Iterator<Item = (u32, &'a D)>;

fn into_iter(self) -> Self::IntoIter {
self.data.iter().map(|(k, v)| (*k, v))
}
}
Expand Down
11 changes: 7 additions & 4 deletions runa-core/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,8 @@ impl<G: 'static> EventSource<GlobalsUpdate<G>> for GlobalStore<G> {
/// GlobalStore will notify listeners when globals are added or removed. The
/// notification will be sent to the slot registered as "wl_registry".
impl<G: 'static> traits::GlobalStore<G> for GlobalStore<G> {
type Iter<'a> = <&'a Self as IntoIterator>::IntoIter where Self: 'a, G: 'a;

type InsertFut<'a, I> = impl Future<Output = u32> + 'a where Self: 'a, I: 'a + Into<G>;
type Iter<'a> = impl Iterator<Item = (u32, &'a Rc<G>)> where Self: 'a, G: 'a;
type RemoveFut<'a> = impl Future<Output = bool> + 'a where Self: 'a;

fn insert<'a, I: Into<G> + 'a>(&'a mut self, global: I) -> Self::InsertFut<'_, I> {
Expand Down Expand Up @@ -82,10 +81,14 @@ impl<G: 'static> traits::GlobalStore<G> for GlobalStore<G> {
self.into_iter()
}
}
impl<'a, G> IntoIterator for &'a GlobalStore<G> {
type IntoIter = crate::IdIter<'a, Rc<G>>;
impl<'a, G> IntoIterator for &'a GlobalStore<G>
where
G: 'a,
{
type Item = (u32, &'a Rc<G>);

type IntoIter = impl Iterator<Item = (u32, &'a Rc<G>)> + 'a;

fn into_iter(self) -> Self::IntoIter {
self.globals.iter()
}
Expand Down
Loading

0 comments on commit 1285951

Please sign in to comment.