gmt_dos-actors-clients_interface 1.5.1

Giant Magellan Telescope Dynamic Optical Simulation Actor to Clients Interface
Documentation
/*!
# gmt_dos-actors-clients_interface

Interface definition betweeen an [actor] and an [actor]'s client.

Data is passed from the [actor] to the client by invoking [Read::read] from the client.

Data is passed from the client to the [actor] by invoking [Write::write] from the client.

The client state may be updated by invoking [Update::update] from the client

The macro [chain] conveniently allows to invoke the sequence of [Read], [Update] and [Write] traits to a series of clients.

[actor]: https://docs.rs/gmt_dos-actors
*/

use std::{any::type_name, convert::Infallible, marker::PhantomData, sync::Arc};

mod data;
pub mod doublet;
pub use data::Data;
pub use dos_uid_derive::UID;
pub mod units;

pub mod select;

#[cfg(feature = "filing")]
pub mod filing;

pub type Assoc<U> = <U as UniqueIdentifier>::DataType;

/// Marker to allow the UID data to be either left or right added or substracted with the [Operator](https://docs.rs/gmt_dos-clients/latest/gmt_dos_clients/operator/index.html) client
pub trait OperatorLeftRight {
    const LEFT: bool;
}
/// Units conversion marker trait for clients
pub trait Units {}

/// Timer heartbeat identifier
pub enum Tick {}
impl UniqueIdentifier for Tick {
    type DataType = ();
}
/// Timer marker trait
pub trait TimerMarker {}
impl<T> Read<Tick> for T
where
    T: TimerMarker + Update,
{
    fn read(&mut self, _: Data<Tick>) {}
}

/// Defines the data type associated with unique identifier data type
pub trait UniqueIdentifier: Send + Sync {
    const PORT: u16 = 50_000;
    type DataType: Send + Sync;
}
pub trait Quote {
    fn quote() -> String;
}
impl<U: UniqueIdentifier> Quote for U {
    fn quote() -> String {
        fn inner(name: &str) -> String {
            if let Some((prefix, suffix)) = name.split_once('<') {
                let generics: Vec<_> = suffix.split(',').map(|s| inner(s)).collect();
                format!("{}<{}", inner(prefix), generics.join(","))
            } else {
                if let Some((_, suffix)) = name.rsplit_once("::") {
                    suffix.into()
                } else {
                    name.into()
                }
            }
        }
        inner(type_name::<U>())
    }
}

impl UniqueIdentifier for () {
    type DataType = ();
}

/// Actor client state update interface
pub trait Update: Send + Sync {
    fn update(&mut self) {}
}
/// Actor client state update fallible interface
pub trait TryUpdate: Send + Sync {
    type Error: std::error::Error + Send + Sync;
    fn try_update(&mut self) -> std::result::Result<&mut Self, Self::Error>;
    fn boxed_try_update<'a, 'b>(
        &'a mut self,
    ) -> std::result::Result<&'a mut Self, Box<dyn std::error::Error + Send + Sync + 'b>>
    where
        <Self as TryUpdate>::Error: 'b,
    {
        self.try_update().map_err(|e| e.into())
    }
}
impl<C: Update> TryUpdate for C {
    type Error = Infallible;
    fn try_update(&mut self) -> std::result::Result<&mut Self, Self::Error> {
        <Self as Update>::update(self);
        Ok(self)
    }
}

/// Client input data reader interface
pub trait Read<U: UniqueIdentifier>: Update {
    /// Read data from an input
    fn read(&mut self, data: Data<U>);
}
/// Client input data reader fallible interface
pub trait TryRead<U: UniqueIdentifier>: TryUpdate {
    type Error: std::error::Error + Send + Sync;
    /// Read data from an input
    fn try_read(
        &mut self,
        data: Data<U>,
    ) -> std::result::Result<&mut Self, <Self as TryRead<U>>::Error>;
    fn boxed_try_read<'a, 'b>(
        &'a mut self,
        data: Data<U>,
    ) -> std::result::Result<&'a mut Self, Box<dyn std::error::Error + Send + Sync + 'b>>
    where
        <Self as TryRead<U>>::Error: 'b,
    {
        self.try_read(data).map_err(move |e| e.into())
    }
}
impl<U: UniqueIdentifier, C: Read<U>> TryRead<U> for C {
    type Error = Infallible;

    fn try_read(
        &mut self,
        data: Data<U>,
    ) -> std::result::Result<&mut Self, <Self as TryRead<U>>::Error> {
        <Self as Read<U>>::read(self, data);
        Ok(self)
    }
}
/// Client output data writer interface
pub trait Write<U: UniqueIdentifier>: Update {
    fn write(&mut self) -> Option<Data<U>>;
}
/// Client output data writer fallible interface
pub trait TryWrite<U: UniqueIdentifier>: TryUpdate {
    type Error: std::error::Error + Send + Sync;
    fn try_write(&mut self) -> std::result::Result<Option<Data<U>>, <Self as TryWrite<U>>::Error>;
    fn boxed_try_write<'a, 'b>(
        &'a mut self,
    ) -> std::result::Result<Option<Data<U>>, Box<dyn std::error::Error + Send + Sync + 'b>>
    where
        <Self as TryWrite<U>>::Error: 'b,
    {
        self.try_write().map_err(move |e| e.into())
    }
}
impl<U: UniqueIdentifier, C: Write<U>> TryWrite<U> for C {
    type Error = Infallible;

    fn try_write(&mut self) -> std::result::Result<Option<Data<U>>, <Self as TryWrite<U>>::Error> {
        Ok(<Self as Write<U>>::write(self))
    }
}
/// Interface for IO data sizes
pub trait Size<U: UniqueIdentifier>: Update {
    fn len(&self) -> usize;
}

pub struct NoneClient<U, V = U>(PhantomData<U>, PhantomData<V>);
impl<U: UniqueIdentifier, V: UniqueIdentifier> Update for NoneClient<U, V> {}
impl<U: UniqueIdentifier, V: UniqueIdentifier> Read<U> for NoneClient<U, V> {
    fn read(&mut self, _: Data<U>) {}
}
impl<U: UniqueIdentifier, V: UniqueIdentifier> Write<V> for NoneClient<U, V> {
    fn write(&mut self) -> Option<Data<V>> {
        None
    }
}

pub trait Who<T> {
    /// Returns type name
    fn who(&self) -> String {
        type_name::<T>().to_string()
    }
    fn highlight(&self) -> String {
        let me = <Self as Who<T>>::who(&self);
        paris::formatter::colorize_string(format!("<italic><on-bright-cyan>{}</>", me))
    }
    fn lite(&self) -> String {
        let me = <Self as Who<T>>::who(&self);
        paris::formatter::colorize_string(format!("<italic><bright-cyan>{}</>", me))
    }
}

/// Pretty prints error message
pub fn print_info<S: Into<String>>(msg: S, e: Option<&dyn std::error::Error>) {
    if let Some(e) = e {
        let mut msg: Vec<String> = vec![msg.into()];
        msg.push(format!("{}", e));
        let mut current = e.source();
        while let Some(cause) = current {
            msg.push(format!("{}", cause));
            current = cause.source();
        }
        eprintln!("{}", msg.join("\n .due to: "))
    } else {
        log::debug!("{}", msg.into())
    }
}

/// Interface for data logging types
pub trait Entry<U: UniqueIdentifier>: Update {
    /// Adds an entry to the logger
    fn entry(&mut self, size: usize);
}

pub fn trim_type_name<T>() -> String {
    fn trim(name: &str) -> String {
        if let Some((prefix, suffix)) = name.split_once('<') {
            let generics: Vec<_> = suffix.split(',').map(|s| trim(s)).collect();
            format!("{}<{}", trim(prefix), generics.join(","))
        } else {
            if let Some((_, suffix)) = name.rsplit_once("::") {
                suffix.into()
            } else {
                name.into()
            }
        }
    }
    trim(type_name::<T>())
}

mod chain;

/// UID to flatten `Vec<Arc<Vec<f64>>>` into `Vec<f64>`
///
/// The flattening happened within [Write]`<Flatten<U>>` that
/// get the data from invoking [Write]`<U>` on `Self`
pub struct Flatten<U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>>(PhantomData<U>);
impl<U> UniqueIdentifier for Flatten<U>
where
    U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>,
{
    type DataType = Vec<f64>;
    const PORT: u16 = <U as UniqueIdentifier>::PORT;
}

/// Marker trait for clients implementing [Write]`<`[Flatten]`<U>>`
pub trait WriteFlatten {}

impl<U, C> Write<Flatten<U>> for C
where
    U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>,
    C: WriteFlatten + Write<U>,
{
    fn write(&mut self) -> Option<Data<Flatten<U>>> {
        <_ as Write<U>>::write(self).map(|data| {
            data.into_arc()
                .iter()
                .flat_map(|data| data.as_slice().to_vec())
                .collect::<Vec<f64>>()
                .into()
        })
    }
}
impl<U, C> Size<Flatten<U>> for C
where
    U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>,
    C: WriteFlatten + Size<U>,
{
    fn len(&self) -> usize {
        <_ as Size<U>>::len(self)
    }
}

pub struct Left<U: UniqueIdentifier>(PhantomData<U>);
impl<U> UniqueIdentifier for Left<U>
where
    U: UniqueIdentifier,
{
    type DataType = <U as UniqueIdentifier>::DataType;

    const PORT: u16 = <U as UniqueIdentifier>::PORT;
}

pub struct Right<U: UniqueIdentifier>(PhantomData<U>);
impl<U> UniqueIdentifier for Right<U>
where
    U: UniqueIdentifier,
{
    type DataType = <U as UniqueIdentifier>::DataType;

    const PORT: u16 = <U as UniqueIdentifier>::PORT;
}