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 }
169
170 pub fn default_format(&self) -> &str {
172 &self.type_registry.default_item
173 }
174
175 pub fn available_formats(&self) -> Vec<&str> {
177 self.type_registry
178 .items
179 .iter()
180 .map(|f| f.name.as_str())
181 .collect()
182 }
183
184 pub fn has_format(&self, name: &str) -> bool {
186 self.type_registry.items.iter().any(|f| f.name == name)
187 }
188
189 pub fn format_default(&self) -> crate::error::Result<String> {
191 self.format(
192 &self.type_registry.default_item,
193 &std::collections::HashMap::new(),
194 )
195 }
196
197 pub fn format(
199 &self,
200 format_name: &str,
201 params: &std::collections::HashMap<String, serde_json::Value>,
202 ) -> crate::error::Result<String> {
203 crate::formatter::format_value(&self.value, format_name, params)
204 }
205
206 pub fn format_with_json_params(
208 &self,
209 format_name: &str,
210 params: &serde_json::Value,
211 ) -> crate::error::Result<String> {
212 let params_map: std::collections::HashMap<String, serde_json::Value> = match params {
213 serde_json::Value::Object(map) => {
214 map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
215 }
216 _ => std::collections::HashMap::new(),
217 };
218 self.format(format_name, ¶ms_map)
219 }
220}
221
222impl ValueEnvelope {
224 pub fn null() -> Self {
226 Self::from_value(WireValue::Null)
227 }
228
229 pub fn number(n: f64) -> Self {
231 Self::from_value(WireValue::Number(n))
232 }
233
234 pub fn string(s: impl Into<String>) -> Self {
236 Self::from_value(WireValue::String(s.into()))
237 }
238
239 pub fn bool(b: bool) -> Self {
241 Self::from_value(WireValue::Bool(b))
242 }
243
244 pub fn timestamp(millis: i64) -> Self {
246 Self::from_value(WireValue::Timestamp(millis))
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 #[test]
255 fn test_envelope_from_value() {
256 let env = ValueEnvelope::from_value(WireValue::Number(42.0));
257 assert_eq!(env.type_info.name, "Number");
258 assert!(env.has_format("Default"));
259 assert!(env.has_format("Fixed"));
260 }
261
262 #[test]
263 fn test_envelope_timestamp() {
264 let env = ValueEnvelope::timestamp(1704067200000);
265 assert_eq!(env.type_info.name, "Timestamp");
266 assert_eq!(env.default_format(), "ISO8601");
267 assert!(env.has_format("Unix"));
268 assert!(env.has_format("Relative"));
269 }
270
271 #[test]
272 fn test_envelope_array() {
273 let env = ValueEnvelope::from_value(WireValue::Array(vec![
274 WireValue::Number(1.0),
275 WireValue::Number(2.0),
276 ]));
277 assert_eq!(env.type_info.name, "Array<Number>");
278 }
279
280 #[test]
281 fn test_envelope_convenience() {
282 let env = ValueEnvelope::number(3.14);
283 assert_eq!(env.value.as_number(), Some(3.14));
284
285 let env = ValueEnvelope::string("hello");
286 assert_eq!(env.value.as_str(), Some("hello"));
287 }
288}