1mod canonical;
16mod coercion;
17mod compare;
18mod hash;
19mod input;
20mod map;
21pub(crate) mod ops;
22mod output;
23mod rank;
24mod semantics;
25mod storage_key;
26mod storage_key_runtime;
27mod tag;
28mod wire;
29
30#[cfg(test)]
31mod tests;
32
33use crate::{
34 prelude::*,
35 traits::{EnumValue, RuntimeValueDecode, RuntimeValueEncode, RuntimeValueMeta},
36 types::*,
37};
38use candid::CandidType;
39use serde::Deserialize;
40use std::{cmp::Ordering, fmt};
41
42pub(crate) use canonical::canonicalize_value_set;
44pub use coercion::{CoercionFamily, CoercionFamilyExt};
45#[cfg(test)]
46pub(crate) use hash::with_test_hash_override;
47pub(crate) use hash::{ValueHashWriter, hash_single_list_identity_canonical_value, hash_value};
48pub use input::{InputValue, InputValueEnum};
49pub use map::{MapValueError, SchemaInvariantError};
50pub use output::{OutputValue, OutputValueEnum};
51pub use storage_key::{StorageKey, StorageKeyDecodeError, StorageKeyEncodeError};
52pub(crate) use storage_key_runtime::{
53 primary_key_value_as_runtime_value, primary_key_value_from_runtime_value,
54};
55pub use tag::ValueTag;
56
57pub(crate) const VALUE_WIRE_TYPE_NAME: &str = "Value";
62pub(crate) const 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 "IntBig",
75 "List",
76 "Map",
77 "Null",
78 "Principal",
79 "Subaccount",
80 "Text",
81 "Timestamp",
82 "Nat",
83 "Nat128",
84 "NatBig",
85 "Ulid",
86 "Unit",
87];
88
89#[derive(Clone, Copy)]
91pub(crate) enum ValueWireVariant {
92 Account,
93 Blob,
94 Bool,
95 Date,
96 Decimal,
97 Duration,
98 Enum,
99 Float32,
100 Float64,
101 Int,
102 Int128,
103 IntBig,
104 List,
105 Map,
106 Null,
107 Principal,
108 Subaccount,
109 Text,
110 Timestamp,
111 Nat,
112 Nat128,
113 NatBig,
114 Ulid,
115 Unit,
116}
117
118impl ValueWireVariant {
119 pub(crate) fn from_label(label: &str) -> Option<Self> {
121 match label {
122 "Account" => Some(Self::Account),
123 "Blob" => Some(Self::Blob),
124 "Bool" => Some(Self::Bool),
125 "Date" => Some(Self::Date),
126 "Decimal" => Some(Self::Decimal),
127 "Duration" => Some(Self::Duration),
128 "Enum" => Some(Self::Enum),
129 "Float32" => Some(Self::Float32),
130 "Float64" => Some(Self::Float64),
131 "Int" => Some(Self::Int),
132 "Int128" => Some(Self::Int128),
133 "IntBig" => Some(Self::IntBig),
134 "List" => Some(Self::List),
135 "Map" => Some(Self::Map),
136 "Null" => Some(Self::Null),
137 "Principal" => Some(Self::Principal),
138 "Subaccount" => Some(Self::Subaccount),
139 "Text" => Some(Self::Text),
140 "Timestamp" => Some(Self::Timestamp),
141 "Nat" => Some(Self::Nat),
142 "Nat128" => Some(Self::Nat128),
143 "NatBig" => Some(Self::NatBig),
144 "Ulid" => Some(Self::Ulid),
145 "Unit" => Some(Self::Unit),
146 _ => None,
147 }
148 }
149}
150
151#[derive(Clone, Copy, Debug, Eq, PartialEq)]
156pub enum TextMode {
157 Cs, Ci, }
160
161#[derive(CandidType, Clone, Eq, PartialEq)]
176pub enum Value {
177 Account(Account),
178 Blob(Vec<u8>),
179 Bool(bool),
180 Date(Date),
181 Decimal(Decimal),
182 Duration(Duration),
183 Enum(ValueEnum),
184 Float32(Float32),
185 Float64(Float64),
186 Int(i64),
187 Int128(Int128),
188 IntBig(Int),
189 List(Vec<Self>),
193 Map(Vec<(Self, Self)>),
200 Null,
201 Principal(Principal),
202 Subaccount(Subaccount),
203 Text(String),
204 Timestamp(Timestamp),
205 Nat(u64),
206 Nat128(Nat128),
207 NatBig(Nat),
208 Ulid(Ulid),
209 Unit,
210}
211
212impl fmt::Debug for Value {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 match self {
215 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
216 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
217 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
218 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
219 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
220 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
221 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
222 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
223 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
224 Self::Int(value) => f.debug_tuple("Int").field(value).finish(),
225 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
226 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
227 Self::List(value) => f.debug_tuple("List").field(value).finish(),
228 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
229 Self::Null => f.write_str("Null"),
230 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
231 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
232 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
233 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
234 Self::Nat(value) => f.debug_tuple("Nat").field(value).finish(),
235 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
236 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
237 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
238 Self::Unit => f.write_str("Unit"),
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 pub fn from_enum<E: EnumValue>(value: E) -> Self {
283 Self::Enum(value.to_value_enum())
284 }
285
286 #[must_use]
288 pub fn enum_strict<E: Path>(variant: &str) -> Self {
289 Self::Enum(ValueEnum::strict::<E>(variant))
290 }
291
292 #[must_use]
298 pub const fn is_text(&self) -> bool {
299 matches!(self, Self::Text(_))
300 }
301
302 #[must_use]
304 pub const fn is_unit(&self) -> bool {
305 matches!(self, Self::Unit)
306 }
307
308 #[must_use]
309 pub const fn is_scalar(&self) -> bool {
310 match self {
311 Self::List(_) | Self::Map(_) | Self::Unit => false,
313 _ => true,
314 }
315 }
316
317 #[must_use]
319 pub(crate) const fn canonical_tag(&self) -> ValueTag {
320 tag::canonical_tag(self)
321 }
322
323 #[must_use]
325 pub(crate) const fn canonical_rank(&self) -> u8 {
326 rank::canonical_rank(self)
327 }
328
329 #[must_use]
331 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
332 compare::canonical_cmp(left, right)
333 }
334
335 #[must_use]
337 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
338 compare::canonical_cmp_key(left, right)
339 }
340
341 #[must_use]
350 pub(crate) const fn as_primary_key_value(&self) -> Option<StorageKey> {
351 match self {
352 Self::Account(value) => Some(StorageKey::Account(*value)),
353 Self::Int(value) => Some(StorageKey::Int(*value)),
354 Self::Principal(value) => Some(StorageKey::Principal(*value)),
355 Self::Subaccount(value) => Some(StorageKey::Subaccount(*value)),
356 Self::Timestamp(value) => Some(StorageKey::Timestamp(*value)),
357 Self::Nat(value) => Some(StorageKey::Nat(*value)),
358 Self::Ulid(value) => Some(StorageKey::Ulid(*value)),
359 Self::Unit => Some(StorageKey::Unit),
360 _ => None,
361 }
362 }
363
364 #[must_use]
365 pub const fn as_text(&self) -> Option<&str> {
366 if let Self::Text(s) = self {
367 Some(s.as_str())
368 } else {
369 None
370 }
371 }
372
373 #[must_use]
374 pub const fn as_list(&self) -> Option<&[Self]> {
375 if let Self::List(xs) = self {
376 Some(xs.as_slice())
377 } else {
378 None
379 }
380 }
381
382 #[must_use]
383 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
384 if let Self::Map(entries) = self {
385 Some(entries.as_slice())
386 } else {
387 None
388 }
389 }
390}
391
392impl RuntimeValueMeta for Value {
393 fn kind() -> crate::traits::RuntimeValueKind {
394 crate::traits::RuntimeValueKind::Atomic
395 }
396}
397
398impl RuntimeValueEncode for Value {
399 fn to_value(&self) -> Value {
400 self.clone()
401 }
402}
403
404impl RuntimeValueDecode for Value {
405 fn from_value(value: &Value) -> Option<Self> {
406 Some(value.clone())
407 }
408}
409
410macro_rules! impl_from_for {
411 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
412 $(
413 impl From<$type> for Value {
414 fn from(v: $type) -> Self {
415 Self::$variant(v.into())
416 }
417 }
418 )*
419 };
420}
421
422impl_from_for! {
423 Account => Account,
424 Date => Date,
425 Decimal => Decimal,
426 Duration => Duration,
427 bool => Bool,
428 i8 => Int,
429 i16 => Int,
430 i32 => Int,
431 i64 => Int,
432 i128 => Int128,
433 Int => IntBig,
434 Principal => Principal,
435 Subaccount => Subaccount,
436 &str => Text,
437 String => Text,
438 Timestamp => Timestamp,
439 u8 => Nat,
440 u16 => Nat,
441 u32 => Nat,
442 u64 => Nat,
443 u128 => Nat128,
444 Nat => NatBig,
445 Ulid => Ulid,
446}
447
448impl From<Vec<Self>> for Value {
449 fn from(vec: Vec<Self>) -> Self {
450 Self::List(vec)
451 }
452}
453
454impl TryFrom<Vec<(Self, Self)>> for Value {
455 type Error = SchemaInvariantError;
456
457 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
458 Self::from_map(entries).map_err(Self::Error::from)
459 }
460}
461
462impl From<()> for Value {
463 fn from((): ()) -> Self {
464 Self::Unit
465 }
466}
467
468#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, PartialOrd)]
474pub struct ValueEnum {
475 variant: String,
476 path: Option<String>,
477 payload: Option<Box<Value>>,
478}
479
480impl ValueEnum {
481 #[must_use]
483 pub fn new(variant: &str, path: Option<&str>) -> Self {
484 Self {
485 variant: variant.to_string(),
486 path: path.map(ToString::to_string),
487 payload: None,
488 }
489 }
490
491 #[must_use]
493 pub fn strict<E: Path>(variant: &str) -> Self {
494 Self::new(variant, Some(E::PATH))
495 }
496
497 #[must_use]
499 pub fn from_enum<E: EnumValue>(value: E) -> Self {
500 value.to_value_enum()
501 }
502
503 #[must_use]
506 pub fn loose(variant: &str) -> Self {
507 Self::new(variant, None)
508 }
509
510 #[must_use]
512 pub fn with_payload(mut self, payload: Value) -> Self {
513 self.payload = Some(Box::new(payload));
514 self
515 }
516
517 #[must_use]
518 pub fn variant(&self) -> &str {
519 &self.variant
520 }
521
522 #[must_use]
523 pub fn path(&self) -> Option<&str> {
524 self.path.as_deref()
525 }
526
527 #[must_use]
528 pub fn payload(&self) -> Option<&Value> {
529 self.payload.as_deref()
530 }
531
532 pub(crate) fn set_path(&mut self, path: Option<String>) {
533 self.path = path;
534 }
535}