1use owning_ref::ArcRef;
14use serde::{Deserialize, Serialize};
15use std::sync::Arc;
16
17#[derive(Clone, PartialEq, Hash, Eq)]
29#[repr(transparent)]
30pub struct ValueRef<T: 'static = serde_json::Value>(ArcRef<'static, serde_json::Value, T>);
31
32impl<T: std::fmt::Debug> std::fmt::Debug for ValueRef<T> {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 self.0.fmt(f)
35 }
36}
37
38impl Default for ValueRef {
39 fn default() -> Self {
40 Self(ArcRef::new(Arc::new(serde_json::Value::Null)))
41 }
42}
43
44impl schemars::JsonSchema for ValueRef {
45 fn schema_name() -> std::borrow::Cow<'static, str> {
46 "Value".into()
47 }
48
49 fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
50 schemars::json_schema!({
51 "description": "Any JSON value (object, array, string, number, boolean, or null)"
52 })
53 }
54}
55
56impl Serialize for ValueRef {
57 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58 where
59 S: serde::Serializer,
60 {
61 self.0.as_ref().serialize(serializer)
62 }
63}
64
65impl<'de> Deserialize<'de> for ValueRef {
66 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
67 where
68 D: serde::Deserializer<'de>,
69 {
70 serde_json::Value::deserialize(deserializer).map(Self::new)
71 }
72}
73
74impl<T: Into<serde_json::Value>> From<T> for ValueRef {
75 fn from(value: T) -> Self {
76 Self::new(value.into())
77 }
78}
79
80impl ValueRef<serde_json::Value> {
81 pub fn new(value: serde_json::Value) -> Self {
82 Self(ArcRef::new(Arc::new(value)))
83 }
84
85 pub fn redacted<'a>(
87 &'a self,
88 secrets: &'a crate::values::Secrets,
89 ) -> crate::values::RedactedValue<'a> {
90 secrets.redacted(self.value())
91 }
92
93 pub fn is_truthy(&self) -> bool {
94 match self.0.as_ref() {
95 serde_json::Value::Bool(b) => *b,
96 serde_json::Value::Number(n) => {
97 if let Some(n) = n.as_u64() {
98 n != 0
99 } else if let Some(n) = n.as_i64() {
100 n != 0
101 } else {
102 n.as_f64().unwrap() != 0.0
103 }
104 }
105 serde_json::Value::String(s) => !s.is_empty(),
106 _ => true,
107 }
108 }
109
110 pub fn path(&self, path: &str) -> Option<ValueRef> {
112 match self.0.as_ref() {
113 serde_json::Value::Object(obj) => obj
114 .get(path)
115 .map(|v| ValueRef(project_to_subfield(self.0.clone(), v))),
116 _ => None,
117 }
118 }
119
120 pub fn index(&self, index: usize) -> Option<ValueRef> {
122 match self.0.as_ref() {
123 serde_json::Value::Array(arr) => arr
124 .get(index)
125 .map(|v| ValueRef(project_to_subfield(self.0.clone(), v))),
126 _ => None,
127 }
128 }
129
130 pub fn resolve_json_path(&self, json_path: &crate::workflow::JsonPath) -> Option<ValueRef> {
132 use crate::workflow::PathPart;
133
134 let mut current = self.clone();
135
136 for part in json_path.parts() {
137 match part {
138 PathPart::Field(field_name) => {
139 current = current.path(field_name)?;
140 }
141 PathPart::Index(index) => {
142 current = current.index(*index)?;
143 }
144 PathPart::IndexStr(index_str) => {
145 current = current.path(index_str)?;
146 }
147 }
148 }
149
150 Some(current)
151 }
152
153 pub fn as_object(&self) -> Option<ValueRef<serde_json::Map<String, serde_json::Value>>> {
155 match self.0.as_ref() {
156 serde_json::Value::Object(obj) => {
157 Some(ValueRef(project_to_subfield(self.0.clone(), obj)))
158 }
159 _ => None,
160 }
161 }
162
163 pub fn as_array(&self) -> Option<ValueRef<Vec<serde_json::Value>>> {
165 match self.0.as_ref() {
166 serde_json::Value::Array(arr) => {
167 Some(ValueRef(project_to_subfield(self.0.clone(), arr)))
168 }
169 _ => None,
170 }
171 }
172
173 pub fn value(&self) -> &serde_json::Value {
174 self.0.as_ref()
175 }
176
177 pub fn clone_value(&self) -> serde_json::Value {
179 self.0.as_ref().clone()
180 }
181
182 pub fn deserialize<T>(&self) -> Result<T, serde_json::Error>
184 where
185 T: serde::de::DeserializeOwned,
186 {
187 serde_json::from_value(self.as_ref().clone())
188 }
189
190 pub fn as_bool(&self) -> Option<bool> {
192 match self.0.as_ref() {
193 serde_json::Value::Bool(b) => Some(*b),
194 _ => None,
195 }
196 }
197
198 pub fn as_str(&self) -> Option<&str> {
200 match self.0.as_ref() {
201 serde_json::Value::String(s) => Some(s.as_str()),
202 _ => None,
203 }
204 }
205
206 pub fn as_number(&self) -> Option<&serde_json::Number> {
208 match self.0.as_ref() {
209 serde_json::Value::Number(n) => Some(n),
210 _ => None,
211 }
212 }
213
214 pub fn is_null(&self) -> bool {
216 matches!(self.0.as_ref(), serde_json::Value::Null)
217 }
218}
219
220impl ValueRef<Vec<serde_json::Value>> {
221 pub fn iter(&self) -> impl Iterator<Item = ValueRef> + '_ {
222 (0..self.0.len()).map(move |i| ValueRef(self.0.clone().map(move |vec| &vec[i])))
223 }
224
225 pub fn get(&self, index: usize) -> Option<ValueRef> {
226 if index < self.0.len() {
227 Some(ValueRef(self.0.clone().map(move |vec| &vec[index])))
228 } else {
229 None
230 }
231 }
232
233 pub fn len(&self) -> usize {
234 self.0.len()
235 }
236
237 pub fn is_empty(&self) -> bool {
238 self.0.is_empty()
239 }
240}
241
242fn project_to_subfield<C, T1, T2>(arc: ArcRef<'static, C, T1>, value: &T2) -> ArcRef<'static, C, T2>
246where
247 T1: 'static,
248 T2: 'static,
249{
250 let ptr = value as *const T2;
251 arc.map(move |_| unsafe { &*ptr })
254}
255
256impl ValueRef<serde_json::Map<String, serde_json::Value>> {
257 pub fn iter(&self) -> impl Iterator<Item = (&str, ValueRef)> + '_ {
258 self.0.iter().map(|(k, v)| {
259 let k = k.as_str();
260 (k, ValueRef(project_to_subfield(self.0.clone(), v)))
261 })
262 }
263
264 pub fn get(&self, key: &str) -> Option<ValueRef> {
265 self.0
266 .get(key)
267 .map(|v| ValueRef(project_to_subfield(self.0.clone(), v)))
268 }
269
270 pub fn contains_key(&self, key: &str) -> bool {
271 self.0.contains_key(key)
272 }
273
274 pub fn len(&self) -> usize {
275 self.0.len()
276 }
277
278 pub fn is_empty(&self) -> bool {
279 self.0.is_empty()
280 }
281
282 pub fn keys(&self) -> impl Iterator<Item = &str> {
283 self.0.keys().map(|s| s.as_str())
284 }
285}
286
287impl AsRef<serde_json::Value> for ValueRef {
289 fn as_ref(&self) -> &serde_json::Value {
290 &self.0
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use std::f64::consts::PI;
297
298 use super::*;
299 use serde_json::json;
300
301 #[test]
302 fn test_value_ref_new() {
303 let value = json!({"key": "value"});
304 let value_ref = ValueRef::new(value.clone());
305 assert_eq!(value_ref.as_ref(), &value);
306 }
307
308 #[test]
309 fn test_value_ref_path_object() {
310 let value = json!({
311 "name": "Alice",
312 "age": 30,
313 "nested": {
314 "city": "San Francisco"
315 }
316 });
317 let value_ref = ValueRef::new(value);
318
319 let name = value_ref.path("name").unwrap();
321 assert_eq!(name.as_ref(), &json!("Alice"));
322
323 let nested = value_ref.path("nested").unwrap();
325 assert_eq!(nested.as_ref(), &json!({"city": "San Francisco"}));
326
327 let city = nested.path("city").unwrap();
329 assert_eq!(city.as_ref(), &json!("San Francisco"));
330
331 assert!(value_ref.path("nonexistent").is_none());
333 }
334
335 #[test]
336 fn test_value_ref_path_array() {
337 let value = json!(["first", "second", {"nested": "value"}]);
338 let value_ref = ValueRef::new(value);
339
340 let first = value_ref.index(0).unwrap();
342 assert_eq!(first.as_ref(), &json!("first"));
343
344 let second = value_ref.index(1).unwrap();
345 assert_eq!(second.as_ref(), &json!("second"));
346
347 let third = value_ref.index(2).unwrap();
348 assert_eq!(third.as_ref(), &json!({"nested": "value"}));
349
350 let nested = third.path("nested").unwrap();
352 assert_eq!(nested.as_ref(), &json!("value"));
353
354 assert!(value_ref.index(10).is_none());
356 }
357
358 #[test]
359 fn test_value_ref_as_object() {
360 let value = json!({
361 "key1": "value1",
362 "key2": "value2"
363 });
364 let value_ref = ValueRef::new(value);
365
366 let obj = value_ref.as_object().unwrap();
367 assert_eq!(obj.len(), 2);
368 assert!(obj.contains_key("key1"));
369 assert!(obj.contains_key("key2"));
370
371 let val1 = obj.get("key1").unwrap();
372 assert_eq!(val1.as_ref(), &json!("value1"));
373
374 let keys: Vec<&str> = obj.keys().collect();
376 assert!(keys.contains(&"key1"));
377 assert!(keys.contains(&"key2"));
378
379 let items: Vec<_> = obj.iter().collect();
381 assert_eq!(items.len(), 2);
382 }
383
384 #[test]
385 fn test_value_ref_as_array() {
386 let value = json!(["item1", "item2", "item3"]);
387 let value_ref = ValueRef::new(value);
388
389 let arr = value_ref.as_array().unwrap();
390 assert_eq!(arr.len(), 3);
391 assert!(!arr.is_empty());
392
393 let item1 = arr.get(0).unwrap();
394 assert_eq!(item1.as_ref(), &json!("item1"));
395
396 let item2 = arr.get(1).unwrap();
397 assert_eq!(item2.as_ref(), &json!("item2"));
398
399 assert!(arr.get(10).is_none());
401
402 let items: Vec<_> = arr.iter().collect();
404 assert_eq!(items.len(), 3);
405 assert_eq!(items[0].as_ref(), &json!("item1"));
406 assert_eq!(items[1].as_ref(), &json!("item2"));
407 assert_eq!(items[2].as_ref(), &json!("item3"));
408 }
409
410 #[test]
411 fn test_value_ref_is_truthy() {
412 assert!(ValueRef::new(json!(true)).is_truthy());
413 assert!(!ValueRef::new(json!(false)).is_truthy());
414
415 assert!(ValueRef::new(json!(1)).is_truthy());
416 assert!(ValueRef::new(json!(-1)).is_truthy());
417 assert!(ValueRef::new(json!(1.5)).is_truthy());
418 assert!(!ValueRef::new(json!(0)).is_truthy());
419 assert!(!ValueRef::new(json!(0.0)).is_truthy());
420
421 assert!(ValueRef::new(json!("hello")).is_truthy());
422 assert!(!ValueRef::new(json!("")).is_truthy());
423
424 assert!(ValueRef::new(json!(null)).is_truthy());
425 assert!(ValueRef::new(json!({})).is_truthy());
426 assert!(ValueRef::new(json!([])).is_truthy());
427 }
428
429 #[test]
430 fn test_value_ref_deserialize() {
431 use serde::{Deserialize, Serialize};
432
433 #[derive(Debug, PartialEq, Serialize, Deserialize)]
434 struct TestStruct {
435 name: String,
436 age: u32,
437 }
438
439 let data = TestStruct {
440 name: "Alice".to_string(),
441 age: 30,
442 };
443 let value = serde_json::to_value(&data).unwrap();
444 let value_ref = ValueRef::new(value);
445
446 let deserialized: TestStruct = value_ref.deserialize().unwrap();
447 assert_eq!(deserialized, data);
448
449 let invalid_value = ValueRef::new(json!("not a struct"));
451 let result: Result<TestStruct, _> = invalid_value.deserialize();
452 assert!(result.is_err());
453 }
454
455 #[test]
456 fn test_value_ref_type_accessors() {
457 assert_eq!(ValueRef::new(json!(true)).as_bool(), Some(true));
459 assert_eq!(ValueRef::new(json!(false)).as_bool(), Some(false));
460 assert_eq!(ValueRef::new(json!("hello")).as_bool(), None);
461 assert_eq!(ValueRef::new(json!(42)).as_bool(), None);
462
463 assert_eq!(ValueRef::new(json!("hello")).as_str(), Some("hello"));
465 assert_eq!(ValueRef::new(json!("")).as_str(), Some(""));
466 assert_eq!(ValueRef::new(json!(42)).as_str(), None);
467 assert_eq!(ValueRef::new(json!(true)).as_str(), None);
468
469 let num_value = ValueRef::new(json!(42));
471 assert!(num_value.as_number().is_some());
472 assert_eq!(num_value.as_number().unwrap().as_u64(), Some(42));
473
474 let float_value = ValueRef::new(json!(PI));
475 assert!(float_value.as_number().is_some());
476 assert_eq!(float_value.as_number().unwrap().as_f64(), Some(PI));
477
478 assert_eq!(ValueRef::new(json!("hello")).as_number(), None);
479 assert_eq!(ValueRef::new(json!(true)).as_number(), None);
480
481 assert!(ValueRef::new(json!(null)).is_null());
483 assert!(!ValueRef::new(json!(0)).is_null());
484 assert!(!ValueRef::new(json!("")).is_null());
485 assert!(!ValueRef::new(json!(false)).is_null());
486 }
487
488 fn assert_same_base<T1, T2>(base: &ValueRef<T1>, derived: &ValueRef<T2>)
490 where
491 T1: 'static,
492 T2: 'static,
493 {
494 assert!(
495 Arc::ptr_eq(base.0.as_owner(), derived.0.as_owner()),
496 "ValueRefs should share the same underlying Arc (no cloning)"
497 );
498 }
499
500 #[test]
501 fn test_path_access_no_cloning() {
502 let value = json!({
503 "data": {
504 "nested": {
505 "deep": "value"
506 }
507 }
508 });
509
510 let root = ValueRef::new(value);
511 let data = root.path("data").unwrap();
512 let nested = data.path("nested").unwrap();
513 let deep = nested.path("deep").unwrap();
514
515 assert_same_base(&root, &data);
517 assert_same_base(&root, &nested);
518 assert_same_base(&root, &deep);
519
520 assert_eq!(deep.as_ref(), &json!("value"));
522 }
523
524 #[test]
525 fn test_array_index_access_no_cloning() {
526 let value = json!([
527 {"name": "first"},
528 {"name": "second"},
529 [1, 2, 3]
530 ]);
531
532 let root = ValueRef::new(value);
533 let first_item = root.index(0).unwrap();
534 let second_item = root.index(1).unwrap();
535 let third_item = root.index(2).unwrap();
536 let nested_array_item = third_item.index(1).unwrap();
537
538 assert_same_base(&root, &first_item);
540 assert_same_base(&root, &second_item);
541 assert_same_base(&root, &third_item);
542 assert_same_base(&root, &nested_array_item);
543
544 assert_eq!(first_item.as_ref(), &json!({"name": "first"}));
546 assert_eq!(nested_array_item.as_ref(), &json!(2));
547 }
548
549 #[test]
550 fn test_as_object_access_no_cloning() {
551 let value = json!({
552 "metadata": {
553 "count": 42,
554 "items": ["a", "b", "c"]
555 }
556 });
557
558 let root = ValueRef::new(value);
559 let metadata = root.path("metadata").unwrap();
560 let metadata_obj = metadata.as_object().unwrap();
561
562 let count = metadata_obj.get("count").unwrap();
564 let items = metadata_obj.get("items").unwrap();
565
566 assert_same_base(&root, &metadata);
568 assert_same_base(&root, &metadata_obj);
569 assert_same_base(&root, &count);
570 assert_same_base(&root, &items);
571
572 assert_eq!(count.as_ref(), &json!(42));
574 assert_eq!(items.as_ref(), &json!(["a", "b", "c"]));
575 }
576
577 #[test]
578 fn test_as_array_access_no_cloning() {
579 let value = json!({
580 "items": [
581 {"id": 1, "name": "first"},
582 {"id": 2, "name": "second"},
583 {"id": 3, "name": "third"}
584 ]
585 });
586
587 let root = ValueRef::new(value);
588 let items = root.path("items").unwrap();
589 let items_array = items.as_array().unwrap();
590
591 let first_item = items_array.get(0).unwrap();
593 let second_item = items_array.get(1).unwrap();
594 let third_item = items_array.get(2).unwrap();
595
596 let first_name = first_item.path("name").unwrap();
598
599 assert_same_base(&root, &items);
601 assert_same_base(&root, &items_array);
602 assert_same_base(&root, &first_item);
603 assert_same_base(&root, &second_item);
604 assert_same_base(&root, &third_item);
605 assert_same_base(&root, &first_name);
606
607 assert_eq!(first_item.as_ref(), &json!({"id": 1, "name": "first"}));
609 assert_eq!(first_name.as_ref(), &json!("first"));
610 }
611
612 #[test]
613 fn test_object_iter_no_cloning() {
614 let value = json!({
615 "key1": "value1",
616 "key2": {"nested": "value2"},
617 "key3": [1, 2, 3]
618 });
619
620 let root = ValueRef::new(value);
621 let obj = root.as_object().unwrap();
622
623 assert_same_base(&root, &obj);
625
626 let items = obj.iter();
628 for (_key, value_ref) in items {
629 assert_same_base(&root, &value_ref);
630 }
631 }
632
633 #[test]
634 fn test_array_iter_no_cloning() {
635 let value = json!([
636 {"type": "first"},
637 {"type": "second"},
638 [1, 2, {"nested": "deep"}]
639 ]);
640
641 let root = ValueRef::new(value);
642 let arr = root.as_array().unwrap();
643
644 assert_same_base(&root, &arr);
646
647 let items: Vec<_> = arr.iter().collect();
649 for item in &items {
650 assert_same_base(&root, item);
651 }
652
653 let nested_array = &items[2];
655 let nested_arr = nested_array.as_array().unwrap();
656 let deep_object = nested_arr.get(2).unwrap();
657 let deep_value = deep_object.path("nested").unwrap();
658
659 assert_same_base(&root, &nested_arr);
661 assert_same_base(&root, &deep_object);
662 assert_same_base(&root, &deep_value);
663
664 assert_eq!(deep_value.as_ref(), &json!("deep"));
666 }
667}