summaryrefslogtreecommitdiff
path: root/mingling_core/src/any.rs
blob: 1bce96a37bf76da11d3a4ce401591cd45f904e7d (plain) (blame)
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
128
#[cfg(feature = "general_renderer")]
use serde::Serialize;

use crate::error::ChainProcessError;

#[derive(Debug)]
pub struct AnyOutput {
    inner: Box<dyn std::any::Any + Send + 'static>,
    pub type_id: std::any::TypeId,
}

impl AnyOutput {
    #[cfg(feature = "general_renderer")]
    pub fn new<T>(value: T) -> Self
    where
        T: Send + Serialize + 'static,
    {
        Self {
            inner: Box::new(value),
            type_id: std::any::TypeId::of::<T>(),
        }
    }

    #[cfg(not(feature = "general_renderer"))]
    pub fn new<T>(value: T) -> Self
    where
        T: Send + 'static,
    {
        Self {
            inner: Box::new(value),
            type_id: std::any::TypeId::of::<T>(),
        }
    }

    pub fn downcast<T: 'static>(self) -> Result<T, Self> {
        if self.type_id == std::any::TypeId::of::<T>() {
            Ok(*self.inner.downcast::<T>().unwrap())
        } else {
            Err(self)
        }
    }

    pub fn is<T: 'static>(&self) -> bool {
        self.type_id == std::any::TypeId::of::<T>()
    }

    /// Route the output to the next Chain
    pub fn route_chain(self) -> ChainProcess {
        ChainProcess::Ok((self, Next::Chain))
    }

    /// Route the output to the Renderer, ending execution
    pub fn route_renderer(self) -> ChainProcess {
        ChainProcess::Ok((self, Next::Renderer))
    }
}

impl std::ops::Deref for AnyOutput {
    type Target = dyn std::any::Any + Send + 'static;

    fn deref(&self) -> &Self::Target {
        &*self.inner
    }
}

impl std::ops::DerefMut for AnyOutput {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.inner
    }
}

pub enum ChainProcess {
    Ok((AnyOutput, Next)),
    Err(ChainProcessError),
}

pub enum Next {
    Chain,
    Renderer,
}

impl ChainProcess {
    pub fn is_next(&self) -> bool {
        matches!(self, Self::Ok(_))
    }

    pub fn is_err(&self) -> bool {
        matches!(self, Self::Err(_))
    }

    pub fn next(&self) -> Option<&Next> {
        match self {
            Self::Ok((_, next)) => Some(next),
            Self::Err(_) => None,
        }
    }

    pub fn err(&self) -> Option<&ChainProcessError> {
        match self {
            Self::Ok(_) => None,
            Self::Err(err) => Some(err),
        }
    }

    pub fn unwrap(self) -> (AnyOutput, Next) {
        match self {
            Self::Ok(tuple) => tuple,
            Self::Err(_) => panic!("called `ChainProcess2::unwrap()` on an `Error` value"),
        }
    }

    pub fn unwrap_or(self, default: (AnyOutput, Next)) -> (AnyOutput, Next) {
        match self {
            Self::Ok(tuple) => tuple,
            Self::Err(_) => default,
        }
    }

    pub fn unwrap_or_else<F>(self, f: F) -> (AnyOutput, Next)
    where
        F: FnOnce(ChainProcessError) -> (AnyOutput, Next),
    {
        match self {
            Self::Ok(tuple) => tuple,
            Self::Err(err) => f(err),
        }
    }
}