gmt_dos_actors_clients_interface/
lib.rs

1/*!
2# gmt_dos-actors-clients_interface
3
4Interface definition betweeen an [actor] and an [actor]'s client.
5
6Data is passed from the [actor] to the client by invoking [Read::read] from the client.
7
8Data is passed from the client to the [actor] by invoking [Write::write] from the client.
9
10The client state may be updated by invoking [Update::update] from the client
11
12The macro [chain] conveniently allows to invoke the sequence of [Read], [Update] and [Write] traits to a series of clients.
13
14[actor]: https://docs.rs/gmt_dos-actors
15*/
16
17use std::{any::type_name, marker::PhantomData, sync::Arc};
18
19mod data;
20pub mod doublet;
21pub mod optics;
22pub use data::Data;
23pub use dos_uid_derive::UID;
24pub mod units;
25
26pub mod select;
27
28#[cfg(feature = "filing")]
29pub mod filing;
30
31pub type Assoc<U> = <U as UniqueIdentifier>::DataType;
32
33/// 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
34pub trait OperatorLeftRight {
35    const LEFT: bool;
36}
37/// Units conversion marker trait for clients
38pub trait Units {}
39
40/// Timer heartbeat identifier
41pub enum Tick {}
42impl UniqueIdentifier for Tick {
43    type DataType = ();
44}
45/// Timer marker trait
46pub trait TimerMarker {}
47impl<T> Read<Tick> for T
48where
49    T: TimerMarker + Update,
50{
51    fn read(&mut self, _: Data<Tick>) {}
52}
53
54/// Defines the data type associated with unique identifier data type
55pub trait UniqueIdentifier: Send + Sync {
56    const PORT: u16 = 50_000;
57    type DataType: Send + Sync;
58}
59pub trait Quote {
60    fn quote() -> String;
61}
62impl<U: UniqueIdentifier> Quote for U {
63    fn quote() -> String {
64        fn inner(name: &str) -> String {
65            if let Some((prefix, suffix)) = name.split_once('<') {
66                let generics: Vec<_> = suffix.split(',').map(|s| inner(s)).collect();
67                format!("{}<{}", inner(prefix), generics.join(","))
68            } else {
69                if let Some((_, suffix)) = name.rsplit_once("::") {
70                    suffix.into()
71                } else {
72                    name.into()
73                }
74            }
75        }
76        inner(type_name::<U>())
77    }
78}
79
80impl UniqueIdentifier for () {
81    type DataType = ();
82}
83
84/// Actor client state update interface
85pub trait Update: Send + Sync {
86    fn update(&mut self) {}
87}
88/// Client input data reader interface
89pub trait Read<U: UniqueIdentifier>: Update {
90    /// Read data from an input
91    fn read(&mut self, data: Data<U>);
92}
93/// Client output data writer interface
94pub trait Write<U: UniqueIdentifier>: Update {
95    fn write(&mut self) -> Option<Data<U>>;
96}
97/// Interface for IO data sizes
98pub trait Size<U: UniqueIdentifier>: Update {
99    fn len(&self) -> usize;
100}
101
102pub trait Who<T> {
103    /// Returns type name
104    fn who(&self) -> String {
105        type_name::<T>().to_string()
106    }
107    fn highlight(&self) -> String {
108        let me = <Self as Who<T>>::who(&self);
109        paris::formatter::colorize_string(format!("<italic><on-bright-cyan>{}</>", me))
110    }
111    fn lite(&self) -> String {
112        let me = <Self as Who<T>>::who(&self);
113        paris::formatter::colorize_string(format!("<italic><bright-cyan>{}</>", me))
114    }
115}
116
117use log::{info, warn};
118
119/// Pretty prints error message
120pub fn print_info<S: Into<String>>(msg: S, e: Option<&dyn std::error::Error>) {
121    if let Some(e) = e {
122        let mut msg: Vec<String> = vec![msg.into()];
123        msg.push(format!("{}", e));
124        let mut current = e.source();
125        while let Some(cause) = current {
126            msg.push(format!("{}", cause));
127            current = cause.source();
128        }
129        warn!("{}", msg.join("\n .due to: "))
130    } else {
131        info!("{}", msg.into())
132    }
133}
134
135/// Interface for data logging types
136pub trait Entry<U: UniqueIdentifier>: Update {
137    /// Adds an entry to the logger
138    fn entry(&mut self, size: usize);
139}
140
141pub fn trim_type_name<T>() -> String {
142    fn trim(name: &str) -> String {
143        if let Some((prefix, suffix)) = name.split_once('<') {
144            let generics: Vec<_> = suffix.split(',').map(|s| trim(s)).collect();
145            format!("{}<{}", trim(prefix), generics.join(","))
146        } else {
147            if let Some((_, suffix)) = name.rsplit_once("::") {
148                suffix.into()
149            } else {
150                name.into()
151            }
152        }
153    }
154    trim(type_name::<T>())
155}
156
157mod chain;
158
159/// UID to flatten `Vec<Arc<Vec<f64>>>` into `Vec<f64>`
160///
161/// The flattening happened within [Write]`<Flatten<U>>` that
162/// get the data from invoking [Write]`<U>` on `Self`
163pub struct Flatten<U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>>(PhantomData<U>);
164impl<U> UniqueIdentifier for Flatten<U>
165where
166    U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>,
167{
168    type DataType = Vec<f64>;
169    const PORT: u16 = <U as UniqueIdentifier>::PORT;
170}
171
172/// Marker trait for clients implementing [Write]`<`[Flatten]`<U>>`
173pub trait WriteFlatten {}
174
175impl<U, C> Write<Flatten<U>> for C
176where
177    U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>,
178    C: WriteFlatten + Write<U>,
179{
180    fn write(&mut self) -> Option<Data<Flatten<U>>> {
181        <_ as Write<U>>::write(self).map(|data| {
182            data.into_arc()
183                .iter()
184                .flat_map(|data| data.as_slice().to_vec())
185                .collect::<Vec<f64>>()
186                .into()
187        })
188    }
189}
190impl<U, C> Size<Flatten<U>> for C
191where
192    U: UniqueIdentifier<DataType = Vec<Arc<Vec<f64>>>>,
193    C: WriteFlatten + Size<U>,
194{
195    fn len(&self) -> usize {
196        <_ as Size<U>>::len(self)
197    }
198}
199
200pub struct Left<U: UniqueIdentifier>(PhantomData<U>);
201impl<U> UniqueIdentifier for Left<U>
202where
203    U: UniqueIdentifier,
204{
205    type DataType = <U as UniqueIdentifier>::DataType;
206
207    const PORT: u16 = <U as UniqueIdentifier>::PORT;
208}
209
210pub struct Right<U: UniqueIdentifier>(PhantomData<U>);
211impl<U> UniqueIdentifier for Right<U>
212where
213    U: UniqueIdentifier,
214{
215    type DataType = <U as UniqueIdentifier>::DataType;
216
217    const PORT: u16 = <U as UniqueIdentifier>::PORT;
218}
219