use std::{
ffi::CString,
fmt,
os::unix::{
io::{BorrowedFd, OwnedFd, RawFd},
net::UnixStream,
},
sync::Arc,
};
use crate::protocol::{Interface, Message, ObjectInfo};
pub use crate::types::server::{Credentials, DisconnectReason, GlobalInfo, InitError, InvalidId};
use super::server_impl;
pub trait ObjectData<D>: downcast_rs::DowncastSync {
fn request(
self: Arc<Self>,
handle: &Handle,
data: &mut D,
client_id: ClientId,
msg: Message<ObjectId, OwnedFd>,
) -> Option<Arc<dyn ObjectData<D>>>;
fn destroyed(
self: Arc<Self>,
handle: &Handle,
data: &mut D,
client_id: ClientId,
object_id: ObjectId,
);
#[cfg_attr(coverage, coverage(off))]
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ObjectData").finish_non_exhaustive()
}
}
downcast_rs::impl_downcast!(sync ObjectData<D>);
impl<D: 'static> std::fmt::Debug for dyn ObjectData<D> {
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.debug(f)
}
}
pub trait GlobalHandler<D>: downcast_rs::DowncastSync {
fn can_view(
&self,
_client_id: ClientId,
_client_data: &Arc<dyn ClientData>,
_global_id: GlobalId,
) -> bool {
true
}
fn bind(
self: Arc<Self>,
handle: &Handle,
data: &mut D,
client_id: ClientId,
global_id: GlobalId,
object_id: ObjectId,
) -> Arc<dyn ObjectData<D>>;
#[cfg_attr(coverage, coverage(off))]
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GlobalHandler").finish_non_exhaustive()
}
}
impl<D: 'static> std::fmt::Debug for dyn GlobalHandler<D> {
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.debug(f)
}
}
downcast_rs::impl_downcast!(sync GlobalHandler<D>);
pub trait ClientData: downcast_rs::DowncastSync {
fn initialized(&self, _client_id: ClientId) {}
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {}
#[cfg_attr(coverage, coverage(off))]
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClientData").finish_non_exhaustive()
}
}
impl std::fmt::Debug for dyn ClientData {
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.debug(f)
}
}
impl ClientData for () {}
downcast_rs::impl_downcast!(sync ClientData);
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ObjectId {
pub(crate) id: server_impl::InnerObjectId,
}
impl ObjectId {
pub fn is_null(&self) -> bool {
self.id.is_null()
}
#[inline]
pub fn null() -> ObjectId {
server_impl::InnerHandle::null_id()
}
pub fn interface(&self) -> &'static Interface {
self.id.interface()
}
pub fn same_client_as(&self, other: &Self) -> bool {
self.id.same_client_as(&other.id)
}
pub fn protocol_id(&self) -> u32 {
self.id.protocol_id()
}
}
impl fmt::Display for ObjectId {
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.id.fmt(f)
}
}
impl fmt::Debug for ObjectId {
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.id.fmt(f)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ClientId {
pub(crate) id: server_impl::InnerClientId,
}
impl fmt::Debug for ClientId {
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.id.fmt(f)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct GlobalId {
pub(crate) id: server_impl::InnerGlobalId,
}
impl fmt::Debug for GlobalId {
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.id.fmt(f)
}
}
#[derive(Clone, Debug)]
pub struct Handle {
pub(crate) handle: server_impl::InnerHandle,
}
#[derive(Clone, Debug)]
pub struct WeakHandle {
pub(crate) handle: server_impl::WeakInnerHandle,
}
impl WeakHandle {
#[inline]
pub fn upgrade(&self) -> Option<Handle> {
self.handle.upgrade().map(|handle| Handle { handle })
}
}
impl Handle {
#[inline]
pub fn downgrade(&self) -> WeakHandle {
WeakHandle { handle: self.handle.downgrade() }
}
#[inline]
pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
self.handle.object_info(id.id)
}
#[inline]
pub fn insert_client(
&mut self,
stream: UnixStream,
data: Arc<dyn ClientData>,
) -> std::io::Result<ClientId> {
Ok(ClientId { id: self.handle.insert_client(stream, data)? })
}
#[inline]
pub fn get_client(&self, id: ObjectId) -> Result<ClientId, InvalidId> {
self.handle.get_client(id.id)
}
#[inline]
pub fn get_client_data(&self, id: ClientId) -> Result<Arc<dyn ClientData>, InvalidId> {
self.handle.get_client_data(id.id)
}
#[inline]
pub fn get_client_credentials(&self, id: ClientId) -> Result<Credentials, InvalidId> {
self.handle.get_client_credentials(id.id)
}
#[inline]
pub fn with_all_clients(&self, f: impl FnMut(ClientId)) {
self.handle.with_all_clients(f)
}
#[inline]
pub fn with_all_objects_for(
&self,
client_id: ClientId,
f: impl FnMut(ObjectId),
) -> Result<(), InvalidId> {
self.handle.with_all_objects_for(client_id.id, f)
}
#[inline]
pub fn object_for_protocol_id(
&self,
client_id: ClientId,
interface: &'static Interface,
protocol_id: u32,
) -> Result<ObjectId, InvalidId> {
self.handle.object_for_protocol_id(client_id.id, interface, protocol_id)
}
#[inline]
pub fn create_object<D: 'static>(
&self,
client_id: ClientId,
interface: &'static Interface,
version: u32,
data: Arc<dyn ObjectData<D>>,
) -> Result<ObjectId, InvalidId> {
self.handle.create_object(client_id.id, interface, version, data)
}
#[inline]
pub fn send_event(&self, msg: Message<ObjectId, RawFd>) -> Result<(), InvalidId> {
self.handle.send_event(msg)
}
#[inline]
pub fn get_object_data<D: 'static>(
&self,
id: ObjectId,
) -> Result<Arc<dyn ObjectData<D>>, InvalidId> {
self.handle.get_object_data(id.id)
}
#[inline]
pub fn get_object_data_any(
&self,
id: ObjectId,
) -> Result<Arc<dyn std::any::Any + Send + Sync>, InvalidId> {
self.handle.get_object_data_any(id.id)
}
#[inline]
pub fn set_object_data<D: 'static>(
&self,
id: ObjectId,
data: Arc<dyn ObjectData<D>>,
) -> Result<(), InvalidId> {
self.handle.set_object_data(id.id, data)
}
#[inline]
pub fn post_error(&self, object_id: ObjectId, error_code: u32, message: CString) {
self.handle.post_error(object_id.id, error_code, message)
}
#[inline]
pub fn kill_client(&self, client_id: ClientId, reason: DisconnectReason) {
self.handle.kill_client(client_id.id, reason)
}
#[inline]
pub fn create_global<D: 'static>(
&self,
interface: &'static Interface,
version: u32,
handler: Arc<dyn GlobalHandler<D>>,
) -> GlobalId {
GlobalId { id: self.handle.create_global(interface, version, handler) }
}
#[inline]
pub fn disable_global<D: 'static>(&self, id: GlobalId) {
self.handle.disable_global::<D>(id.id)
}
#[inline]
pub fn remove_global<D: 'static>(&self, id: GlobalId) {
self.handle.remove_global::<D>(id.id)
}
#[inline]
pub fn global_info(&self, id: GlobalId) -> Result<GlobalInfo, InvalidId> {
self.handle.global_info(id.id)
}
#[inline]
pub fn get_global_handler<D: 'static>(
&self,
id: GlobalId,
) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
self.handle.get_global_handler(id.id)
}
pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
self.handle.flush(client)
}
}
#[derive(Debug)]
pub struct Backend<D: 'static> {
pub(crate) backend: server_impl::InnerBackend<D>,
}
impl<D> Backend<D> {
#[inline]
pub fn new() -> Result<Self, InitError> {
Ok(Self { backend: server_impl::InnerBackend::new()? })
}
#[inline]
pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
self.backend.flush(client)
}
#[inline]
pub fn handle(&self) -> Handle {
self.backend.handle()
}
#[inline]
pub fn poll_fd(&self) -> BorrowedFd {
self.backend.poll_fd()
}
#[inline]
pub fn dispatch_single_client(
&mut self,
data: &mut D,
client_id: ClientId,
) -> std::io::Result<usize> {
self.backend.dispatch_client(data, client_id.id)
}
#[inline]
pub fn dispatch_all_clients(&mut self, data: &mut D) -> std::io::Result<usize> {
self.backend.dispatch_all_clients(data)
}
}
#[allow(dead_code)]
pub(crate) struct DumbObjectData;
#[allow(dead_code)]
impl<D> ObjectData<D> for DumbObjectData {
#[cfg_attr(coverage, coverage(off))]
fn request(
self: Arc<Self>,
_handle: &Handle,
_data: &mut D,
_client_id: ClientId,
_msg: Message<ObjectId, OwnedFd>,
) -> Option<Arc<dyn ObjectData<D>>> {
unreachable!()
}
#[cfg_attr(coverage, coverage(off))]
fn destroyed(
self: Arc<Self>,
_handle: &Handle,
_: &mut D,
_client_id: ClientId,
_object_id: ObjectId,
) {
}
}