1mod canonical;
12mod canonical_enum;
13mod cleanup;
14mod coercion;
15mod compare;
16#[macro_use]
17mod constructors;
18pub(crate) mod format;
19mod hash;
20mod input;
21mod map;
22pub(crate) mod ops;
23mod output;
24mod public;
25mod rank;
26mod semantics;
27mod tag;
28mod wire;
29
30#[cfg(test)]
31mod tests;
32
33use crate::types::*;
34use serde::{Deserialize, Deserializer, de};
35use std::{cmp::Ordering, fmt};
36
37pub(crate) use canonical::{canonicalize_value_set, value_set_is_strictly_canonical};
39pub(crate) use canonical_enum::{CanonicalEnumBody, CanonicalEnumValue, EnumTypeId, EnumVariantId};
40pub(crate) use cleanup::clear_value;
41pub use coercion::CoercionFamily;
42pub(crate) use hash::{
43 ValueHashWriter, fingerprint_value, hash_single_list_identity_canonical_value, hash_value,
44};
45#[cfg(test)]
46pub(crate) use hash::{test_hash_budget_error, with_test_hash_override};
47pub use input::InputValue;
48pub use map::{MapValueError, SchemaInvariantError};
49pub(crate) use ops::{
50 casefold_text, lower_text, lower_text_construction_allowance, upper_text,
51 upper_text_construction_allowance,
52};
53pub use output::{OutputValue, render_output_value_text};
54pub use public::{PublicEnumValue, PublicValue};
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 "List",
75 "Map",
76 "Null",
77 "Principal",
78 "Subaccount",
79 "Text",
80 "Timestamp",
81 "Nat",
82 "Nat128",
83 "Ulid",
84 "Unit",
85 "U256",
86];
87
88#[derive(Clone, Copy)]
90enum ValueWireVariant {
91 Account,
92 Blob,
93 Bool,
94 Date,
95 Decimal,
96 Duration,
97 Enum,
98 Float32,
99 Float64,
100 Int64,
101 Int128,
102 List,
103 Map,
104 Null,
105 Principal,
106 Subaccount,
107 Text,
108 Timestamp,
109 Nat64,
110 Nat128,
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 "List" => Some(Self::List),
132 "Map" => Some(Self::Map),
133 "Null" => Some(Self::Null),
134 "Principal" => Some(Self::Principal),
135 "Subaccount" => Some(Self::Subaccount),
136 "Text" => Some(Self::Text),
137 "Timestamp" => Some(Self::Timestamp),
138 "Nat" => Some(Self::Nat64),
139 "Nat128" => Some(Self::Nat128),
140 "Ulid" => Some(Self::Ulid),
141 "Unit" => Some(Self::Unit),
142 "U256" => Some(Self::U256),
143 _ => None,
144 }
145 }
146}
147
148#[derive(Clone, Copy, Debug, Eq, PartialEq)]
153pub enum TextMode {
154 Cs, Ci, }
157
158#[derive(Clone, Eq, PartialEq)]
172pub enum Value {
173 Account(Account),
174 Blob(Vec<u8>),
175 Bool(bool),
176 Date(Date),
177 Decimal(Decimal),
178 Duration(Duration),
179 Enum(ValueEnum),
180 Float32(Float32),
181 Float64(Float64),
182 Int64(i64),
183 Int128(i128),
184 List(Vec<Self>),
188 Map(Vec<(Self, Self)>),
195 Null,
196 Principal(Principal),
197 Subaccount(Subaccount),
198 Text(String),
199 Timestamp(Timestamp),
200 Nat64(u64),
201 Nat128(u128),
202 Ulid(Ulid),
203 Unit,
204 U256(U256),
205}
206
207impl fmt::Debug for Value {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 match self {
210 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
211 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
212 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
213 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
214 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
215 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
216 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
217 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
218 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
219 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
220 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
221 Self::List(value) => f.debug_tuple("List").field(value).finish(),
222 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
223 Self::Null => f.write_str("Null"),
224 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
225 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
226 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
227 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
228 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
229 Self::Nat128(value) => f.debug_tuple("Nat128").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) const fn canonical_tag(&self) -> ValueTag {
297 tag::canonical_tag(self)
298 }
299
300 #[must_use]
302 pub(crate) const fn canonical_rank(&self) -> u8 {
303 rank::canonical_rank(self)
304 }
305
306 #[must_use]
308 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
309 compare::canonical_cmp(left, right)
310 }
311
312 #[must_use]
314 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
315 compare::canonical_cmp_key(left, right)
316 }
317
318 #[must_use]
323 pub const fn as_text(&self) -> Option<&str> {
324 if let Self::Text(s) = self {
325 Some(s.as_str())
326 } else {
327 None
328 }
329 }
330
331 #[must_use]
332 pub const fn as_list(&self) -> Option<&[Self]> {
333 if let Self::List(xs) = self {
334 Some(xs.as_slice())
335 } else {
336 None
337 }
338 }
339
340 #[must_use]
341 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
342 if let Self::Map(entries) = self {
343 Some(entries.as_slice())
344 } else {
345 None
346 }
347 }
348}
349
350macro_rules! impl_from_for {
351 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
352 $(
353 impl From<$type> for Value {
354 fn from(v: $type) -> Self {
355 Self::$variant(v.into())
356 }
357 }
358 )*
359 };
360}
361
362impl_from_for! {
363 Account => Account,
364 Date => Date,
365 Decimal => Decimal,
366 Duration => Duration,
367 bool => Bool,
368 i8 => Int64,
369 i16 => Int64,
370 i32 => Int64,
371 i64 => Int64,
372 i128 => Int128,
373 Principal => Principal,
374 Subaccount => Subaccount,
375 &str => Text,
376 String => Text,
377 Timestamp => Timestamp,
378 u8 => Nat64,
379 u16 => Nat64,
380 u32 => Nat64,
381 u64 => Nat64,
382 u128 => Nat128,
383 Ulid => Ulid,
384 U256 => U256,
385}
386
387impl From<Vec<Self>> for Value {
388 fn from(vec: Vec<Self>) -> Self {
389 Self::List(vec)
390 }
391}
392
393impl TryFrom<Vec<(Self, Self)>> for Value {
394 type Error = SchemaInvariantError;
395
396 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
397 Self::from_map(entries).map_err(Self::Error::from)
398 }
399}
400
401impl From<()> for Value {
402 fn from((): ()) -> Self {
403 Self::Unit
404 }
405}
406
407#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
413pub struct ValueEnum(CanonicalEnumValue<Value>);
414
415impl ValueEnum {
416 #[cfg(test)]
417 pub(crate) const fn test_unit(type_id: u32, variant_id: u32) -> Self {
418 Self::new(
419 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
420 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
421 CanonicalEnumBody::Unit,
422 )
423 }
424
425 #[cfg(test)]
426 pub(crate) fn test_payload(type_id: u32, variant_id: u32, payload: Value) -> Self {
427 Self::new(
428 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
429 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
430 CanonicalEnumBody::Payload(Box::new(payload)),
431 )
432 }
433
434 #[cfg(test)]
435 pub(crate) fn test_with_payload(self, payload: Value) -> Self {
436 Self::new(
437 self.type_id(),
438 self.variant_id(),
439 CanonicalEnumBody::Payload(Box::new(payload)),
440 )
441 }
442
443 #[must_use]
444 pub(crate) const fn from_canonical(value: CanonicalEnumValue<Value>) -> Self {
445 Self(value)
446 }
447
448 #[must_use]
449 pub(crate) const fn new(
450 type_id: EnumTypeId,
451 variant_id: EnumVariantId,
452 body: CanonicalEnumBody<Value>,
453 ) -> Self {
454 Self(CanonicalEnumValue::new(type_id, variant_id, body))
455 }
456
457 #[must_use]
458 pub(crate) const fn canonical(&self) -> &CanonicalEnumValue<Value> {
459 &self.0
460 }
461
462 #[must_use]
463 pub(crate) const fn type_id(&self) -> EnumTypeId {
464 self.0.type_id()
465 }
466
467 #[must_use]
468 pub(crate) const fn variant_id(&self) -> EnumVariantId {
469 self.0.variant_id()
470 }
471
472 #[must_use]
473 pub(crate) const fn body(&self) -> &CanonicalEnumBody<Value> {
474 self.0.body()
475 }
476
477 #[must_use]
479 pub(crate) fn into_body(self) -> CanonicalEnumBody<Value> {
480 self.0.into_body()
481 }
482
483 #[must_use]
484 pub(crate) fn payload(&self) -> Option<&Value> {
485 match self.body() {
486 CanonicalEnumBody::Unit => None,
487 CanonicalEnumBody::Payload(payload) => Some(payload.as_ref()),
488 }
489 }
490}
491
492impl<'de> Deserialize<'de> for ValueEnum {
493 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
494 where
495 D: Deserializer<'de>,
496 {
497 let (type_id, variant_id, payload): (u32, u32, Option<Box<Value>>) =
498 Deserialize::deserialize(deserializer)?;
499 let type_id = EnumTypeId::new(type_id)
500 .ok_or_else(|| de::Error::custom("enum type ID must be non-zero"))?;
501 let variant_id = EnumVariantId::new(variant_id)
502 .ok_or_else(|| de::Error::custom("enum variant ID must be non-zero"))?;
503 let body = payload.map_or(CanonicalEnumBody::Unit, CanonicalEnumBody::Payload);
504 Ok(Self::new(type_id, variant_id, body))
505 }
506}
507
508crate::retained::retained_fields!(Value {
510Self::Account(field_0) => [field_0],
511Self::Blob(field_0) => [field_0],
512Self::Bool(field_0) => [field_0],
513Self::Date(field_0) => [field_0],
514Self::Decimal(field_0) => [field_0],
515Self::Duration(field_0) => [field_0],
516Self::Enum(field_0) => [field_0],
517Self::Float32(field_0) => [field_0],
518Self::Float64(field_0) => [field_0],
519Self::Int64(field_0) => [field_0],
520Self::Int128(field_0) => [field_0],
521Self::List(field_0) => [field_0],
522Self::Map(field_0) => [field_0],
523Self::Null => [],
524Self::Principal(field_0) => [field_0],
525Self::Subaccount(field_0) => [field_0],
526Self::Text(field_0) => [field_0],
527Self::Timestamp(field_0) => [field_0],
528Self::Nat64(field_0) => [field_0],
529Self::Nat128(field_0) => [field_0],
530Self::Ulid(field_0) => [field_0],
531Self::Unit => [],
532Self::U256(field_0) => [field_0],
533});
534crate::retained::retained_fields!(ValueEnum {
535Self(field_0) => [field_0],
536});