1use std::borrow::Cow;
2
3use crate::value::{Value, ValueRegex, kind::Collection};
4use bytes::Bytes;
5use chrono::{DateTime, Utc};
6
7use crate::compiler::{
8 Expression,
9 expression::{Container, Expr, Variant},
10 value::{Kind, ObjectMap, ValueError},
11};
12
13#[macro_export]
17macro_rules! expr {
18 ($($v:tt)*) => {{
19 let value = $crate::value!($($v)*);
20 $crate::compiler::value::VrlValueConvert::into_expression(value)
21 }};
22}
23
24#[allow(clippy::module_name_repetitions, clippy::missing_errors_doc)]
25pub trait VrlValueConvert: Sized {
26 fn into_expression(self) -> Box<dyn Expression>;
28
29 fn try_integer(self) -> Result<i64, ValueError>;
30 fn try_float(self) -> Result<f64, ValueError>;
31 fn try_bytes(self) -> Result<Bytes, ValueError>;
32 fn try_boolean(self) -> Result<bool, ValueError>;
33 fn try_regex(self) -> Result<ValueRegex, ValueError>;
34 fn try_null(self) -> Result<(), ValueError>;
35 fn try_array(self) -> Result<Vec<Value>, ValueError>;
36 fn try_object(self) -> Result<ObjectMap, ValueError>;
37 fn try_timestamp(self) -> Result<DateTime<Utc>, ValueError>;
38
39 fn try_into_i64(&self) -> Result<i64, ValueError>;
40 fn try_into_f64(&self) -> Result<f64, ValueError>;
41
42 fn try_bytes_utf8_lossy(&self) -> Result<Cow<'_, str>, ValueError>;
43}
44
45impl VrlValueConvert for Value {
46 fn into_expression(self) -> Box<dyn Expression> {
48 Box::new(Expr::from(self))
49 }
50
51 fn try_integer(self) -> Result<i64, ValueError> {
52 match self {
53 Value::Integer(v) => Ok(v),
54 _ => Err(ValueError::Expected {
55 got: self.kind(),
56 expected: Kind::integer(),
57 }),
58 }
59 }
60
61 fn try_into_i64(self: &Value) -> Result<i64, ValueError> {
62 match self {
63 Value::Integer(v) => Ok(*v),
64 #[allow(clippy::cast_possible_truncation)]
65 Value::Float(v) => Ok(v.into_inner() as i64),
66 _ => Err(ValueError::Coerce(self.kind(), Kind::integer())),
67 }
68 }
69
70 fn try_float(self) -> Result<f64, ValueError> {
71 match self {
72 Value::Float(v) => Ok(v.into_inner()),
73 _ => Err(ValueError::Expected {
74 got: self.kind(),
75 expected: Kind::float(),
76 }),
77 }
78 }
79
80 fn try_into_f64(&self) -> Result<f64, ValueError> {
81 match self {
82 #[allow(clippy::cast_precision_loss)]
83 Value::Integer(v) => Ok(*v as f64),
84 Value::Float(v) => Ok(v.into_inner()),
85 _ => Err(ValueError::Coerce(self.kind(), Kind::float())),
86 }
87 }
88
89 fn try_bytes(self) -> Result<Bytes, ValueError> {
90 match self {
91 Value::Bytes(v) => Ok(v),
92 _ => Err(ValueError::Expected {
93 got: self.kind(),
94 expected: Kind::bytes(),
95 }),
96 }
97 }
98
99 fn try_bytes_utf8_lossy(&self) -> Result<Cow<'_, str>, ValueError> {
100 self.as_str().ok_or(ValueError::Expected {
101 got: self.kind(),
102 expected: Kind::bytes(),
103 })
104 }
105
106 fn try_boolean(self) -> Result<bool, ValueError> {
107 match self {
108 Value::Boolean(v) => Ok(v),
109 _ => Err(ValueError::Expected {
110 got: self.kind(),
111 expected: Kind::boolean(),
112 }),
113 }
114 }
115
116 fn try_regex(self) -> Result<ValueRegex, ValueError> {
117 match self {
118 Value::Regex(v) => Ok(v),
119 _ => Err(ValueError::Expected {
120 got: self.kind(),
121 expected: Kind::regex(),
122 }),
123 }
124 }
125
126 fn try_null(self) -> Result<(), ValueError> {
127 match self {
128 Value::Null => Ok(()),
129 _ => Err(ValueError::Expected {
130 got: self.kind(),
131 expected: Kind::null(),
132 }),
133 }
134 }
135
136 fn try_array(self) -> Result<Vec<Value>, ValueError> {
137 match self {
138 Value::Array(v) => Ok(v),
139 _ => Err(ValueError::Expected {
140 got: self.kind(),
141 expected: Kind::array(Collection::any()),
142 }),
143 }
144 }
145
146 fn try_object(self) -> Result<ObjectMap, ValueError> {
147 match self {
148 Value::Object(v) => Ok(v),
149 _ => Err(ValueError::Expected {
150 got: self.kind(),
151 expected: Kind::object(Collection::any()),
152 }),
153 }
154 }
155
156 fn try_timestamp(self) -> Result<DateTime<Utc>, ValueError> {
157 match self {
158 Value::Timestamp(v) => Ok(v),
159 _ => Err(ValueError::Expected {
160 got: self.kind(),
161 expected: Kind::timestamp(),
162 }),
163 }
164 }
165}
166
167impl TryFrom<Expr> for Value {
171 type Error = Expr;
172
173 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
174 match expr {
175 Expr::Literal(literal) => Ok(literal.to_value()),
176 Expr::Container(Container {
177 variant: Variant::Object(object),
178 }) => Ok(Value::Object(
179 object
180 .iter()
181 .map(|(key, value)| Ok((key.clone(), value.clone().try_into()?)))
182 .collect::<Result<_, Self::Error>>()?,
183 )),
184 Expr::Container(Container {
185 variant: Variant::Array(array),
186 }) => Ok(Value::Array(
187 array
188 .iter()
189 .map(|value| value.clone().try_into())
190 .collect::<Result<_, _>>()?,
191 )),
192 expr => Err(expr),
193 }
194 }
195}