summaryrefslogtreecommitdiff
path: root/mingling_core/src/any.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_core/src/any.rs')
-rw-r--r--mingling_core/src/any.rs128
1 files changed, 128 insertions, 0 deletions
diff --git a/mingling_core/src/any.rs b/mingling_core/src/any.rs
new file mode 100644
index 0000000..1bce96a
--- /dev/null
+++ b/mingling_core/src/any.rs
@@ -0,0 +1,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),
+ }
+ }
+}