1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*!
# 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

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

use std::any::type_name;

mod data;
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;

/// 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>())
    }
}

/// Actor client state update interface
pub trait Update: Send + Sync {
    fn update(&mut 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 output data writer interface
pub trait Write<U: UniqueIdentifier>: Update {
    fn write(&mut self) -> Option<Data<U>>;
}
/// Interface for IO data sizes
pub trait Size<U: UniqueIdentifier>: Update {
    fn len(&self) -> usize;
}

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))
    }
}

use log::{info, warn};

/// 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();
        }
        warn!("{}", msg.join("\n .due to: "))
    } else {
        info!("{}", 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);
}