1mod canonical;
8mod coercion;
9mod compare;
10mod hash;
11mod input;
12pub mod map;
13pub mod ops;
14mod output;
15mod rank;
16pub mod semantics;
17mod storage_key;
18mod storage_key_runtime;
19mod tag;
20mod wire;
21
22#[cfg(test)]
23mod tests;
24
25use crate::{
26 prelude::*,
27 traits::{EnumValue, RuntimeValueDecode, RuntimeValueEncode, RuntimeValueMeta},
28 types::*,
29};
30use candid::CandidType;
31use serde::Deserialize;
32use std::{cmp::Ordering, fmt};
33
34pub(crate) use canonical::canonicalize_value_set;
36pub use coercion::{CoercionFamily, CoercionFamilyExt};
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, InputValueEnum};
41pub use map::{MapValueError, SchemaInvariantError};
42pub use output::{OutputValue, OutputValueEnum};
43pub use storage_key::{StorageKey, StorageKeyDecodeError, StorageKeyEncodeError};
44pub(crate) use storage_key_runtime::{
45 storage_key_as_runtime_value, storage_key_from_runtime_value,
46};
47pub use tag::ValueTag;
48
49pub(crate) const VALUE_WIRE_TYPE_NAME: &str = "Value";
54pub(crate) const VALUE_WIRE_VARIANT_LABELS: &[&str] = &[
55 "Account",
56 "Blob",
57 "Bool",
58 "Date",
59 "Decimal",
60 "Duration",
61 "Enum",
62 "Float32",
63 "Float64",
64 "Int",
65 "Int128",
66 "IntBig",
67 "List",
68 "Map",
69 "Null",
70 "Principal",
71 "Subaccount",
72 "Text",
73 "Timestamp",
74 "Uint",
75 "Uint128",
76 "UintBig",
77 "Ulid",
78 "Unit",
79];
80
81#[derive(Clone, Copy)]
83pub(crate) enum ValueWireVariant {
84 Account,
85 Blob,
86 Bool,
87 Date,
88 Decimal,
89 Duration,
90 Enum,
91 Float32,
92 Float64,
93 Int,
94 Int128,
95 IntBig,
96 List,
97 Map,
98 Null,
99 Principal,
100 Subaccount,
101 Text,
102 Timestamp,
103 Uint,
104 Uint128,
105 UintBig,
106 Ulid,
107 Unit,
108}
109
110impl ValueWireVariant {
111 pub(crate) 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::Int),
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 "Uint" => Some(Self::Uint),
134 "Uint128" => Some(Self::Uint128),
135 "UintBig" => Some(Self::UintBig),
136 "Ulid" => Some(Self::Ulid),
137 "Unit" => Some(Self::Unit),
138 _ => None,
139 }
140 }
141}
142
143#[derive(Clone, Copy, Debug, Eq, PartialEq)]
148pub enum TextMode {
149 Cs, Ci, }
152
153#[derive(CandidType, 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 Int(i64),
179 Int128(Int128),
180 IntBig(Int),
181 List(Vec<Self>),
185 Map(Vec<(Self, Self)>),
192 Null,
193 Principal(Principal),
194 Subaccount(Subaccount),
195 Text(String),
196 Timestamp(Timestamp),
197 Uint(u64),
198 Uint128(Nat128),
199 UintBig(Nat),
200 Ulid(Ulid),
201 Unit,
202}
203
204impl fmt::Debug for Value {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 match self {
207 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
208 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
209 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
210 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
211 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
212 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
213 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
214 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
215 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
216 Self::Int(value) => f.debug_tuple("Int").field(value).finish(),
217 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
218 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
219 Self::List(value) => f.debug_tuple("List").field(value).finish(),
220 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
221 Self::Null => f.write_str("Null"),
222 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
223 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
224 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
225 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
226 Self::Uint(value) => f.debug_tuple("Uint").field(value).finish(),
227 Self::Uint128(value) => f.debug_tuple("Uint128").field(value).finish(),
228 Self::UintBig(value) => f.debug_tuple("UintBig").field(value).finish(),
229 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
230 Self::Unit => f.write_str("Unit"),
231 }
232 }
233}
234
235impl Value {
236 pub fn from_slice<T>(items: &[T]) -> Self
245 where
246 T: Into<Self> + Clone,
247 {
248 Self::List(items.iter().cloned().map(Into::into).collect())
249 }
250
251 pub fn from_list<T>(items: Vec<T>) -> Self
255 where
256 T: Into<Self>,
257 {
258 Self::List(items.into_iter().map(Into::into).collect())
259 }
260
261 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
269 let normalized = map::normalize_map_entries(entries)?;
270 Ok(Self::Map(normalized))
271 }
272
273 pub fn from_enum<E: EnumValue>(value: E) -> Self {
275 Self::Enum(value.to_value_enum())
276 }
277
278 #[must_use]
280 pub fn enum_strict<E: Path>(variant: &str) -> Self {
281 Self::Enum(ValueEnum::strict::<E>(variant))
282 }
283
284 #[must_use]
290 pub const fn is_text(&self) -> bool {
291 matches!(self, Self::Text(_))
292 }
293
294 #[must_use]
296 pub const fn is_unit(&self) -> bool {
297 matches!(self, Self::Unit)
298 }
299
300 #[must_use]
301 pub const fn is_scalar(&self) -> bool {
302 match self {
303 Self::List(_) | Self::Map(_) | Self::Unit => false,
305 _ => true,
306 }
307 }
308
309 #[must_use]
311 pub(crate) const fn canonical_tag(&self) -> ValueTag {
312 tag::canonical_tag(self)
313 }
314
315 #[must_use]
317 pub(crate) const fn canonical_rank(&self) -> u8 {
318 rank::canonical_rank(self)
319 }
320
321 #[must_use]
323 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
324 compare::canonical_cmp(left, right)
325 }
326
327 #[must_use]
329 pub fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
330 compare::canonical_cmp_key(left, right)
331 }
332
333 #[must_use]
342 pub const fn as_storage_key(&self) -> Option<StorageKey> {
343 match self {
344 Self::Account(value) => Some(StorageKey::Account(*value)),
345 Self::Int(value) => Some(StorageKey::Int(*value)),
346 Self::Principal(value) => Some(StorageKey::Principal(*value)),
347 Self::Subaccount(value) => Some(StorageKey::Subaccount(*value)),
348 Self::Timestamp(value) => Some(StorageKey::Timestamp(*value)),
349 Self::Uint(value) => Some(StorageKey::Uint(*value)),
350 Self::Ulid(value) => Some(StorageKey::Ulid(*value)),
351 Self::Unit => Some(StorageKey::Unit),
352 _ => None,
353 }
354 }
355
356 #[must_use]
357 pub const fn as_text(&self) -> Option<&str> {
358 if let Self::Text(s) = self {
359 Some(s.as_str())
360 } else {
361 None
362 }
363 }
364
365 #[must_use]
366 pub const fn as_list(&self) -> Option<&[Self]> {
367 if let Self::List(xs) = self {
368 Some(xs.as_slice())
369 } else {
370 None
371 }
372 }
373
374 #[must_use]
375 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
376 if let Self::Map(entries) = self {
377 Some(entries.as_slice())
378 } else {
379 None
380 }
381 }
382}
383
384impl RuntimeValueMeta for Value {
385 fn kind() -> crate::traits::RuntimeValueKind {
386 crate::traits::RuntimeValueKind::Atomic
387 }
388}
389
390impl RuntimeValueEncode for Value {
391 fn to_value(&self) -> Value {
392 self.clone()
393 }
394}
395
396impl RuntimeValueDecode for Value {
397 fn from_value(value: &Value) -> Option<Self> {
398 Some(value.clone())
399 }
400}
401
402#[macro_export]
403macro_rules! impl_from_for {
404 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
405 $(
406 impl From<$type> for Value {
407 fn from(v: $type) -> Self {
408 Self::$variant(v.into())
409 }
410 }
411 )*
412 };
413}
414
415impl_from_for! {
416 Account => Account,
417 Date => Date,
418 Decimal => Decimal,
419 Duration => Duration,
420 bool => Bool,
421 i8 => Int,
422 i16 => Int,
423 i32 => Int,
424 i64 => Int,
425 i128 => Int128,
426 Int => IntBig,
427 Principal => Principal,
428 Subaccount => Subaccount,
429 &str => Text,
430 String => Text,
431 Timestamp => Timestamp,
432 u8 => Uint,
433 u16 => Uint,
434 u32 => Uint,
435 u64 => Uint,
436 u128 => Uint128,
437 Nat => UintBig,
438 Ulid => Ulid,
439}
440
441impl From<Vec<Self>> for Value {
442 fn from(vec: Vec<Self>) -> Self {
443 Self::List(vec)
444 }
445}
446
447impl TryFrom<Vec<(Self, Self)>> for Value {
448 type Error = SchemaInvariantError;
449
450 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
451 Self::from_map(entries).map_err(Self::Error::from)
452 }
453}
454
455impl From<()> for Value {
456 fn from((): ()) -> Self {
457 Self::Unit
458 }
459}
460
461#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, PartialOrd)]
467pub struct ValueEnum {
468 variant: String,
469 path: Option<String>,
470 payload: Option<Box<Value>>,
471}
472
473impl ValueEnum {
474 #[must_use]
476 pub fn new(variant: &str, path: Option<&str>) -> Self {
477 Self {
478 variant: variant.to_string(),
479 path: path.map(ToString::to_string),
480 payload: None,
481 }
482 }
483
484 #[must_use]
486 pub fn strict<E: Path>(variant: &str) -> Self {
487 Self::new(variant, Some(E::PATH))
488 }
489
490 #[must_use]
492 pub fn from_enum<E: EnumValue>(value: E) -> Self {
493 value.to_value_enum()
494 }
495
496 #[must_use]
499 pub fn loose(variant: &str) -> Self {
500 Self::new(variant, None)
501 }
502
503 #[must_use]
505 pub fn with_payload(mut self, payload: Value) -> Self {
506 self.payload = Some(Box::new(payload));
507 self
508 }
509
510 #[must_use]
511 pub fn variant(&self) -> &str {
512 &self.variant
513 }
514
515 #[must_use]
516 pub fn path(&self) -> Option<&str> {
517 self.path.as_deref()
518 }
519
520 #[must_use]
521 pub fn payload(&self) -> Option<&Value> {
522 self.payload.as_deref()
523 }
524
525 pub(crate) fn set_path(&mut self, path: Option<String>) {
526 self.path = path;
527 }
528}