acts_next/model/
output.rs1use crate::{ActError, Vars};
2use core::fmt;
3use serde::{Deserialize, Serialize, de};
4use serde_json::Value;
5use std::collections::HashMap;
6
7#[derive(Debug, Default, Clone, Serialize, Deserialize, strum::AsRefStr)]
8pub enum OutputType {
9 #[default]
10 String,
11 Bool,
12 Number,
13 Array,
14 Object,
15}
16
17#[derive(Debug, Default, Clone, Serialize, Deserialize)]
18pub struct Output {
19 pub required: bool,
20 pub default: Value,
21 pub r#type: OutputType,
22}
23
24#[derive(Debug, Default, Clone)]
25pub struct Outputs {
26 inner: HashMap<String, Output>,
27}
28
29fn get<T>(name: &str, value: &Value) -> Option<T>
30where
31 T: for<'de> Deserialize<'de> + Clone,
32{
33 if let Some(v) = value.get(name)
34 && let Ok(v) = serde_json::from_value::<T>(v.clone())
35 {
36 Some(v)
37 } else {
38 None
39 }
40}
41
42impl fmt::Display for OutputType {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.write_str(self.as_ref())
45 }
46}
47
48impl From<Value> for Output {
49 fn from(value: Value) -> Self {
50 let required = get::<bool>("required", &value).unwrap_or_default();
51 let default = get::<Value>("default", &value).unwrap_or_default();
52 let r#type = get::<OutputType>("type", &value).unwrap_or_default();
53
54 Self {
55 required,
56 default,
57 r#type,
58 }
59 }
60}
61
62impl Serialize for Outputs {
63 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
64 where
65 S: serde::Serializer,
66 {
67 use serde::ser::SerializeMap;
68
69 let mut map = serializer.serialize_map(Some(self.inner.len()))?;
70 for (k, v) in &self.inner {
71 map.serialize_entry(k, v)?;
72 }
73 map.end()
74 }
75}
76
77impl<'de> Deserialize<'de> for Outputs {
78 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
79 where
80 D: serde::Deserializer<'de>,
81 {
82 struct Visitor;
83
84 impl<'de> de::Visitor<'de> for Visitor {
85 type Value = HashMap<String, Output>;
86 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
87 formatter.write_str("a map")
88 }
89
90 #[inline]
91 fn visit_unit<E>(self) -> Result<Self::Value, E>
92 where
93 E: de::Error,
94 {
95 Ok(HashMap::new())
96 }
97
98 #[inline]
99 fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
100 where
101 V: de::MapAccess<'de>,
102 {
103 let mut values = HashMap::new();
104
105 while let Some((key, value)) = visitor.next_entry::<String, Value>()? {
106 let value: Output = value.into();
107 values.insert(key, value);
108 }
109
110 Ok(values)
111 }
112 }
113
114 core::result::Result::Ok(Self {
115 inner: deserializer.deserialize_map(Visitor)?,
116 })
117 }
118}
119
120impl Outputs {
121 pub fn push(&mut self, name: &str, output: &Output) {
122 self.inner.insert(name.to_string(), output.clone());
123 }
124
125 pub fn check(&self, vars: &Vars) -> crate::Result<()> {
126 for (k, output) in &self.inner {
127 let v = vars.get::<Value>(k);
128 if v.is_none() && output.required {
129 return Err(ActError::Runtime(format!("the key '{k}' is required",)));
130 }
131
132 if let Some(v) = &v {
133 let is_type_match = match output.r#type {
134 OutputType::String => v.is_string(),
135 OutputType::Bool => v.is_boolean(),
136 OutputType::Number => v.is_number(),
137 OutputType::Array => v.is_array(),
138 OutputType::Object => v.is_object(),
139 };
140
141 if !is_type_match {
142 return Err(ActError::Runtime(format!(
143 "the value {k}({v}) is not matched the type '{}'",
144 output.r#type
145 )));
146 }
147 }
148 }
149 Ok(())
150 }
151}