use std::{any::Any, error::Error, pin::Pin};
use futures_core::{Future, Stream};
use runa_io::traits::WriteMessage;
use crate::{events, objects};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StoreUpdateKind {
Inserted {
interface: &'static str,
},
Removed {
interface: &'static str,
},
Replaced {
old_interface: &'static str,
new_interface: &'static str,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StoreUpdate {
pub object_id: u32,
pub kind: StoreUpdateKind,
}
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub enum GetError {
#[error("Object ID {0} not found")]
IdNotFound(u32),
#[error("Object ID {0} is not of the requested type")]
TypeMismatch(u32),
}
impl From<GetError> for crate::error::Error {
fn from(e: GetError) -> Self {
use GetError::*;
match e {
IdNotFound(id) => Self::UnknownObject(id),
TypeMismatch(id) => Self::InvalidObject(id),
}
}
}
pub trait Store<O>: events::EventSource<StoreUpdate> {
type ByType<'a, T>: Iterator<Item = (u32, &'a T)> + 'a
where
O: 'a,
T: objects::MonoObject + 'a,
Self: 'a;
type IdsByType<'a, T>: Iterator<Item = u32> + 'a
where
O: 'a,
T: 'static,
Self: 'a;
fn insert<T: Into<O> + 'static>(&mut self, id: u32, object: T) -> Result<&mut T, T>;
fn insert_with_state<T: Into<O> + objects::MonoObject + 'static>(
&mut self,
id: u32,
object: T,
) -> Result<(&mut T, &mut T::SingletonState), T>;
fn allocate<T: Into<O> + 'static>(&mut self, object: T) -> Result<(u32, &mut T), T>;
fn remove(&mut self, id: u32) -> Option<O>;
fn get_state<T: objects::MonoObject>(&self) -> Option<&T::SingletonState>;
fn get_state_mut<T: objects::MonoObject>(&mut self) -> Option<&mut T::SingletonState>;
fn get_with_state<T: objects::MonoObject>(
&self,
id: u32,
) -> Result<(&T, &T::SingletonState), GetError>;
fn get_with_state_mut<T: objects::MonoObject>(
&mut self,
id: u32,
) -> Result<(&mut T, &mut T::SingletonState), GetError>;
fn get<T: 'static>(&self, id: u32) -> Result<&T, GetError>;
fn get_mut<T: 'static>(&mut self, id: u32) -> Result<&mut T, GetError>;
fn contains(&self, id: u32) -> bool;
fn try_insert_with(&mut self, id: u32, f: impl FnOnce() -> O) -> Option<&mut O>;
fn try_insert_with_state<T: Into<O> + objects::MonoObject + 'static>(
&mut self,
id: u32,
f: impl FnOnce(&mut T::SingletonState) -> T,
) -> Option<(&mut T, &mut T::SingletonState)>;
fn by_type<T: objects::MonoObject + 'static>(&self) -> Self::ByType<'_, T>;
fn ids_by_type<T: 'static>(&self) -> Self::IdsByType<'_, T>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EventHandlerAction {
Stop,
Keep,
}
pub trait EventHandler<Ctx: Client>: 'static {
type Message;
type Future<'ctx>: Future<
Output = Result<
EventHandlerAction,
Box<dyn Error + std::marker::Send + Sync + 'static>,
>,
> + 'ctx;
fn handle_event<'ctx>(
&'ctx mut self,
objects: &'ctx mut Ctx::ObjectStore,
connection: &'ctx mut Ctx::Connection,
server_context: &'ctx Ctx::ServerContext,
message: &'ctx mut Self::Message,
) -> Self::Future<'ctx>;
}
pub trait EventDispatcher<Ctx: Client> {
fn add_event_handler<M: Any>(
&mut self,
event_stream: impl Stream<Item = M> + 'static,
handler: impl EventHandler<Ctx, Message = M> + 'static,
);
}
#[derive(Debug)]
#[non_exhaustive]
pub struct ClientParts<'a, C: Client> {
pub server_context: &'a C::ServerContext,
pub objects: &'a mut C::ObjectStore,
pub connection: &'a mut C::Connection,
pub event_dispatcher: &'a mut C::EventDispatcher,
}
impl<'a, C: Client> ClientParts<'a, C> {
pub fn new(
server_context: &'a C::ServerContext,
objects: &'a mut C::ObjectStore,
connection: &'a mut C::Connection,
event_dispatcher: &'a mut C::EventDispatcher,
) -> Self {
Self {
server_context,
objects,
connection,
event_dispatcher,
}
}
}
pub trait Client: Sized + 'static {
type ServerContext: crate::server::traits::Server<ClientContext = Self> + 'static;
type ObjectStore: Store<Self::Object>;
type Connection: WriteMessage + Unpin + 'static;
type Object: objects::Object<Self> + objects::AnyObject + std::fmt::Debug;
type EventDispatcher: EventDispatcher<Self> + 'static;
type DispatchFut<'a, R>: Future<Output = bool> + 'a
where
Self: 'a,
R: runa_io::traits::buf::AsyncBufReadWithFd + 'a;
fn server_context(&self) -> &Self::ServerContext;
fn objects(&self) -> &Self::ObjectStore;
fn connection_mut(&mut self) -> &mut Self::Connection {
self.as_mut_parts().connection
}
fn objects_mut(&mut self) -> &mut Self::ObjectStore {
self.as_mut_parts().objects
}
fn event_dispatcher_mut(&mut self) -> &mut Self::EventDispatcher {
self.as_mut_parts().event_dispatcher
}
fn as_mut_parts(&mut self) -> ClientParts<'_, Self>;
fn dispatch<'a, R>(&'a mut self, reader: Pin<&'a mut R>) -> Self::DispatchFut<'a, R>
where
R: runa_io::traits::buf::AsyncBufReadWithFd;
}