1use crate::metadata::{TypeInfo, TypeKind, TypeRegistry};
8use crate::value::WireValue;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19pub struct ValueEnvelope {
20 pub value: WireValue,
22
23 pub type_info: TypeInfo,
25
26 pub type_registry: TypeRegistry,
28}
29
30impl ValueEnvelope {
31 pub fn new(value: WireValue, type_info: TypeInfo, type_registry: TypeRegistry) -> Self {
33 ValueEnvelope {
34 value,
35 type_info,
36 type_registry,
37 }
38 }
39
40 pub fn from_value(value: WireValue) -> Self {
42 let (type_info, type_registry) = Self::infer_metadata(&value);
43 ValueEnvelope {
44 value,
45 type_info,
46 type_registry,
47 }
48 }
49
50 fn infer_metadata(value: &WireValue) -> (TypeInfo, TypeRegistry) {
52 match value {
53 WireValue::Null => (TypeInfo::null(), TypeRegistry::default_for_primitives()),
54
55 WireValue::Bool(_) => (TypeInfo::bool(), TypeRegistry::default_for_primitives()),
56
57 WireValue::Number(_) => (TypeInfo::number(), TypeRegistry::for_number()),
58
59 WireValue::Integer(_) => (TypeInfo::integer(), TypeRegistry::for_number()),
60
61 WireValue::I8(_) => (TypeInfo::primitive("i8"), TypeRegistry::for_number()),
62 WireValue::U8(_) => (TypeInfo::primitive("u8"), TypeRegistry::for_number()),
63 WireValue::I16(_) => (TypeInfo::primitive("i16"), TypeRegistry::for_number()),
64 WireValue::U16(_) => (TypeInfo::primitive("u16"), TypeRegistry::for_number()),
65 WireValue::I32(_) => (TypeInfo::primitive("i32"), TypeRegistry::for_number()),
66 WireValue::U32(_) => (TypeInfo::primitive("u32"), TypeRegistry::for_number()),
67 WireValue::I64(_) => (TypeInfo::primitive("i64"), TypeRegistry::for_number()),
68 WireValue::U64(_) => (TypeInfo::primitive("u64"), TypeRegistry::for_number()),
69 WireValue::Isize(_) => (TypeInfo::primitive("isize"), TypeRegistry::for_number()),
70 WireValue::Usize(_) => (TypeInfo::primitive("usize"), TypeRegistry::for_number()),
71 WireValue::Ptr(_) => (
72 TypeInfo::primitive("ptr"),
73 TypeRegistry::default_for_primitives(),
74 ),
75 WireValue::F32(_) => (TypeInfo::primitive("f32"), TypeRegistry::for_number()),
76
77 WireValue::String(_) => (TypeInfo::string(), TypeRegistry::default_for_primitives()),
78
79 WireValue::Timestamp(_) => (TypeInfo::timestamp(), TypeRegistry::for_timestamp()),
80
81 WireValue::Duration { .. } => (
82 TypeInfo::primitive("Duration"),
83 TypeRegistry::default_for_primitives(),
84 ),
85
86 WireValue::Array(items) => {
87 let element_type = if items.is_empty() {
88 TypeInfo::primitive("Unknown")
89 } else {
90 Self::infer_metadata(&items[0]).0
91 };
92 (
93 TypeInfo::array(element_type),
94 TypeRegistry::default_for_primitives(),
95 )
96 }
97
98 WireValue::Object(fields) => {
99 let field_infos: Vec<_> = fields
100 .iter()
101 .map(|(name, v)| {
102 let (field_type, _) = Self::infer_metadata(v);
103 crate::metadata::FieldInfo::required(name, field_type)
104 })
105 .collect();
106 (
107 TypeInfo::object("Object", field_infos),
108 TypeRegistry::default_for_primitives(),
109 )
110 }
111
112 WireValue::Table(series) => {
113 let element_type = series
114 .type_name
115 .as_ref()
116 .map(|n| TypeInfo::primitive(n.clone()))
117 .unwrap_or_else(|| TypeInfo::primitive("Row"));
118 (
119 TypeInfo::table(element_type),
120 TypeRegistry::default_for_primitives(),
121 )
122 }
123
124 WireValue::Result { ok, value } => {
125 let (inner_type, _) = Self::infer_metadata(value);
126 let name = if *ok {
127 format!("Ok<{}>", inner_type.name)
128 } else {
129 format!("Err<{}>", inner_type.name)
130 };
131 (
132 TypeInfo {
133 name,
134 kind: TypeKind::Result,
135 fields: None,
136 generic_params: Some(vec![inner_type]),
137 variants: None,
138 description: None,
139 metadata: None,
140 },
141 TypeRegistry::default_for_primitives(),
142 )
143 }
144
145 WireValue::Range { .. } => (
146 TypeInfo::primitive("Range"),
147 TypeRegistry::default_for_primitives(),
148 ),
149
150 WireValue::FunctionRef { name } => (
151 TypeInfo {
152 name: format!("Function<{}>", name),
153 kind: TypeKind::Function,
154 fields: None,
155 generic_params: None,
156 variants: None,
157 description: None,
158 metadata: None,
159 },
160 TypeRegistry::default_for_primitives(),
161 ),
162
163 WireValue::PrintResult(_) => (
164 TypeInfo::primitive("PrintResult"),
165 TypeRegistry::default_for_primitives(),
166 ),
167
168 WireValue::Content(_) => (
169 TypeInfo::primitive("Content"),
170 TypeRegistry::default_for_primitives(),
171 ),
172 }
173 }
174
175 pub fn default_format(&self) -> &str {
177 &self.type_registry.default_item
178 }
179
180 pub fn available_formats(&self) -> Vec<&str> {
182 self.type_registry
183 .items
184 .iter()
185 .map(|f| f.name.as_str())
186 .collect()
187 }
188
189 pub fn has_format(&self, name: &str) -> bool {
191 self.type_registry.items.iter().any(|f| f.name == name)
192 }
193
194 pub fn format_default(&self) -> crate::error::Result<String> {
196 self.format(
197 &self.type_registry.default_item,
198 &std::collections::HashMap::new(),
199 )
200 }
201
202 pub fn format(
204 &self,
205 format_name: &str,
206 params: &std::collections::HashMap<String, serde_json::Value>,
207 ) -> crate::error::Result<String> {
208 crate::formatter::format_value(&self.value, format_name, params)
209 }
210
211 pub fn format_with_json_params(
213 &self,
214 format_name: &str,
215 params: &serde_json::Value,
216 ) -> crate::error::Result<String> {
217 let params_map: std::collections::HashMap<String, serde_json::Value> = match params {
218 serde_json::Value::Object(map) => {
219 map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
220 }
221 _ => std::collections::HashMap::new(),
222 };
223 self.format(format_name, ¶ms_map)
224 }
225}
226
227impl ValueEnvelope {
229 pub fn null() -> Self {
231 Self::from_value(WireValue::Null)
232 }
233
234 pub fn number(n: f64) -> Self {
236 Self::from_value(WireValue::Number(n))
237 }
238
239 pub fn string(s: impl Into<String>) -> Self {
241 Self::from_value(WireValue::String(s.into()))
242 }
243
244 pub fn bool(b: bool) -> Self {
246 Self::from_value(WireValue::Bool(b))
247 }
248
249 pub fn timestamp(millis: i64) -> Self {
251 Self::from_value(WireValue::Timestamp(millis))
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258
259 #[test]
260 fn test_envelope_from_value() {
261 let env = ValueEnvelope::from_value(WireValue::Number(42.0));
262 assert_eq!(env.type_info.name, "Number");
263 assert!(env.has_format("Default"));
264 assert!(env.has_format("Fixed"));
265 }
266
267 #[test]
268 fn test_envelope_timestamp() {
269 let env = ValueEnvelope::timestamp(1704067200000);
270 assert_eq!(env.type_info.name, "Timestamp");
271 assert_eq!(env.default_format(), "ISO8601");
272 assert!(env.has_format("Unix"));
273 assert!(env.has_format("Relative"));
274 }
275
276 #[test]
277 fn test_envelope_array() {
278 let env = ValueEnvelope::from_value(WireValue::Array(vec![
279 WireValue::Number(1.0),
280 WireValue::Number(2.0),
281 ]));
282 assert_eq!(env.type_info.name, "Array<Number>");
283 }
284
285 #[test]
286 fn test_envelope_convenience() {
287 let env = ValueEnvelope::number(3.14);
288 assert_eq!(env.value.as_number(), Some(3.14));
289
290 let env = ValueEnvelope::string("hello");
291 assert_eq!(env.value.as_str(), Some("hello"));
292 }
293}