1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::types::TypeSig;
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum Value {
14 Null,
16 Bool(bool),
18 Int(i64),
20 Float(f64),
22 Str(std::string::String),
24 Bytes(Vec<u8>),
26 List(Vec<Value>),
28 Map(BTreeMap<std::string::String, Value>),
30}
31
32impl Value {
33 pub fn type_sig(&self) -> TypeSig {
35 match self {
36 Value::Null => TypeSig::Null,
37 Value::Bool(_) => TypeSig::Bool,
38 Value::Int(_) => TypeSig::Int,
39 Value::Float(_) => TypeSig::Float,
40 Value::Str(_) => TypeSig::String,
41 Value::Bytes(_) => TypeSig::Bytes,
42 Value::List(items) => {
43 let elem_sig = items.first().map(|v| v.type_sig()).unwrap_or(TypeSig::Any);
45 TypeSig::List(Box::new(elem_sig))
46 }
47 Value::Map(map) => {
48 let val_sig = map
49 .values()
50 .next()
51 .map(|v| v.type_sig())
52 .unwrap_or(TypeSig::Any);
53 TypeSig::Map(Box::new(val_sig))
54 }
55 }
56 }
57
58 #[inline]
60 pub fn is_null(&self) -> bool {
61 matches!(self, Value::Null)
62 }
63
64 pub fn as_bool(&self) -> Option<bool> {
66 match self {
67 Value::Bool(b) => Some(*b),
68 _ => None,
69 }
70 }
71
72 pub fn as_int(&self) -> Option<i64> {
74 match self {
75 Value::Int(i) => Some(*i),
76 _ => None,
77 }
78 }
79
80 pub fn as_float(&self) -> Option<f64> {
82 match self {
83 Value::Float(f) => Some(*f),
84 _ => None,
85 }
86 }
87
88 pub fn as_str(&self) -> Option<&str> {
90 match self {
91 Value::Str(s) => Some(s.as_str()),
92 _ => None,
93 }
94 }
95
96 pub fn as_list(&self) -> Option<&Vec<Value>> {
98 match self {
99 Value::List(v) => Some(v),
100 _ => None,
101 }
102 }
103
104 pub fn as_map(&self) -> Option<&BTreeMap<std::string::String, Value>> {
106 match self {
107 Value::Map(m) => Some(m),
108 _ => None,
109 }
110 }
111}
112
113impl std::fmt::Display for Value {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 match self {
116 Value::Null => write!(f, "null"),
117 Value::Bool(b) => write!(f, "{}", b),
118 Value::Int(i) => write!(f, "{}", i),
119 Value::Float(fl) => write!(f, "{}", fl),
120 Value::Str(s) => write!(f, "\"{}\"", s),
121 Value::Bytes(b) => write!(f, "<bytes:{}>", b.len()),
122 Value::List(v) => write!(f, "[..{}]", v.len()),
123 Value::Map(m) => write!(f, "{{..{}}}", m.len()),
124 }
125 }
126}
127
128impl From<bool> for Value {
129 fn from(b: bool) -> Self {
130 Value::Bool(b)
131 }
132}
133
134impl From<i64> for Value {
135 fn from(i: i64) -> Self {
136 Value::Int(i)
137 }
138}
139
140impl From<f64> for Value {
141 fn from(f: f64) -> Self {
142 Value::Float(f)
143 }
144}
145
146impl From<std::string::String> for Value {
147 fn from(s: std::string::String) -> Self {
148 Value::Str(s)
149 }
150}
151
152impl From<&str> for Value {
153 fn from(s: &str) -> Self {
154 Value::Str(s.to_owned())
155 }
156}
157
158#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn type_sig_matches_variant() {
168 assert_eq!(Value::Null.type_sig(), TypeSig::Null);
169 assert_eq!(Value::Bool(true).type_sig(), TypeSig::Bool);
170 assert_eq!(Value::Int(1).type_sig(), TypeSig::Int);
171 assert_eq!(Value::Float(1.0).type_sig(), TypeSig::Float);
172 assert_eq!(Value::Str("hi".into()).type_sig(), TypeSig::String);
173 }
174
175 #[test]
176 fn list_type_sig_infers_element() {
177 let v = Value::List(vec![Value::Int(1), Value::Int(2)]);
178 assert_eq!(v.type_sig(), TypeSig::List(Box::new(TypeSig::Int)));
179 }
180
181 #[test]
182 fn empty_list_type_sig_is_any() {
183 let v = Value::List(vec![]);
184 assert_eq!(v.type_sig(), TypeSig::List(Box::new(TypeSig::Any)));
185 }
186
187 #[test]
188 fn from_conversions() {
189 assert_eq!(Value::from(42i64), Value::Int(42));
190 assert_eq!(Value::from("hello"), Value::Str("hello".into()));
191 }
192}