1mod canonical;
12mod canonical_enum;
13mod coercion;
14mod compare;
15mod hash;
16mod input;
17mod map;
18pub(crate) mod ops;
19mod output;
20mod rank;
21mod runtime;
22mod semantics;
23mod tag;
24mod wire;
25
26#[cfg(test)]
27mod runtime_tests;
28#[cfg(test)]
29mod tests;
30
31use crate::types::*;
32use serde::{Deserialize, Deserializer, de};
33use std::{cmp::Ordering, fmt};
34
35pub(crate) use canonical::canonicalize_value_set;
37pub(crate) use canonical_enum::{CanonicalEnumBody, CanonicalEnumValue, EnumTypeId, EnumVariantId};
38pub use coercion::CoercionFamily;
39#[cfg(test)]
40pub(crate) use hash::with_test_hash_override;
41pub(crate) use hash::{ValueHashWriter, hash_single_list_identity_canonical_value, hash_value};
42pub use input::{InputValue, InputValueEnum};
43pub use map::{MapValueError, SchemaInvariantError};
44pub use output::{OutputValue, OutputValueEnum, render_output_value_text};
45pub use runtime::{
46 Collection, MapCollection, RuntimeEnumContext, RuntimeEnumSelection, RuntimeValueDecode,
47 RuntimeValueEncode, RuntimeValueKind, RuntimeValueMeta, runtime_value_btree_map_from_value,
48 runtime_value_btree_set_from_value, runtime_value_collection_to_value,
49 runtime_value_from_value, runtime_value_from_value_with_enum_context,
50 runtime_value_from_value_with_optional_enum_context, runtime_value_from_vec_into,
51 runtime_value_from_vec_into_btree_map, runtime_value_from_vec_into_btree_set,
52 runtime_value_into, runtime_value_map_collection_to_value, runtime_value_to_value,
53 runtime_value_vec_from_value,
54};
55pub use tag::ValueTag;
56
57const VALUE_WIRE_TYPE_NAME: &str = "Value";
62const VALUE_WIRE_VARIANT_LABELS: &[&str] = &[
63 "Account",
64 "Blob",
65 "Bool",
66 "Date",
67 "Decimal",
68 "Duration",
69 "Enum",
70 "Float32",
71 "Float64",
72 "Int",
73 "Int128",
74 "IntBig",
75 "List",
76 "Map",
77 "Null",
78 "Principal",
79 "Subaccount",
80 "Text",
81 "Timestamp",
82 "Nat",
83 "Nat128",
84 "NatBig",
85 "Ulid",
86 "Unit",
87];
88
89#[derive(Clone, Copy)]
91enum ValueWireVariant {
92 Account,
93 Blob,
94 Bool,
95 Date,
96 Decimal,
97 Duration,
98 Enum,
99 Float32,
100 Float64,
101 Int64,
102 Int128,
103 IntBig,
104 List,
105 Map,
106 Null,
107 Principal,
108 Subaccount,
109 Text,
110 Timestamp,
111 Nat64,
112 Nat128,
113 NatBig,
114 Ulid,
115 Unit,
116}
117
118impl ValueWireVariant {
119 fn from_label(label: &str) -> Option<Self> {
121 match label {
122 "Account" => Some(Self::Account),
123 "Blob" => Some(Self::Blob),
124 "Bool" => Some(Self::Bool),
125 "Date" => Some(Self::Date),
126 "Decimal" => Some(Self::Decimal),
127 "Duration" => Some(Self::Duration),
128 "Enum" => Some(Self::Enum),
129 "Float32" => Some(Self::Float32),
130 "Float64" => Some(Self::Float64),
131 "Int" => Some(Self::Int64),
132 "Int128" => Some(Self::Int128),
133 "IntBig" => Some(Self::IntBig),
134 "List" => Some(Self::List),
135 "Map" => Some(Self::Map),
136 "Null" => Some(Self::Null),
137 "Principal" => Some(Self::Principal),
138 "Subaccount" => Some(Self::Subaccount),
139 "Text" => Some(Self::Text),
140 "Timestamp" => Some(Self::Timestamp),
141 "Nat" => Some(Self::Nat64),
142 "Nat128" => Some(Self::Nat128),
143 "NatBig" => Some(Self::NatBig),
144 "Ulid" => Some(Self::Ulid),
145 "Unit" => Some(Self::Unit),
146 _ => None,
147 }
148 }
149}
150
151#[derive(Clone, Copy, Debug, Eq, PartialEq)]
156pub enum TextMode {
157 Cs, Ci, }
160
161#[derive(Clone, Eq, PartialEq)]
175pub enum Value {
176 Account(Account),
177 Blob(Vec<u8>),
178 Bool(bool),
179 Date(Date),
180 Decimal(Decimal),
181 Duration(Duration),
182 Enum(ValueEnum),
183 Float32(Float32),
184 Float64(Float64),
185 Int64(i64),
186 Int128(i128),
187 IntBig(IntBig),
188 List(Vec<Self>),
192 Map(Vec<(Self, Self)>),
199 Null,
200 Principal(Principal),
201 Subaccount(Subaccount),
202 Text(String),
203 Timestamp(Timestamp),
204 Nat64(u64),
205 Nat128(u128),
206 NatBig(NatBig),
207 Ulid(Ulid),
208 Unit,
209}
210
211impl fmt::Debug for Value {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 match self {
214 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
215 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
216 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
217 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
218 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
219 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
220 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
221 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
222 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
223 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
224 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
225 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
226 Self::List(value) => f.debug_tuple("List").field(value).finish(),
227 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
228 Self::Null => f.write_str("Null"),
229 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
230 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
231 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
232 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
233 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
234 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
235 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
236 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
237 Self::Unit => f.write_str("Unit"),
238 }
239 }
240}
241
242impl Value {
243 pub fn from_slice<T>(items: &[T]) -> Self
252 where
253 T: Into<Self> + Clone,
254 {
255 Self::List(items.iter().cloned().map(Into::into).collect())
256 }
257
258 pub fn from_list<T>(items: Vec<T>) -> Self
262 where
263 T: Into<Self>,
264 {
265 Self::List(items.into_iter().map(Into::into).collect())
266 }
267
268 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
276 let normalized = map::normalize_map_entries(entries)?;
277 Ok(Self::Map(normalized))
278 }
279
280 #[must_use]
286 pub const fn is_text(&self) -> bool {
287 matches!(self, Self::Text(_))
288 }
289
290 #[must_use]
292 pub const fn is_unit(&self) -> bool {
293 matches!(self, Self::Unit)
294 }
295
296 #[must_use]
297 pub const fn is_scalar(&self) -> bool {
298 match self {
299 Self::List(_) | Self::Map(_) | Self::Unit => false,
301 _ => true,
302 }
303 }
304
305 #[must_use]
307 pub(crate) fn contains_enum(&self) -> bool {
308 match self {
309 Self::Enum(_) => true,
310 Self::List(values) => values.iter().any(Self::contains_enum),
311 Self::Map(entries) => entries
312 .iter()
313 .any(|(key, value)| key.contains_enum() || value.contains_enum()),
314 _ => false,
315 }
316 }
317
318 #[must_use]
320 pub(crate) const fn canonical_tag(&self) -> ValueTag {
321 tag::canonical_tag(self)
322 }
323
324 #[must_use]
326 pub(crate) const fn canonical_rank(&self) -> u8 {
327 rank::canonical_rank(self)
328 }
329
330 #[must_use]
332 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
333 compare::canonical_cmp(left, right)
334 }
335
336 #[must_use]
338 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
339 compare::canonical_cmp_key(left, right)
340 }
341
342 #[must_use]
347 pub const fn as_text(&self) -> Option<&str> {
348 if let Self::Text(s) = self {
349 Some(s.as_str())
350 } else {
351 None
352 }
353 }
354
355 #[must_use]
356 pub const fn as_list(&self) -> Option<&[Self]> {
357 if let Self::List(xs) = self {
358 Some(xs.as_slice())
359 } else {
360 None
361 }
362 }
363
364 #[must_use]
365 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
366 if let Self::Map(entries) = self {
367 Some(entries.as_slice())
368 } else {
369 None
370 }
371 }
372}
373
374macro_rules! impl_from_for {
375 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
376 $(
377 impl From<$type> for Value {
378 fn from(v: $type) -> Self {
379 Self::$variant(v.into())
380 }
381 }
382 )*
383 };
384}
385
386impl_from_for! {
387 Account => Account,
388 Date => Date,
389 Decimal => Decimal,
390 Duration => Duration,
391 bool => Bool,
392 i8 => Int64,
393 i16 => Int64,
394 i32 => Int64,
395 i64 => Int64,
396 i128 => Int128,
397 IntBig => IntBig,
398 Principal => Principal,
399 Subaccount => Subaccount,
400 &str => Text,
401 String => Text,
402 Timestamp => Timestamp,
403 u8 => Nat64,
404 u16 => Nat64,
405 u32 => Nat64,
406 u64 => Nat64,
407 u128 => Nat128,
408 NatBig => NatBig,
409 Ulid => Ulid,
410}
411
412impl From<Vec<Self>> for Value {
413 fn from(vec: Vec<Self>) -> Self {
414 Self::List(vec)
415 }
416}
417
418impl TryFrom<Vec<(Self, Self)>> for Value {
419 type Error = SchemaInvariantError;
420
421 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
422 Self::from_map(entries).map_err(Self::Error::from)
423 }
424}
425
426impl From<()> for Value {
427 fn from((): ()) -> Self {
428 Self::Unit
429 }
430}
431
432#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
438pub struct ValueEnum(CanonicalEnumValue<Value>);
439
440impl ValueEnum {
441 #[cfg(test)]
442 pub(crate) const fn test_unit(type_id: u32, variant_id: u32) -> Self {
443 Self::new(
444 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
445 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
446 CanonicalEnumBody::Unit,
447 )
448 }
449
450 #[cfg(test)]
451 pub(crate) fn test_payload(type_id: u32, variant_id: u32, payload: Value) -> Self {
452 Self::new(
453 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
454 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
455 CanonicalEnumBody::Payload(Box::new(payload)),
456 )
457 }
458
459 #[cfg(test)]
460 pub(crate) fn test_with_payload(self, payload: Value) -> Self {
461 Self::new(
462 self.type_id(),
463 self.variant_id(),
464 CanonicalEnumBody::Payload(Box::new(payload)),
465 )
466 }
467
468 #[must_use]
469 pub(crate) const fn from_canonical(value: CanonicalEnumValue<Value>) -> Self {
470 Self(value)
471 }
472
473 #[must_use]
474 pub(crate) const fn new(
475 type_id: EnumTypeId,
476 variant_id: EnumVariantId,
477 body: CanonicalEnumBody<Value>,
478 ) -> Self {
479 Self(CanonicalEnumValue::new(type_id, variant_id, body))
480 }
481
482 #[must_use]
483 pub(crate) const fn canonical(&self) -> &CanonicalEnumValue<Value> {
484 &self.0
485 }
486
487 #[must_use]
488 pub(crate) const fn type_id(&self) -> EnumTypeId {
489 self.0.type_id()
490 }
491
492 #[must_use]
493 pub(crate) const fn variant_id(&self) -> EnumVariantId {
494 self.0.variant_id()
495 }
496
497 #[must_use]
498 pub(crate) const fn body(&self) -> &CanonicalEnumBody<Value> {
499 self.0.body()
500 }
501
502 #[must_use]
503 pub(crate) fn payload(&self) -> Option<&Value> {
504 match self.body() {
505 CanonicalEnumBody::Unit => None,
506 CanonicalEnumBody::Payload(payload) => Some(payload.as_ref()),
507 }
508 }
509}
510
511impl<'de> Deserialize<'de> for ValueEnum {
512 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
513 where
514 D: Deserializer<'de>,
515 {
516 let (type_id, variant_id, payload): (u32, u32, Option<Box<Value>>) =
517 Deserialize::deserialize(deserializer)?;
518 let type_id = EnumTypeId::new(type_id)
519 .ok_or_else(|| de::Error::custom("enum type ID must be non-zero"))?;
520 let variant_id = EnumVariantId::new(variant_id)
521 .ok_or_else(|| de::Error::custom("enum variant ID must be non-zero"))?;
522 let body = payload.map_or(CanonicalEnumBody::Unit, CanonicalEnumBody::Payload);
523 Ok(Self::new(type_id, variant_id, body))
524 }
525}