1use super::{Value, ValueEnum};
10use std::{
11 cmp::Ordering,
12 collections::{BTreeMap, BTreeSet},
13};
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub enum RuntimeValueKind {
18 Atomic,
20
21 Structured {
23 queryable: bool,
25 },
26}
27
28impl RuntimeValueKind {
29 #[must_use]
31 pub const fn is_queryable(self) -> bool {
32 match self {
33 Self::Atomic => true,
34 Self::Structured { queryable } => queryable,
35 }
36 }
37}
38
39pub trait RuntimeValueMeta {
41 fn kind() -> RuntimeValueKind
43 where
44 Self: Sized;
45}
46
47pub trait RuntimeValueEncode {
51 fn to_value(&self) -> Value;
53}
54
55pub trait RuntimeValueDecode {
60 #[must_use]
62 fn from_value(value: &Value) -> Option<Self>
63 where
64 Self: Sized;
65
66 #[doc(hidden)]
69 fn from_value_with_enum_context(
70 value: &Value,
71 _context: &dyn RuntimeEnumContext,
72 ) -> Option<Self>
73 where
74 Self: Sized,
75 {
76 Self::from_value(value)
77 }
78}
79
80#[doc(hidden)]
82pub struct RuntimeEnumSelection<'a> {
83 pub path: &'a str,
84 pub variant: &'a str,
85 pub payload: Option<&'a Value>,
86}
87
88#[doc(hidden)]
90pub trait RuntimeEnumContext {
91 fn resolve_enum<'a>(&'a self, value: &'a ValueEnum) -> Option<RuntimeEnumSelection<'a>>;
92}
93
94pub trait Collection {
96 type Item;
98
99 type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
101 where
102 Self: 'a;
103
104 fn iter(&self) -> Self::Iter<'_>;
106
107 fn len(&self) -> usize;
109
110 fn is_empty(&self) -> bool {
112 self.len() == 0
113 }
114}
115
116pub trait MapCollection {
118 type Key;
120
121 type Value;
123
124 type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
126 where
127 Self: 'a;
128
129 fn iter(&self) -> Self::Iter<'_>;
131
132 fn len(&self) -> usize;
134
135 fn is_empty(&self) -> bool {
137 self.len() == 0
138 }
139}
140
141impl<T> Collection for Vec<T> {
142 type Item = T;
143 type Iter<'a>
144 = std::slice::Iter<'a, T>
145 where
146 Self: 'a;
147
148 fn iter(&self) -> Self::Iter<'_> {
149 self.as_slice().iter()
150 }
151
152 fn len(&self) -> usize {
153 self.as_slice().len()
154 }
155}
156
157impl<T> Collection for BTreeSet<T> {
158 type Item = T;
159 type Iter<'a>
160 = std::collections::btree_set::Iter<'a, T>
161 where
162 Self: 'a;
163
164 fn iter(&self) -> Self::Iter<'_> {
165 self.iter()
166 }
167
168 fn len(&self) -> usize {
169 self.len()
170 }
171}
172
173impl<K, V> MapCollection for BTreeMap<K, V> {
174 type Key = K;
175 type Value = V;
176 type Iter<'a>
177 = std::collections::btree_map::Iter<'a, K, V>
178 where
179 Self: 'a;
180
181 fn iter(&self) -> Self::Iter<'_> {
182 self.iter()
183 }
184
185 fn len(&self) -> usize {
186 self.len()
187 }
188}
189
190pub fn runtime_value_to_value<T>(value: &T) -> Value
193where
194 T: ?Sized + RuntimeValueEncode,
195{
196 value.to_value()
197}
198
199#[must_use]
202pub fn runtime_value_from_value<T>(value: &Value) -> Option<T>
203where
204 T: RuntimeValueDecode,
205{
206 T::from_value(value)
207}
208
209#[doc(hidden)]
211pub fn runtime_value_from_value_with_enum_context<T>(
212 value: &Value,
213 context: &dyn RuntimeEnumContext,
214) -> Option<T>
215where
216 T: RuntimeValueDecode,
217{
218 T::from_value_with_enum_context(value, context)
219}
220
221#[doc(hidden)]
223#[must_use]
224pub fn runtime_value_from_value_with_optional_enum_context<T>(
225 value: &Value,
226 context: Option<&dyn RuntimeEnumContext>,
227) -> Option<T>
228where
229 T: RuntimeValueDecode,
230{
231 match context {
232 Some(context) => T::from_value_with_enum_context(value, context),
233 None => T::from_value(value),
234 }
235}
236
237pub fn runtime_value_collection_to_value<C>(collection: &C) -> Value
239where
240 C: Collection,
241 C::Item: RuntimeValueEncode,
242{
243 Value::List(
244 collection
245 .iter()
246 .map(RuntimeValueEncode::to_value)
247 .collect(),
248 )
249}
250
251#[must_use]
253pub fn runtime_value_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
254where
255 T: RuntimeValueDecode,
256{
257 decode_runtime_value_list(value, T::from_value)
258}
259
260fn decode_runtime_value_list<T>(
261 value: &Value,
262 mut decode: impl FnMut(&Value) -> Option<T>,
263) -> Option<Vec<T>> {
264 let Value::List(values) = value else {
265 return None;
266 };
267
268 let mut out = Vec::with_capacity(values.len());
269 for value in values {
270 out.push(decode(value)?);
271 }
272
273 Some(out)
274}
275
276#[must_use]
278pub fn runtime_value_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
279where
280 T: Ord + RuntimeValueDecode,
281{
282 decode_runtime_value_set(value, T::from_value)
283}
284
285fn decode_runtime_value_set<T>(
286 value: &Value,
287 mut decode: impl FnMut(&Value) -> Option<T>,
288) -> Option<BTreeSet<T>>
289where
290 T: Ord,
291{
292 let Value::List(values) = value else {
293 return None;
294 };
295
296 let mut out = BTreeSet::new();
297 for value in values {
298 let item = decode(value)?;
299 if !out.insert(item) {
300 return None;
301 }
302 }
303
304 Some(out)
305}
306
307pub fn runtime_value_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
309where
310 M: MapCollection,
311 M::Key: RuntimeValueEncode,
312 M::Value: RuntimeValueEncode,
313{
314 let mut entries: Vec<(Value, Value)> = map
315 .iter()
316 .map(|(key, value)| {
317 (
318 RuntimeValueEncode::to_value(key),
319 RuntimeValueEncode::to_value(value),
320 )
321 })
322 .collect();
323
324 if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
325 debug_assert!(false, "invalid map field value for {path}: {err}");
326 return Value::Map(entries);
327 }
328
329 Value::sort_map_entries_in_place(entries.as_mut_slice());
330
331 for i in 1..entries.len() {
332 let (left_key, _) = &entries[i - 1];
333 let (right_key, _) = &entries[i];
334 if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
335 debug_assert!(
336 false,
337 "duplicate map key in {path} after value-surface canonicalization",
338 );
339 break;
340 }
341 }
342
343 Value::Map(entries)
344}
345
346#[must_use]
349pub fn runtime_value_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
350where
351 K: Ord + RuntimeValueDecode,
352 V: RuntimeValueDecode,
353{
354 decode_runtime_value_map(value, K::from_value, V::from_value)
355}
356
357fn decode_runtime_value_map<K, V>(
358 value: &Value,
359 mut decode_key: impl FnMut(&Value) -> Option<K>,
360 mut decode_value: impl FnMut(&Value) -> Option<V>,
361) -> Option<BTreeMap<K, V>>
362where
363 K: Ord,
364{
365 let Value::Map(entries) = value else {
366 return None;
367 };
368
369 Value::validate_map_entries(entries).ok()?;
370 if !Value::map_entries_are_strictly_canonical(entries) {
371 return None;
372 }
373
374 let mut map = BTreeMap::new();
375 for (entry_key, entry_value) in entries {
376 let key = decode_key(entry_key)?;
377 let value = decode_value(entry_value)?;
378 match map.entry(key) {
379 std::collections::btree_map::Entry::Vacant(entry) => {
380 entry.insert(value);
381 }
382 std::collections::btree_map::Entry::Occupied(_) => return None,
383 }
384 }
385
386 Some(map)
387}
388
389#[must_use]
391pub fn runtime_value_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
392where
393 I: Into<T>,
394{
395 entries.into_iter().map(Into::into).collect()
396}
397
398#[must_use]
400pub fn runtime_value_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
401where
402 I: Into<T>,
403 T: Ord,
404{
405 entries.into_iter().map(Into::into).collect()
406}
407
408#[must_use]
411pub fn runtime_value_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
412where
413 IK: Into<K>,
414 IV: Into<V>,
415 K: Ord,
416{
417 entries
418 .into_iter()
419 .map(|(key, value)| (key.into(), value.into()))
420 .collect()
421}
422
423#[must_use]
425pub fn runtime_value_into<T, U>(value: U) -> T
426where
427 U: Into<T>,
428{
429 value.into()
430}
431
432impl RuntimeValueMeta for Value {
433 fn kind() -> RuntimeValueKind {
434 RuntimeValueKind::Atomic
435 }
436}
437
438impl RuntimeValueEncode for Value {
439 fn to_value(&self) -> Value {
440 self.clone()
441 }
442}
443
444impl RuntimeValueDecode for Value {
445 fn from_value(value: &Value) -> Option<Self> {
446 Some(value.clone())
447 }
448}
449
450impl RuntimeValueMeta for &str {
451 fn kind() -> RuntimeValueKind {
452 RuntimeValueKind::Atomic
453 }
454}
455
456impl RuntimeValueEncode for &str {
457 fn to_value(&self) -> Value {
458 Value::Text((*self).to_string())
459 }
460}
461
462impl RuntimeValueMeta for String {
463 fn kind() -> RuntimeValueKind {
464 RuntimeValueKind::Atomic
465 }
466}
467
468impl RuntimeValueEncode for String {
469 fn to_value(&self) -> Value {
470 Value::Text(self.clone())
471 }
472}
473
474impl RuntimeValueDecode for String {
475 fn from_value(value: &Value) -> Option<Self> {
476 match value {
477 Value::Text(value) => Some(value.clone()),
478 _ => None,
479 }
480 }
481}
482
483impl<T: RuntimeValueMeta> RuntimeValueMeta for Option<T> {
484 fn kind() -> RuntimeValueKind {
485 T::kind()
486 }
487}
488
489impl<T: RuntimeValueEncode> RuntimeValueEncode for Option<T> {
490 fn to_value(&self) -> Value {
491 match self {
492 Some(value) => value.to_value(),
493 None => Value::Null,
494 }
495 }
496}
497
498impl<T: RuntimeValueDecode> RuntimeValueDecode for Option<T> {
499 fn from_value(value: &Value) -> Option<Self> {
500 if matches!(value, Value::Null) {
501 return Some(None);
502 }
503
504 T::from_value(value).map(Some)
505 }
506
507 fn from_value_with_enum_context(
508 value: &Value,
509 context: &dyn RuntimeEnumContext,
510 ) -> Option<Self> {
511 if matches!(value, Value::Null) {
512 return Some(None);
513 }
514
515 T::from_value_with_enum_context(value, context).map(Some)
516 }
517}
518
519impl<T: RuntimeValueMeta> RuntimeValueMeta for Box<T> {
520 fn kind() -> RuntimeValueKind {
521 T::kind()
522 }
523}
524
525impl<T: RuntimeValueEncode> RuntimeValueEncode for Box<T> {
526 fn to_value(&self) -> Value {
527 (**self).to_value()
528 }
529}
530
531impl<T: RuntimeValueDecode> RuntimeValueDecode for Box<T> {
532 fn from_value(value: &Value) -> Option<Self> {
533 T::from_value(value).map(Self::new)
534 }
535
536 fn from_value_with_enum_context(
537 value: &Value,
538 context: &dyn RuntimeEnumContext,
539 ) -> Option<Self> {
540 T::from_value_with_enum_context(value, context).map(Self::new)
541 }
542}
543
544impl<T> RuntimeValueMeta for Vec<T> {
545 fn kind() -> RuntimeValueKind {
546 RuntimeValueKind::Structured { queryable: true }
547 }
548}
549
550impl<T: RuntimeValueEncode> RuntimeValueEncode for Vec<T> {
551 fn to_value(&self) -> Value {
552 runtime_value_collection_to_value(self)
553 }
554}
555
556impl<T: RuntimeValueDecode> RuntimeValueDecode for Vec<T> {
557 fn from_value(value: &Value) -> Option<Self> {
558 runtime_value_vec_from_value(value)
559 }
560
561 fn from_value_with_enum_context(
562 value: &Value,
563 context: &dyn RuntimeEnumContext,
564 ) -> Option<Self> {
565 decode_runtime_value_list(value, |value| {
566 T::from_value_with_enum_context(value, context)
567 })
568 }
569}
570
571impl<T> RuntimeValueMeta for BTreeSet<T>
572where
573 T: Ord,
574{
575 fn kind() -> RuntimeValueKind {
576 RuntimeValueKind::Structured { queryable: true }
577 }
578}
579
580impl<T> RuntimeValueEncode for BTreeSet<T>
581where
582 T: Ord + RuntimeValueEncode,
583{
584 fn to_value(&self) -> Value {
585 runtime_value_collection_to_value(self)
586 }
587}
588
589impl<T> RuntimeValueDecode for BTreeSet<T>
590where
591 T: Ord + RuntimeValueDecode,
592{
593 fn from_value(value: &Value) -> Option<Self> {
594 runtime_value_btree_set_from_value(value)
595 }
596
597 fn from_value_with_enum_context(
598 value: &Value,
599 context: &dyn RuntimeEnumContext,
600 ) -> Option<Self> {
601 decode_runtime_value_set(value, |value| {
602 T::from_value_with_enum_context(value, context)
603 })
604 }
605}
606
607impl<K, V> RuntimeValueMeta for BTreeMap<K, V>
608where
609 K: Ord,
610{
611 fn kind() -> RuntimeValueKind {
612 RuntimeValueKind::Structured { queryable: true }
613 }
614}
615
616impl<K, V> RuntimeValueEncode for BTreeMap<K, V>
617where
618 K: Ord + RuntimeValueEncode,
619 V: RuntimeValueEncode,
620{
621 fn to_value(&self) -> Value {
622 runtime_value_map_collection_to_value(self, std::any::type_name::<Self>())
623 }
624}
625
626impl<K, V> RuntimeValueDecode for BTreeMap<K, V>
627where
628 K: Ord + RuntimeValueDecode,
629 V: RuntimeValueDecode,
630{
631 fn from_value(value: &Value) -> Option<Self> {
632 runtime_value_btree_map_from_value(value)
633 }
634
635 fn from_value_with_enum_context(
636 value: &Value,
637 context: &dyn RuntimeEnumContext,
638 ) -> Option<Self> {
639 decode_runtime_value_map(
640 value,
641 |key| K::from_value_with_enum_context(key, context),
642 |value| V::from_value_with_enum_context(value, context),
643 )
644 }
645}
646
647macro_rules! impl_runtime_value {
648 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
649 $(
650 impl RuntimeValueMeta for $type {
651 fn kind() -> RuntimeValueKind {
652 RuntimeValueKind::Atomic
653 }
654 }
655
656 impl RuntimeValueEncode for $type {
657 fn to_value(&self) -> Value {
658 Value::$variant((*self).into())
659 }
660 }
661
662 impl RuntimeValueDecode for $type {
663 fn from_value(value: &Value) -> Option<Self> {
664 match value {
665 Value::$variant(value) => (*value).try_into().ok(),
666 _ => None,
667 }
668 }
669 }
670 )*
671 };
672}
673
674impl_runtime_value!(
675 i8 => Int64,
676 i16 => Int64,
677 i32 => Int64,
678 i64 => Int64,
679 i128 => Int128,
680 u8 => Nat64,
681 u16 => Nat64,
682 u32 => Nat64,
683 u64 => Nat64,
684 u128 => Nat128,
685 bool => Bool,
686);