1mod canonical;
12mod canonical_enum;
13mod coercion;
14mod compare;
15mod hash;
16mod input;
17mod map;
18pub(crate) mod ops;
19mod output;
20mod rank;
21mod semantics;
22mod tag;
23mod wire;
24
25#[cfg(test)]
26mod tests;
27
28use crate::{
29 traits::{RuntimeValueDecode, RuntimeValueEncode, RuntimeValueMeta},
30 types::*,
31};
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, CoercionFamilyExt};
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 tag::ValueTag;
46
47const VALUE_WIRE_TYPE_NAME: &str = "Value";
52const VALUE_WIRE_VARIANT_LABELS: &[&str] = &[
53 "Account",
54 "Blob",
55 "Bool",
56 "Date",
57 "Decimal",
58 "Duration",
59 "Enum",
60 "Float32",
61 "Float64",
62 "Int",
63 "Int128",
64 "IntBig",
65 "List",
66 "Map",
67 "Null",
68 "Principal",
69 "Subaccount",
70 "Text",
71 "Timestamp",
72 "Nat",
73 "Nat128",
74 "NatBig",
75 "Ulid",
76 "Unit",
77];
78
79#[derive(Clone, Copy)]
81enum ValueWireVariant {
82 Account,
83 Blob,
84 Bool,
85 Date,
86 Decimal,
87 Duration,
88 Enum,
89 Float32,
90 Float64,
91 Int64,
92 Int128,
93 IntBig,
94 List,
95 Map,
96 Null,
97 Principal,
98 Subaccount,
99 Text,
100 Timestamp,
101 Nat64,
102 Nat128,
103 NatBig,
104 Ulid,
105 Unit,
106}
107
108impl ValueWireVariant {
109 fn from_label(label: &str) -> Option<Self> {
111 match label {
112 "Account" => Some(Self::Account),
113 "Blob" => Some(Self::Blob),
114 "Bool" => Some(Self::Bool),
115 "Date" => Some(Self::Date),
116 "Decimal" => Some(Self::Decimal),
117 "Duration" => Some(Self::Duration),
118 "Enum" => Some(Self::Enum),
119 "Float32" => Some(Self::Float32),
120 "Float64" => Some(Self::Float64),
121 "Int" => Some(Self::Int64),
122 "Int128" => Some(Self::Int128),
123 "IntBig" => Some(Self::IntBig),
124 "List" => Some(Self::List),
125 "Map" => Some(Self::Map),
126 "Null" => Some(Self::Null),
127 "Principal" => Some(Self::Principal),
128 "Subaccount" => Some(Self::Subaccount),
129 "Text" => Some(Self::Text),
130 "Timestamp" => Some(Self::Timestamp),
131 "Nat" => Some(Self::Nat64),
132 "Nat128" => Some(Self::Nat128),
133 "NatBig" => Some(Self::NatBig),
134 "Ulid" => Some(Self::Ulid),
135 "Unit" => Some(Self::Unit),
136 _ => None,
137 }
138 }
139}
140
141#[derive(Clone, Copy, Debug, Eq, PartialEq)]
146pub enum TextMode {
147 Cs, Ci, }
150
151#[derive(Clone, Eq, PartialEq)]
166pub enum Value {
167 Account(Account),
168 Blob(Vec<u8>),
169 Bool(bool),
170 Date(Date),
171 Decimal(Decimal),
172 Duration(Duration),
173 Enum(ValueEnum),
174 Float32(Float32),
175 Float64(Float64),
176 Int64(i64),
177 Int128(i128),
178 IntBig(IntBig),
179 List(Vec<Self>),
183 Map(Vec<(Self, Self)>),
190 Null,
191 Principal(Principal),
192 Subaccount(Subaccount),
193 Text(String),
194 Timestamp(Timestamp),
195 Nat64(u64),
196 Nat128(u128),
197 NatBig(NatBig),
198 Ulid(Ulid),
199 Unit,
200}
201
202impl fmt::Debug for Value {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 match self {
205 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
206 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
207 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
208 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
209 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
210 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
211 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
212 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
213 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
214 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
215 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
216 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
217 Self::List(value) => f.debug_tuple("List").field(value).finish(),
218 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
219 Self::Null => f.write_str("Null"),
220 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
221 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
222 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
223 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
224 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
225 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
226 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
227 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
228 Self::Unit => f.write_str("Unit"),
229 }
230 }
231}
232
233impl Value {
234 pub fn from_slice<T>(items: &[T]) -> Self
243 where
244 T: Into<Self> + Clone,
245 {
246 Self::List(items.iter().cloned().map(Into::into).collect())
247 }
248
249 pub fn from_list<T>(items: Vec<T>) -> Self
253 where
254 T: Into<Self>,
255 {
256 Self::List(items.into_iter().map(Into::into).collect())
257 }
258
259 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
267 let normalized = map::normalize_map_entries(entries)?;
268 Ok(Self::Map(normalized))
269 }
270
271 #[must_use]
277 pub const fn is_text(&self) -> bool {
278 matches!(self, Self::Text(_))
279 }
280
281 #[must_use]
283 pub const fn is_unit(&self) -> bool {
284 matches!(self, Self::Unit)
285 }
286
287 #[must_use]
288 pub const fn is_scalar(&self) -> bool {
289 match self {
290 Self::List(_) | Self::Map(_) | Self::Unit => false,
292 _ => true,
293 }
294 }
295
296 #[must_use]
298 pub(crate) fn contains_enum(&self) -> bool {
299 match self {
300 Self::Enum(_) => true,
301 Self::List(values) => values.iter().any(Self::contains_enum),
302 Self::Map(entries) => entries
303 .iter()
304 .any(|(key, value)| key.contains_enum() || value.contains_enum()),
305 _ => false,
306 }
307 }
308
309 #[must_use]
311 pub(crate) const fn canonical_tag(&self) -> ValueTag {
312 tag::canonical_tag(self)
313 }
314
315 #[must_use]
317 pub(crate) const fn canonical_rank(&self) -> u8 {
318 rank::canonical_rank(self)
319 }
320
321 #[must_use]
323 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
324 compare::canonical_cmp(left, right)
325 }
326
327 #[must_use]
329 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
330 compare::canonical_cmp_key(left, right)
331 }
332
333 #[must_use]
338 pub const fn as_text(&self) -> Option<&str> {
339 if let Self::Text(s) = self {
340 Some(s.as_str())
341 } else {
342 None
343 }
344 }
345
346 #[must_use]
347 pub const fn as_list(&self) -> Option<&[Self]> {
348 if let Self::List(xs) = self {
349 Some(xs.as_slice())
350 } else {
351 None
352 }
353 }
354
355 #[must_use]
356 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
357 if let Self::Map(entries) = self {
358 Some(entries.as_slice())
359 } else {
360 None
361 }
362 }
363}
364
365impl RuntimeValueMeta for Value {
366 fn kind() -> crate::traits::RuntimeValueKind {
367 crate::traits::RuntimeValueKind::Atomic
368 }
369}
370
371impl RuntimeValueEncode for Value {
372 fn to_value(&self) -> Value {
373 self.clone()
374 }
375}
376
377impl RuntimeValueDecode for Value {
378 fn from_value(value: &Value) -> Option<Self> {
379 Some(value.clone())
380 }
381}
382
383macro_rules! impl_from_for {
384 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
385 $(
386 impl From<$type> for Value {
387 fn from(v: $type) -> Self {
388 Self::$variant(v.into())
389 }
390 }
391 )*
392 };
393}
394
395impl_from_for! {
396 Account => Account,
397 Date => Date,
398 Decimal => Decimal,
399 Duration => Duration,
400 bool => Bool,
401 i8 => Int64,
402 i16 => Int64,
403 i32 => Int64,
404 i64 => Int64,
405 i128 => Int128,
406 IntBig => IntBig,
407 Principal => Principal,
408 Subaccount => Subaccount,
409 &str => Text,
410 String => Text,
411 Timestamp => Timestamp,
412 u8 => Nat64,
413 u16 => Nat64,
414 u32 => Nat64,
415 u64 => Nat64,
416 u128 => Nat128,
417 NatBig => NatBig,
418 Ulid => Ulid,
419}
420
421impl From<Vec<Self>> for Value {
422 fn from(vec: Vec<Self>) -> Self {
423 Self::List(vec)
424 }
425}
426
427impl TryFrom<Vec<(Self, Self)>> for Value {
428 type Error = SchemaInvariantError;
429
430 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
431 Self::from_map(entries).map_err(Self::Error::from)
432 }
433}
434
435impl From<()> for Value {
436 fn from((): ()) -> Self {
437 Self::Unit
438 }
439}
440
441#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
447pub struct ValueEnum(CanonicalEnumValue<Value>);
448
449impl ValueEnum {
450 #[cfg(test)]
451 pub(crate) const fn test_unit(type_id: u32, variant_id: u32) -> 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::Unit,
456 )
457 }
458
459 #[cfg(test)]
460 pub(crate) fn test_payload(type_id: u32, variant_id: u32, payload: Value) -> Self {
461 Self::new(
462 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
463 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
464 CanonicalEnumBody::Payload(Box::new(payload)),
465 )
466 }
467
468 #[cfg(test)]
469 pub(crate) fn test_with_payload(self, payload: Value) -> Self {
470 Self::new(
471 self.type_id(),
472 self.variant_id(),
473 CanonicalEnumBody::Payload(Box::new(payload)),
474 )
475 }
476
477 #[must_use]
478 pub(crate) const fn from_canonical(value: CanonicalEnumValue<Value>) -> Self {
479 Self(value)
480 }
481
482 #[must_use]
483 pub(crate) const fn new(
484 type_id: EnumTypeId,
485 variant_id: EnumVariantId,
486 body: CanonicalEnumBody<Value>,
487 ) -> Self {
488 Self(CanonicalEnumValue::new(type_id, variant_id, body))
489 }
490
491 #[must_use]
492 pub(crate) const fn canonical(&self) -> &CanonicalEnumValue<Value> {
493 &self.0
494 }
495
496 #[must_use]
497 pub(crate) const fn type_id(&self) -> EnumTypeId {
498 self.0.type_id()
499 }
500
501 #[must_use]
502 pub(crate) const fn variant_id(&self) -> EnumVariantId {
503 self.0.variant_id()
504 }
505
506 #[must_use]
507 pub(crate) const fn body(&self) -> &CanonicalEnumBody<Value> {
508 self.0.body()
509 }
510
511 #[must_use]
512 pub(crate) fn payload(&self) -> Option<&Value> {
513 match self.body() {
514 CanonicalEnumBody::Unit => None,
515 CanonicalEnumBody::Payload(payload) => Some(payload.as_ref()),
516 }
517 }
518}
519
520impl<'de> Deserialize<'de> for ValueEnum {
521 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
522 where
523 D: Deserializer<'de>,
524 {
525 let (type_id, variant_id, payload): (u32, u32, Option<Box<Value>>) =
526 Deserialize::deserialize(deserializer)?;
527 let type_id = EnumTypeId::new(type_id)
528 .ok_or_else(|| de::Error::custom("enum type ID must be non-zero"))?;
529 let variant_id = EnumVariantId::new(variant_id)
530 .ok_or_else(|| de::Error::custom("enum variant ID must be non-zero"))?;
531 let body = payload.map_or(CanonicalEnumBody::Unit, CanonicalEnumBody::Payload);
532 Ok(Self::new(type_id, variant_id, body))
533 }
534}