1mod canonical;
12mod canonical_enum;
13mod cleanup;
14mod coercion;
15mod compare;
16pub(crate) mod format;
17mod hash;
18mod input;
19mod map;
20pub(crate) mod ops;
21mod output;
22mod public;
23mod rank;
24mod semantics;
25mod tag;
26mod wire;
27
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, value_set_is_strictly_canonical};
37pub(crate) use canonical_enum::{CanonicalEnumBody, CanonicalEnumValue, EnumTypeId, EnumVariantId};
38pub(crate) use cleanup::clear_value;
39pub use coercion::CoercionFamily;
40pub(crate) use hash::{
41 ValueHashWriter, fingerprint_value, hash_single_list_identity_canonical_value, hash_value,
42};
43#[cfg(test)]
44pub(crate) use hash::{test_hash_budget_error, with_test_hash_override};
45pub use input::InputValue;
46pub use map::{MapValueError, SchemaInvariantError};
47pub(crate) use ops::{casefold_text, lower_text, lower_text_construction_allowance, upper_text};
48pub use output::{OutputValue, render_output_value_text};
49pub use public::{PublicEnumValue, PublicValue};
50pub use tag::ValueTag;
51
52const VALUE_WIRE_TYPE_NAME: &str = "Value";
57const VALUE_WIRE_VARIANT_LABELS: &[&str] = &[
58 "Account",
59 "Blob",
60 "Bool",
61 "Date",
62 "Decimal",
63 "Duration",
64 "Enum",
65 "Float32",
66 "Float64",
67 "Int",
68 "Int128",
69 "List",
70 "Map",
71 "Null",
72 "Principal",
73 "Subaccount",
74 "Text",
75 "Timestamp",
76 "Nat",
77 "Nat128",
78 "Ulid",
79 "Unit",
80 "U256",
81];
82
83#[derive(Clone, Copy)]
85enum ValueWireVariant {
86 Account,
87 Blob,
88 Bool,
89 Date,
90 Decimal,
91 Duration,
92 Enum,
93 Float32,
94 Float64,
95 Int64,
96 Int128,
97 List,
98 Map,
99 Null,
100 Principal,
101 Subaccount,
102 Text,
103 Timestamp,
104 Nat64,
105 Nat128,
106 Ulid,
107 Unit,
108 U256,
109}
110
111impl ValueWireVariant {
112 fn from_label(label: &str) -> Option<Self> {
114 match label {
115 "Account" => Some(Self::Account),
116 "Blob" => Some(Self::Blob),
117 "Bool" => Some(Self::Bool),
118 "Date" => Some(Self::Date),
119 "Decimal" => Some(Self::Decimal),
120 "Duration" => Some(Self::Duration),
121 "Enum" => Some(Self::Enum),
122 "Float32" => Some(Self::Float32),
123 "Float64" => Some(Self::Float64),
124 "Int" => Some(Self::Int64),
125 "Int128" => Some(Self::Int128),
126 "List" => Some(Self::List),
127 "Map" => Some(Self::Map),
128 "Null" => Some(Self::Null),
129 "Principal" => Some(Self::Principal),
130 "Subaccount" => Some(Self::Subaccount),
131 "Text" => Some(Self::Text),
132 "Timestamp" => Some(Self::Timestamp),
133 "Nat" => Some(Self::Nat64),
134 "Nat128" => Some(Self::Nat128),
135 "Ulid" => Some(Self::Ulid),
136 "Unit" => Some(Self::Unit),
137 "U256" => Some(Self::U256),
138 _ => None,
139 }
140 }
141}
142
143#[derive(Clone, Copy, Debug, Eq, PartialEq)]
148pub enum TextMode {
149 Cs, Ci, }
152
153#[derive(Clone, Eq, PartialEq)]
167pub enum Value {
168 Account(Account),
169 Blob(Vec<u8>),
170 Bool(bool),
171 Date(Date),
172 Decimal(Decimal),
173 Duration(Duration),
174 Enum(ValueEnum),
175 Float32(Float32),
176 Float64(Float64),
177 Int64(i64),
178 Int128(i128),
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 Ulid(Ulid),
198 Unit,
199 U256(U256),
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::List(value) => f.debug_tuple("List").field(value).finish(),
217 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
218 Self::Null => f.write_str("Null"),
219 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
220 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
221 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
222 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
223 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
224 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
225 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
226 Self::Unit => f.write_str("Unit"),
227 Self::U256(value) => f.debug_tuple("U256").field(value).finish(),
228 }
229 }
230}
231
232impl Value {
233 pub fn from_slice<T>(items: &[T]) -> Self
242 where
243 T: Into<Self> + Clone,
244 {
245 Self::List(items.iter().cloned().map(Into::into).collect())
246 }
247
248 pub fn from_list<T>(items: Vec<T>) -> Self
252 where
253 T: Into<Self>,
254 {
255 Self::List(items.into_iter().map(Into::into).collect())
256 }
257
258 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
266 let normalized = map::normalize_map_entries(entries)?;
267 Ok(Self::Map(normalized))
268 }
269
270 #[must_use]
276 pub const fn is_text(&self) -> bool {
277 matches!(self, Self::Text(_))
278 }
279
280 #[must_use]
281 pub const fn is_scalar(&self) -> bool {
282 match self {
283 Self::List(_) | Self::Map(_) | Self::Unit => false,
285 _ => true,
286 }
287 }
288
289 #[must_use]
291 pub(crate) const fn canonical_tag(&self) -> ValueTag {
292 tag::canonical_tag(self)
293 }
294
295 #[must_use]
297 pub(crate) const fn canonical_rank(&self) -> u8 {
298 rank::canonical_rank(self)
299 }
300
301 #[must_use]
303 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
304 compare::canonical_cmp(left, right)
305 }
306
307 #[must_use]
309 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
310 compare::canonical_cmp_key(left, right)
311 }
312
313 #[must_use]
318 pub const fn as_text(&self) -> Option<&str> {
319 if let Self::Text(s) = self {
320 Some(s.as_str())
321 } else {
322 None
323 }
324 }
325
326 #[must_use]
327 pub const fn as_list(&self) -> Option<&[Self]> {
328 if let Self::List(xs) = self {
329 Some(xs.as_slice())
330 } else {
331 None
332 }
333 }
334
335 #[must_use]
336 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
337 if let Self::Map(entries) = self {
338 Some(entries.as_slice())
339 } else {
340 None
341 }
342 }
343}
344
345macro_rules! impl_from_for {
346 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
347 $(
348 impl From<$type> for Value {
349 fn from(v: $type) -> Self {
350 Self::$variant(v.into())
351 }
352 }
353 )*
354 };
355}
356
357impl_from_for! {
358 Account => Account,
359 Date => Date,
360 Decimal => Decimal,
361 Duration => Duration,
362 bool => Bool,
363 i8 => Int64,
364 i16 => Int64,
365 i32 => Int64,
366 i64 => Int64,
367 i128 => Int128,
368 Principal => Principal,
369 Subaccount => Subaccount,
370 &str => Text,
371 String => Text,
372 Timestamp => Timestamp,
373 u8 => Nat64,
374 u16 => Nat64,
375 u32 => Nat64,
376 u64 => Nat64,
377 u128 => Nat128,
378 Ulid => Ulid,
379 U256 => U256,
380}
381
382impl From<Vec<Self>> for Value {
383 fn from(vec: Vec<Self>) -> Self {
384 Self::List(vec)
385 }
386}
387
388impl TryFrom<Vec<(Self, Self)>> for Value {
389 type Error = SchemaInvariantError;
390
391 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
392 Self::from_map(entries).map_err(Self::Error::from)
393 }
394}
395
396impl From<()> for Value {
397 fn from((): ()) -> Self {
398 Self::Unit
399 }
400}
401
402#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
408pub struct ValueEnum(CanonicalEnumValue<Value>);
409
410impl ValueEnum {
411 #[cfg(test)]
412 pub(crate) const fn test_unit(type_id: u32, variant_id: u32) -> Self {
413 Self::new(
414 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
415 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
416 CanonicalEnumBody::Unit,
417 )
418 }
419
420 #[cfg(test)]
421 pub(crate) fn test_payload(type_id: u32, variant_id: u32, payload: Value) -> Self {
422 Self::new(
423 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
424 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
425 CanonicalEnumBody::Payload(Box::new(payload)),
426 )
427 }
428
429 #[cfg(test)]
430 pub(crate) fn test_with_payload(self, payload: Value) -> Self {
431 Self::new(
432 self.type_id(),
433 self.variant_id(),
434 CanonicalEnumBody::Payload(Box::new(payload)),
435 )
436 }
437
438 #[must_use]
439 pub(crate) const fn from_canonical(value: CanonicalEnumValue<Value>) -> Self {
440 Self(value)
441 }
442
443 #[must_use]
444 pub(crate) const fn new(
445 type_id: EnumTypeId,
446 variant_id: EnumVariantId,
447 body: CanonicalEnumBody<Value>,
448 ) -> Self {
449 Self(CanonicalEnumValue::new(type_id, variant_id, body))
450 }
451
452 #[must_use]
453 pub(crate) const fn canonical(&self) -> &CanonicalEnumValue<Value> {
454 &self.0
455 }
456
457 #[must_use]
458 pub(crate) const fn type_id(&self) -> EnumTypeId {
459 self.0.type_id()
460 }
461
462 #[must_use]
463 pub(crate) const fn variant_id(&self) -> EnumVariantId {
464 self.0.variant_id()
465 }
466
467 #[must_use]
468 pub(crate) const fn body(&self) -> &CanonicalEnumBody<Value> {
469 self.0.body()
470 }
471
472 #[must_use]
474 pub(crate) fn into_body(self) -> CanonicalEnumBody<Value> {
475 self.0.into_body()
476 }
477
478 #[must_use]
479 pub(crate) fn payload(&self) -> Option<&Value> {
480 match self.body() {
481 CanonicalEnumBody::Unit => None,
482 CanonicalEnumBody::Payload(payload) => Some(payload.as_ref()),
483 }
484 }
485}
486
487impl<'de> Deserialize<'de> for ValueEnum {
488 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
489 where
490 D: Deserializer<'de>,
491 {
492 let (type_id, variant_id, payload): (u32, u32, Option<Box<Value>>) =
493 Deserialize::deserialize(deserializer)?;
494 let type_id = EnumTypeId::new(type_id)
495 .ok_or_else(|| de::Error::custom("enum type ID must be non-zero"))?;
496 let variant_id = EnumVariantId::new(variant_id)
497 .ok_or_else(|| de::Error::custom("enum variant ID must be non-zero"))?;
498 let body = payload.map_or(CanonicalEnumBody::Unit, CanonicalEnumBody::Payload);
499 Ok(Self::new(type_id, variant_id, body))
500 }
501}
502
503crate::retained::retained_fields!(Value {
505Self::Account(field_0) => [field_0],
506Self::Blob(field_0) => [field_0],
507Self::Bool(field_0) => [field_0],
508Self::Date(field_0) => [field_0],
509Self::Decimal(field_0) => [field_0],
510Self::Duration(field_0) => [field_0],
511Self::Enum(field_0) => [field_0],
512Self::Float32(field_0) => [field_0],
513Self::Float64(field_0) => [field_0],
514Self::Int64(field_0) => [field_0],
515Self::Int128(field_0) => [field_0],
516Self::List(field_0) => [field_0],
517Self::Map(field_0) => [field_0],
518Self::Null => [],
519Self::Principal(field_0) => [field_0],
520Self::Subaccount(field_0) => [field_0],
521Self::Text(field_0) => [field_0],
522Self::Timestamp(field_0) => [field_0],
523Self::Nat64(field_0) => [field_0],
524Self::Nat128(field_0) => [field_0],
525Self::Ulid(field_0) => [field_0],
526Self::Unit => [],
527Self::U256(field_0) => [field_0],
528});
529crate::retained::retained_fields!(ValueEnum {
530Self(field_0) => [field_0],
531});