1mod canonical;
12mod coercion;
13mod compare;
14mod hash;
15mod input;
16mod map;
17pub(crate) mod ops;
18mod output;
19mod rank;
20mod semantics;
21mod tag;
22mod wire;
23
24#[cfg(test)]
25mod tests;
26
27use crate::{
28 prelude::*,
29 traits::{EnumValue, RuntimeValueDecode, RuntimeValueEncode, RuntimeValueMeta},
30 types::*,
31};
32use candid::CandidType;
33use serde::Deserialize;
34use std::{cmp::Ordering, fmt};
35
36pub(crate) use canonical::canonicalize_value_set;
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};
45pub use tag::ValueTag;
46
47pub(crate) const VALUE_WIRE_TYPE_NAME: &str = "Value";
52pub(crate) const 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)]
81pub(crate) enum 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 pub(crate) 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(CandidType, 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 pub fn from_enum<E: EnumValue>(value: E) -> Self {
273 Self::Enum(value.to_value_enum())
274 }
275
276 #[must_use]
278 pub fn enum_strict<E: Path>(variant: &str) -> Self {
279 Self::Enum(ValueEnum::strict::<E>(variant))
280 }
281
282 #[must_use]
288 pub const fn is_text(&self) -> bool {
289 matches!(self, Self::Text(_))
290 }
291
292 #[must_use]
294 pub const fn is_unit(&self) -> bool {
295 matches!(self, Self::Unit)
296 }
297
298 #[must_use]
299 pub const fn is_scalar(&self) -> bool {
300 match self {
301 Self::List(_) | Self::Map(_) | Self::Unit => false,
303 _ => true,
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
363impl RuntimeValueMeta for Value {
364 fn kind() -> crate::traits::RuntimeValueKind {
365 crate::traits::RuntimeValueKind::Atomic
366 }
367}
368
369impl RuntimeValueEncode for Value {
370 fn to_value(&self) -> Value {
371 self.clone()
372 }
373}
374
375impl RuntimeValueDecode for Value {
376 fn from_value(value: &Value) -> Option<Self> {
377 Some(value.clone())
378 }
379}
380
381macro_rules! impl_from_for {
382 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
383 $(
384 impl From<$type> for Value {
385 fn from(v: $type) -> Self {
386 Self::$variant(v.into())
387 }
388 }
389 )*
390 };
391}
392
393impl_from_for! {
394 Account => Account,
395 Date => Date,
396 Decimal => Decimal,
397 Duration => Duration,
398 bool => Bool,
399 i8 => Int64,
400 i16 => Int64,
401 i32 => Int64,
402 i64 => Int64,
403 i128 => Int128,
404 IntBig => IntBig,
405 Principal => Principal,
406 Subaccount => Subaccount,
407 &str => Text,
408 String => Text,
409 Timestamp => Timestamp,
410 u8 => Nat64,
411 u16 => Nat64,
412 u32 => Nat64,
413 u64 => Nat64,
414 u128 => Nat128,
415 NatBig => NatBig,
416 Ulid => Ulid,
417}
418
419impl From<Vec<Self>> for Value {
420 fn from(vec: Vec<Self>) -> Self {
421 Self::List(vec)
422 }
423}
424
425impl TryFrom<Vec<(Self, Self)>> for Value {
426 type Error = SchemaInvariantError;
427
428 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
429 Self::from_map(entries).map_err(Self::Error::from)
430 }
431}
432
433impl From<()> for Value {
434 fn from((): ()) -> Self {
435 Self::Unit
436 }
437}
438
439#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, PartialOrd)]
445pub struct ValueEnum {
446 variant: String,
447 path: Option<String>,
448 payload: Option<Box<Value>>,
449}
450
451impl ValueEnum {
452 #[must_use]
454 pub fn new(variant: &str, path: Option<&str>) -> Self {
455 Self {
456 variant: variant.to_string(),
457 path: path.map(ToString::to_string),
458 payload: None,
459 }
460 }
461
462 #[must_use]
464 pub fn strict<E: Path>(variant: &str) -> Self {
465 Self::new(variant, Some(E::PATH))
466 }
467
468 #[must_use]
470 pub fn from_enum<E: EnumValue>(value: E) -> Self {
471 value.to_value_enum()
472 }
473
474 #[must_use]
477 pub fn loose(variant: &str) -> Self {
478 Self::new(variant, None)
479 }
480
481 #[must_use]
483 pub fn with_payload(mut self, payload: Value) -> Self {
484 self.payload = Some(Box::new(payload));
485 self
486 }
487
488 #[must_use]
489 pub fn variant(&self) -> &str {
490 &self.variant
491 }
492
493 #[must_use]
494 pub fn path(&self) -> Option<&str> {
495 self.path.as_deref()
496 }
497
498 #[must_use]
499 pub fn payload(&self) -> Option<&Value> {
500 self.payload.as_deref()
501 }
502
503 pub(crate) fn set_path(&mut self, path: Option<String>) {
504 self.path = path;
505 }
506}