1use cel::objects::{Key, Map, Opaque, Value};
2use chrono::{DateTime, FixedOffset, NaiveDate, TimeZone, Utc};
3use rust_decimal::Decimal;
4use uuid::Uuid;
5
6use std::{collections::HashMap, sync::Arc};
7
8use crate::{cel_type::*, error::*};
9
10pub struct CelResult<'a> {
11 pub expr: &'a str,
12 pub val: CelValue,
13}
14
15#[derive(Debug, Clone, Eq, PartialEq)]
16pub(crate) struct CelDecimal(pub Decimal);
17
18impl Opaque for CelDecimal {
19 fn runtime_type_name(&self) -> &str {
20 "cala.Decimal"
21 }
22}
23
24#[derive(Debug, Clone, Eq, PartialEq)]
25pub(crate) struct CelUuid(pub Uuid);
26
27impl Opaque for CelUuid {
28 fn runtime_type_name(&self) -> &str {
29 "cala.Uuid"
30 }
31}
32
33#[derive(Debug, Clone, PartialEq)]
34pub enum CelValue {
35 Map(Arc<CelMap>),
37 List(Arc<CelArray>),
38 Int(i64),
39 UInt(u64),
40 Double(f64),
41 String(Arc<String>),
42 Bytes(Arc<Vec<u8>>),
43 Bool(bool),
44 Null,
45
46 Decimal(Decimal),
48 Date(NaiveDate),
49 Timestamp(DateTime<Utc>),
50 Uuid(Uuid),
51}
52
53#[derive(Debug, PartialEq)]
54pub struct CelMap {
55 inner: HashMap<CelKey, CelValue>,
56}
57
58impl CelMap {
59 pub fn new() -> Self {
60 Self {
61 inner: HashMap::new(),
62 }
63 }
64
65 pub fn insert(&mut self, k: impl Into<CelKey>, val: impl Into<CelValue>) {
66 self.inner.insert(k.into(), val.into());
67 }
68
69 pub fn get(&self, key: impl Into<CelKey>) -> CelValue {
70 self.inner
71 .get(&key.into())
72 .cloned()
73 .unwrap_or(CelValue::Null)
74 }
75
76 pub fn contains_key(&self, key: impl Into<CelKey>) -> bool {
77 self.inner.contains_key(&key.into())
78 }
79}
80
81impl Default for CelMap {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87impl From<HashMap<String, CelValue>> for CelMap {
88 fn from(map: HashMap<String, CelValue>) -> Self {
89 let mut res = CelMap::new();
90 for (k, v) in map {
91 res.insert(CelKey::String(Arc::from(k)), v);
92 }
93 res
94 }
95}
96
97impl From<CelMap> for CelValue {
98 fn from(m: CelMap) -> Self {
99 CelValue::Map(Arc::from(m))
100 }
101}
102
103impl CelValue {
104 pub(crate) fn into_cel_value(self) -> Value {
105 match self {
106 CelValue::Map(map) => {
107 let map = map
108 .inner
109 .iter()
110 .map(|(k, v)| (k.clone().into_cel_key(), v.clone().into_cel_value()))
111 .collect::<HashMap<_, _>>();
112 Value::Map(Map { map: Arc::new(map) })
113 }
114 CelValue::List(array) => Value::List(Arc::new(
115 array
116 .inner
117 .iter()
118 .map(|v| v.clone().into_cel_value())
119 .collect(),
120 )),
121 CelValue::Int(i) => Value::Int(i),
122 CelValue::UInt(u) => Value::UInt(u),
123 CelValue::Double(d) => Value::Float(d),
124 CelValue::String(s) => Value::String(s),
125 CelValue::Bytes(b) => Value::Bytes(b),
126 CelValue::Bool(b) => Value::Bool(b),
127 CelValue::Null => Value::Null,
128 CelValue::Decimal(d) => Value::Opaque(Arc::new(CelDecimal(d))),
129 CelValue::Date(d) => {
130 let dt = d.and_hms_opt(0, 0, 0).expect("midnight is valid");
131 Value::Timestamp(
132 FixedOffset::east_opt(0)
133 .expect("UTC offset is valid")
134 .from_utc_datetime(&dt),
135 )
136 }
137 CelValue::Timestamp(ts) => Value::Timestamp(ts.fixed_offset()),
138 CelValue::Uuid(id) => Value::Opaque(Arc::new(CelUuid(id))),
139 }
140 }
141
142 pub(crate) fn from_cel_value(value: Value) -> Result<Self, CelError> {
143 Ok(match value {
144 Value::Map(map) => {
145 let mut res = CelMap::new();
146 for (k, v) in map.map.iter() {
147 res.inner
148 .insert(CelKey::try_from(k)?, CelValue::from_cel_value(v.clone())?);
149 }
150 CelValue::Map(Arc::new(res))
151 }
152 Value::List(values) => {
153 let mut res = CelArray::new();
154 for value in values.iter() {
155 res.push(CelValue::from_cel_value(value.clone())?);
156 }
157 CelValue::List(Arc::new(res))
158 }
159 Value::Int(i) => CelValue::Int(i),
160 Value::UInt(u) => CelValue::UInt(u),
161 Value::Float(f) => CelValue::Double(f),
162 Value::String(s) => CelValue::String(s),
163 Value::Bytes(b) => CelValue::Bytes(b),
164 Value::Bool(b) => CelValue::Bool(b),
165 Value::Duration(d) => CelValue::String(Arc::new(format!("{d:?}"))),
166 Value::Timestamp(ts) => CelValue::Timestamp(ts.with_timezone(&Utc)),
167 Value::Opaque(o) if o.runtime_type_name() == "cala.Decimal" => {
168 let decimal = o.downcast_ref::<CelDecimal>().ok_or_else(|| {
169 CelError::Unexpected("Could not downcast decimal".to_string())
170 })?;
171 CelValue::Decimal(decimal.0)
172 }
173 Value::Opaque(o) if o.runtime_type_name() == "cala.Uuid" => {
174 let id = o
175 .downcast_ref::<CelUuid>()
176 .ok_or_else(|| CelError::Unexpected("Could not downcast uuid".to_string()))?;
177 CelValue::Uuid(id.0)
178 }
179 Value::Opaque(o) => {
180 return Err(CelError::Unexpected(format!(
181 "Unsupported opaque value {}",
182 o.runtime_type_name()
183 )))
184 }
185 Value::Null => CelValue::Null,
186 Value::Function(_, _) => {
187 return Err(CelError::Unexpected(
188 "Cannot convert function value".to_string(),
189 ))
190 }
191 })
192 }
193}
194
195#[derive(Debug, PartialEq)]
196pub struct CelArray {
197 inner: Vec<CelValue>,
198}
199
200impl CelArray {
201 pub fn new() -> Self {
202 Self { inner: Vec::new() }
203 }
204
205 pub fn push(&mut self, elem: impl Into<CelValue>) {
206 self.inner.push(elem.into());
207 }
208}
209
210impl Default for CelArray {
211 fn default() -> Self {
212 Self::new()
213 }
214}
215
216impl From<i64> for CelValue {
217 fn from(i: i64) -> Self {
218 CelValue::Int(i)
219 }
220}
221
222impl From<Decimal> for CelValue {
223 fn from(d: Decimal) -> Self {
224 CelValue::Decimal(d)
225 }
226}
227
228impl From<bool> for CelValue {
229 fn from(b: bool) -> Self {
230 CelValue::Bool(b)
231 }
232}
233
234impl From<String> for CelValue {
235 fn from(s: String) -> Self {
236 CelValue::String(Arc::from(s))
237 }
238}
239
240impl From<NaiveDate> for CelValue {
241 fn from(d: NaiveDate) -> Self {
242 CelValue::Date(d)
243 }
244}
245
246impl From<Uuid> for CelValue {
247 fn from(id: Uuid) -> Self {
248 CelValue::Uuid(id)
249 }
250}
251
252impl From<&str> for CelValue {
253 fn from(s: &str) -> Self {
254 CelValue::String(Arc::from(s.to_string()))
255 }
256}
257
258impl From<serde_json::Value> for CelValue {
259 fn from(v: serde_json::Value) -> Self {
260 use serde_json::Value::*;
261 match v {
262 Null => CelValue::Null,
263 Bool(b) => CelValue::Bool(b),
264 Number(n) => {
265 if let Some(u) = n.as_u64() {
266 CelValue::UInt(u)
267 } else if let Some(i) = n.as_i64() {
268 CelValue::Int(i)
269 } else if let Some(f) = n.as_f64() {
270 CelValue::Double(f)
271 } else {
272 unimplemented!()
273 }
274 }
275 String(s) => CelValue::String(Arc::from(s)),
276 Object(o) => {
277 let mut map = CelMap::new();
278 for (k, v) in o.into_iter() {
279 map.insert(CelKey::String(Arc::from(k)), CelValue::from(v));
280 }
281 CelValue::Map(Arc::from(map))
282 }
283 Array(a) => {
284 let mut ar = CelArray::new();
285 for v in a.into_iter() {
286 ar.push(CelValue::from(v));
287 }
288 CelValue::List(Arc::from(ar))
289 }
290 }
291 }
292}
293
294#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
295pub enum CelKey {
296 Int(i64),
297 UInt(u64),
298 Bool(bool),
299 String(Arc<String>),
300}
301
302impl CelKey {
303 fn into_cel_key(self) -> Key {
304 match self {
305 CelKey::Int(i) => Key::Int(i),
306 CelKey::UInt(u) => Key::Uint(u),
307 CelKey::Bool(b) => Key::Bool(b),
308 CelKey::String(s) => Key::String(s),
309 }
310 }
311}
312
313impl TryFrom<&Key> for CelKey {
314 type Error = CelError;
315
316 fn try_from(key: &Key) -> Result<Self, Self::Error> {
317 Ok(match key {
318 Key::Int(i) => CelKey::Int(*i),
319 Key::Uint(u) => CelKey::UInt(*u),
320 Key::Bool(b) => CelKey::Bool(*b),
321 Key::String(s) => CelKey::String(s.clone()),
322 })
323 }
324}
325
326impl From<&str> for CelKey {
327 fn from(s: &str) -> Self {
328 CelKey::String(Arc::from(s.to_string()))
329 }
330}
331
332impl From<String> for CelKey {
333 fn from(s: String) -> Self {
334 CelKey::String(Arc::from(s))
335 }
336}
337
338impl From<&Arc<String>> for CelKey {
339 fn from(s: &Arc<String>) -> Self {
340 CelKey::String(s.clone())
341 }
342}
343
344impl From<&CelValue> for CelType {
345 fn from(v: &CelValue) -> Self {
346 match v {
347 CelValue::Map(_) => CelType::Map,
348 CelValue::List(_) => CelType::List,
349 CelValue::Int(_) => CelType::Int,
350 CelValue::UInt(_) => CelType::UInt,
351 CelValue::Double(_) => CelType::Double,
352 CelValue::String(_) => CelType::String,
353 CelValue::Bytes(_) => CelType::Bytes,
354 CelValue::Bool(_) => CelType::Bool,
355 CelValue::Null => CelType::Null,
356
357 CelValue::Decimal(_) => CelType::Decimal,
358 CelValue::Date(_) => CelType::Date,
359 CelValue::Uuid(_) => CelType::Uuid,
360 CelValue::Timestamp(_) => CelType::Timestamp,
361 }
362 }
363}
364
365impl From<DateTime<Utc>> for CelValue {
366 fn from(d: DateTime<Utc>) -> Self {
367 CelValue::Timestamp(d)
368 }
369}
370
371impl TryFrom<&CelValue> for Arc<String> {
372 type Error = CelError;
373
374 fn try_from(v: &CelValue) -> Result<Self, Self::Error> {
375 if let CelValue::String(s) = v {
376 Ok(s.clone())
377 } else {
378 Err(CelError::BadType(CelType::String, CelType::from(v)))
379 }
380 }
381}
382
383impl<'a> TryFrom<&'a CelValue> for &'a Decimal {
384 type Error = CelError;
385
386 fn try_from(v: &'a CelValue) -> Result<Self, Self::Error> {
387 if let CelValue::Decimal(d) = v {
388 Ok(d)
389 } else {
390 Err(CelError::BadType(CelType::Decimal, CelType::from(v)))
391 }
392 }
393}
394
395impl TryFrom<CelResult<'_>> for bool {
396 type Error = ResultCoercionError;
397
398 fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
399 if let CelValue::Bool(b) = val {
400 Ok(b)
401 } else {
402 Err(ResultCoercionError::BadCoreTypeCoercion(
403 format!("{expr:?}"),
404 CelType::from(&val),
405 CelType::Bool,
406 ))
407 }
408 }
409}
410
411impl TryFrom<CelResult<'_>> for NaiveDate {
412 type Error = ResultCoercionError;
413
414 fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
415 match val {
416 CelValue::Date(d) => Ok(d),
417 CelValue::Timestamp(ts) => Ok(ts.date_naive()),
418 _ => Err(ResultCoercionError::BadCoreTypeCoercion(
419 expr.to_string(),
420 CelType::from(&val),
421 CelType::Date,
422 )),
423 }
424 }
425}
426
427impl TryFrom<CelResult<'_>> for DateTime<Utc> {
428 type Error = ResultCoercionError;
429
430 fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
431 if let CelValue::Timestamp(d) = val {
432 Ok(d)
433 } else {
434 Err(ResultCoercionError::BadCoreTypeCoercion(
435 expr.to_string(),
436 CelType::from(&val),
437 CelType::Timestamp,
438 ))
439 }
440 }
441}
442
443impl TryFrom<CelResult<'_>> for Uuid {
444 type Error = ResultCoercionError;
445
446 fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
447 if let CelValue::Uuid(id) = val {
448 Ok(id)
449 } else {
450 Err(ResultCoercionError::BadCoreTypeCoercion(
451 expr.to_string(),
452 CelType::from(&val),
453 CelType::Uuid,
454 ))
455 }
456 }
457}
458
459impl TryFrom<CelResult<'_>> for String {
460 type Error = ResultCoercionError;
461
462 fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
463 if let CelValue::String(s) = val {
464 Ok(s.to_string())
465 } else {
466 Err(ResultCoercionError::BadCoreTypeCoercion(
467 expr.to_string(),
468 CelType::from(&val),
469 CelType::String,
470 ))
471 }
472 }
473}
474
475impl TryFrom<CelResult<'_>> for Decimal {
476 type Error = ResultCoercionError;
477
478 fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
479 match val {
480 CelValue::Decimal(n) => Ok(n),
481 _ => Err(ResultCoercionError::BadCoreTypeCoercion(
482 expr.to_string(),
483 CelType::from(&val),
484 CelType::Decimal,
485 )),
486 }
487 }
488}
489
490impl From<&CelKey> for CelType {
491 fn from(v: &CelKey) -> Self {
492 match v {
493 CelKey::Int(_) => CelType::Int,
494 CelKey::UInt(_) => CelType::UInt,
495 CelKey::Bool(_) => CelType::Bool,
496 CelKey::String(_) => CelType::String,
497 }
498 }
499}
500
501impl TryFrom<&CelKey> for String {
502 type Error = ResultCoercionError;
503
504 fn try_from(v: &CelKey) -> Result<Self, Self::Error> {
505 if let CelKey::String(s) = v {
506 Ok(s.to_string())
507 } else {
508 Err(ResultCoercionError::BadCoreTypeCoercion(
509 format!("{v:?}"),
510 CelType::from(v),
511 CelType::String,
512 ))
513 }
514 }
515}
516
517impl TryFrom<CelResult<'_>> for serde_json::Value {
518 type Error = ResultCoercionError;
519
520 fn try_from(CelResult { expr, val }: CelResult) -> Result<Self, Self::Error> {
521 use serde_json::*;
522 Ok(match val {
523 CelValue::Int(n) => Value::from(n),
524 CelValue::UInt(n) => Value::from(n),
525 CelValue::Double(n) => Value::from(n.to_string()),
526 CelValue::Bool(b) => Value::from(b),
527 CelValue::String(n) => Value::from(n.as_str()),
528 CelValue::Null => Value::Null,
529 CelValue::Date(d) => Value::from(d.to_string()),
530 CelValue::Timestamp(d) => Value::from(d.to_rfc3339()),
531 CelValue::Uuid(u) => Value::from(u.to_string()),
532 CelValue::Map(m) => {
533 let mut res = serde_json::Map::new();
534 for (k, v) in m.inner.iter() {
535 let key: String = k.try_into()?;
536 let value = Self::try_from(CelResult {
537 expr,
538 val: v.clone(),
539 })?;
540 res.insert(key, value);
541 }
542 Value::from(res)
543 }
544 CelValue::List(a) => {
545 let mut res = Vec::new();
546 for v in a.inner.iter() {
547 res.push(Self::try_from(CelResult {
548 expr,
549 val: v.clone(),
550 })?);
551 }
552 Value::from(res)
553 }
554 CelValue::Decimal(d) => Value::from(d.to_string()),
555 CelValue::Bytes(_) => {
556 return Err(ResultCoercionError::BadExternalTypeCoercion(
557 expr.to_string(),
558 CelType::Bytes,
559 "serde_json::Value",
560 ));
561 }
562 })
563 }
564}