1mod canonical;
12mod canonical_enum;
13mod coercion;
14mod compare;
15mod hash;
16mod input;
17mod map;
18pub(crate) mod ops;
19mod output;
20mod public;
21mod rank;
22mod semantics;
23mod tag;
24mod wire;
25
26#[cfg(test)]
27mod tests;
28
29use crate::types::*;
30use serde::{Deserialize, Deserializer, de};
31use std::{cmp::Ordering, fmt};
32
33pub(crate) use canonical::canonicalize_value_set;
35pub(crate) use canonical_enum::{CanonicalEnumBody, CanonicalEnumValue, EnumTypeId, EnumVariantId};
36pub use coercion::CoercionFamily;
37#[cfg(test)]
38pub(crate) use hash::with_test_hash_override;
39pub(crate) use hash::{ValueHashWriter, hash_single_list_identity_canonical_value, hash_value};
40pub use input::InputValue;
41pub use map::{MapValueError, SchemaInvariantError};
42pub(crate) use ops::{casefold_text, lower_text, upper_text};
43pub use output::{OutputValue, render_output_value_text};
44pub use public::{PublicEnumValue, PublicValue};
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 "U256",
78];
79
80#[derive(Clone, Copy)]
82enum ValueWireVariant {
83 Account,
84 Blob,
85 Bool,
86 Date,
87 Decimal,
88 Duration,
89 Enum,
90 Float32,
91 Float64,
92 Int64,
93 Int128,
94 IntBig,
95 List,
96 Map,
97 Null,
98 Principal,
99 Subaccount,
100 Text,
101 Timestamp,
102 Nat64,
103 Nat128,
104 NatBig,
105 Ulid,
106 Unit,
107 U256,
108}
109
110impl ValueWireVariant {
111 fn from_label(label: &str) -> Option<Self> {
113 match label {
114 "Account" => Some(Self::Account),
115 "Blob" => Some(Self::Blob),
116 "Bool" => Some(Self::Bool),
117 "Date" => Some(Self::Date),
118 "Decimal" => Some(Self::Decimal),
119 "Duration" => Some(Self::Duration),
120 "Enum" => Some(Self::Enum),
121 "Float32" => Some(Self::Float32),
122 "Float64" => Some(Self::Float64),
123 "Int" => Some(Self::Int64),
124 "Int128" => Some(Self::Int128),
125 "IntBig" => Some(Self::IntBig),
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 "NatBig" => Some(Self::NatBig),
136 "Ulid" => Some(Self::Ulid),
137 "Unit" => Some(Self::Unit),
138 "U256" => Some(Self::U256),
139 _ => None,
140 }
141 }
142}
143
144#[derive(Clone, Copy, Debug, Eq, PartialEq)]
149pub enum TextMode {
150 Cs, Ci, }
153
154#[derive(Clone, Eq, PartialEq)]
168pub enum Value {
169 Account(Account),
170 Blob(Vec<u8>),
171 Bool(bool),
172 Date(Date),
173 Decimal(Decimal),
174 Duration(Duration),
175 Enum(ValueEnum),
176 Float32(Float32),
177 Float64(Float64),
178 Int64(i64),
179 Int128(i128),
180 IntBig(IntBig),
181 List(Vec<Self>),
185 Map(Vec<(Self, Self)>),
192 Null,
193 Principal(Principal),
194 Subaccount(Subaccount),
195 Text(String),
196 Timestamp(Timestamp),
197 Nat64(u64),
198 Nat128(u128),
199 NatBig(NatBig),
200 Ulid(Ulid),
201 Unit,
202 U256(U256),
203}
204
205impl fmt::Debug for Value {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 match self {
208 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
209 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
210 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
211 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
212 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
213 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
214 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
215 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
216 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
217 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
218 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
219 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
220 Self::List(value) => f.debug_tuple("List").field(value).finish(),
221 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
222 Self::Null => f.write_str("Null"),
223 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
224 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
225 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
226 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
227 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
228 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
229 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
230 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
231 Self::Unit => f.write_str("Unit"),
232 Self::U256(value) => f.debug_tuple("U256").field(value).finish(),
233 }
234 }
235}
236
237impl Value {
238 pub fn from_slice<T>(items: &[T]) -> Self
247 where
248 T: Into<Self> + Clone,
249 {
250 Self::List(items.iter().cloned().map(Into::into).collect())
251 }
252
253 pub fn from_list<T>(items: Vec<T>) -> Self
257 where
258 T: Into<Self>,
259 {
260 Self::List(items.into_iter().map(Into::into).collect())
261 }
262
263 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
271 let normalized = map::normalize_map_entries(entries)?;
272 Ok(Self::Map(normalized))
273 }
274
275 #[must_use]
281 pub const fn is_text(&self) -> bool {
282 matches!(self, Self::Text(_))
283 }
284
285 #[must_use]
286 pub const fn is_scalar(&self) -> bool {
287 match self {
288 Self::List(_) | Self::Map(_) | Self::Unit => false,
290 _ => true,
291 }
292 }
293
294 #[must_use]
296 pub(crate) fn contains_enum(&self) -> bool {
297 match self {
298 Self::Enum(_) => true,
299 Self::List(values) => values.iter().any(Self::contains_enum),
300 Self::Map(entries) => entries
301 .iter()
302 .any(|(key, value)| key.contains_enum() || value.contains_enum()),
303 _ => false,
304 }
305 }
306
307 #[must_use]
309 pub(crate) const fn canonical_tag(&self) -> ValueTag {
310 tag::canonical_tag(self)
311 }
312
313 #[must_use]
315 pub(crate) const fn canonical_rank(&self) -> u8 {
316 rank::canonical_rank(self)
317 }
318
319 #[must_use]
321 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
322 compare::canonical_cmp(left, right)
323 }
324
325 #[must_use]
327 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
328 compare::canonical_cmp_key(left, right)
329 }
330
331 #[must_use]
336 pub const fn as_text(&self) -> Option<&str> {
337 if let Self::Text(s) = self {
338 Some(s.as_str())
339 } else {
340 None
341 }
342 }
343
344 #[must_use]
345 pub const fn as_list(&self) -> Option<&[Self]> {
346 if let Self::List(xs) = self {
347 Some(xs.as_slice())
348 } else {
349 None
350 }
351 }
352
353 #[must_use]
354 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
355 if let Self::Map(entries) = self {
356 Some(entries.as_slice())
357 } else {
358 None
359 }
360 }
361}
362
363macro_rules! impl_from_for {
364 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
365 $(
366 impl From<$type> for Value {
367 fn from(v: $type) -> Self {
368 Self::$variant(v.into())
369 }
370 }
371 )*
372 };
373}
374
375impl_from_for! {
376 Account => Account,
377 Date => Date,
378 Decimal => Decimal,
379 Duration => Duration,
380 bool => Bool,
381 i8 => Int64,
382 i16 => Int64,
383 i32 => Int64,
384 i64 => Int64,
385 i128 => Int128,
386 IntBig => IntBig,
387 Principal => Principal,
388 Subaccount => Subaccount,
389 &str => Text,
390 String => Text,
391 Timestamp => Timestamp,
392 u8 => Nat64,
393 u16 => Nat64,
394 u32 => Nat64,
395 u64 => Nat64,
396 u128 => Nat128,
397 NatBig => NatBig,
398 Ulid => Ulid,
399 U256 => U256,
400}
401
402impl From<Vec<Self>> for Value {
403 fn from(vec: Vec<Self>) -> Self {
404 Self::List(vec)
405 }
406}
407
408impl TryFrom<Vec<(Self, Self)>> for Value {
409 type Error = SchemaInvariantError;
410
411 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
412 Self::from_map(entries).map_err(Self::Error::from)
413 }
414}
415
416impl From<()> for Value {
417 fn from((): ()) -> Self {
418 Self::Unit
419 }
420}
421
422#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
428pub struct ValueEnum(CanonicalEnumValue<Value>);
429
430impl ValueEnum {
431 #[cfg(test)]
432 pub(crate) const fn test_unit(type_id: u32, variant_id: u32) -> Self {
433 Self::new(
434 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
435 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
436 CanonicalEnumBody::Unit,
437 )
438 }
439
440 #[cfg(test)]
441 pub(crate) fn test_payload(type_id: u32, variant_id: u32, payload: Value) -> Self {
442 Self::new(
443 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
444 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
445 CanonicalEnumBody::Payload(Box::new(payload)),
446 )
447 }
448
449 #[cfg(test)]
450 pub(crate) fn test_with_payload(self, payload: Value) -> Self {
451 Self::new(
452 self.type_id(),
453 self.variant_id(),
454 CanonicalEnumBody::Payload(Box::new(payload)),
455 )
456 }
457
458 #[must_use]
459 pub(crate) const fn from_canonical(value: CanonicalEnumValue<Value>) -> Self {
460 Self(value)
461 }
462
463 #[must_use]
464 pub(crate) const fn new(
465 type_id: EnumTypeId,
466 variant_id: EnumVariantId,
467 body: CanonicalEnumBody<Value>,
468 ) -> Self {
469 Self(CanonicalEnumValue::new(type_id, variant_id, body))
470 }
471
472 #[must_use]
473 pub(crate) const fn canonical(&self) -> &CanonicalEnumValue<Value> {
474 &self.0
475 }
476
477 #[must_use]
478 pub(crate) const fn type_id(&self) -> EnumTypeId {
479 self.0.type_id()
480 }
481
482 #[must_use]
483 pub(crate) const fn variant_id(&self) -> EnumVariantId {
484 self.0.variant_id()
485 }
486
487 #[must_use]
488 pub(crate) const fn body(&self) -> &CanonicalEnumBody<Value> {
489 self.0.body()
490 }
491
492 #[must_use]
493 pub(crate) fn payload(&self) -> Option<&Value> {
494 match self.body() {
495 CanonicalEnumBody::Unit => None,
496 CanonicalEnumBody::Payload(payload) => Some(payload.as_ref()),
497 }
498 }
499}
500
501impl<'de> Deserialize<'de> for ValueEnum {
502 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
503 where
504 D: Deserializer<'de>,
505 {
506 let (type_id, variant_id, payload): (u32, u32, Option<Box<Value>>) =
507 Deserialize::deserialize(deserializer)?;
508 let type_id = EnumTypeId::new(type_id)
509 .ok_or_else(|| de::Error::custom("enum type ID must be non-zero"))?;
510 let variant_id = EnumVariantId::new(variant_id)
511 .ok_or_else(|| de::Error::custom("enum variant ID must be non-zero"))?;
512 let body = payload.map_or(CanonicalEnumBody::Unit, CanonicalEnumBody::Payload);
513 Ok(Self::new(type_id, variant_id, body))
514 }
515}