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