1mod canonical;
12mod coercion;
13mod compare;
14mod hash;
15mod input;
16mod map;
17pub(crate) mod ops;
18mod output;
19mod rank;
20mod semantics;
21mod storage_key;
22mod storage_key_runtime;
23mod tag;
24mod wire;
25
26#[cfg(test)]
27mod tests;
28
29use crate::{
30 prelude::*,
31 traits::{EnumValue, RuntimeValueDecode, RuntimeValueEncode, RuntimeValueMeta},
32 types::*,
33};
34use candid::CandidType;
35use serde::Deserialize;
36use std::{cmp::Ordering, fmt};
37
38pub(crate) use canonical::canonicalize_value_set;
40pub use coercion::{CoercionFamily, CoercionFamilyExt};
41#[cfg(test)]
42pub(crate) use hash::with_test_hash_override;
43pub(crate) use hash::{ValueHashWriter, hash_single_list_identity_canonical_value, hash_value};
44pub use input::{InputValue, InputValueEnum};
45pub use map::{MapValueError, SchemaInvariantError};
46pub use output::{OutputValue, OutputValueEnum};
47pub use storage_key::{StorageKey, StorageKeyDecodeError, StorageKeyEncodeError};
48pub(crate) use storage_key_runtime::{
49 storage_key_as_runtime_value, storage_key_from_runtime_value,
50};
51pub use tag::ValueTag;
52
53pub(crate) const VALUE_WIRE_TYPE_NAME: &str = "Value";
58pub(crate) const VALUE_WIRE_VARIANT_LABELS: &[&str] = &[
59 "Account",
60 "Blob",
61 "Bool",
62 "Date",
63 "Decimal",
64 "Duration",
65 "Enum",
66 "Float32",
67 "Float64",
68 "Int",
69 "Int128",
70 "IntBig",
71 "List",
72 "Map",
73 "Null",
74 "Principal",
75 "Subaccount",
76 "Text",
77 "Timestamp",
78 "Nat",
79 "Nat128",
80 "NatBig",
81 "Ulid",
82 "Unit",
83];
84
85#[derive(Clone, Copy)]
87pub(crate) enum ValueWireVariant {
88 Account,
89 Blob,
90 Bool,
91 Date,
92 Decimal,
93 Duration,
94 Enum,
95 Float32,
96 Float64,
97 Int64,
98 Int128,
99 IntBig,
100 List,
101 Map,
102 Null,
103 Principal,
104 Subaccount,
105 Text,
106 Timestamp,
107 Nat64,
108 Nat128,
109 NatBig,
110 Ulid,
111 Unit,
112}
113
114impl ValueWireVariant {
115 pub(crate) fn from_label(label: &str) -> Option<Self> {
117 match label {
118 "Account" => Some(Self::Account),
119 "Blob" => Some(Self::Blob),
120 "Bool" => Some(Self::Bool),
121 "Date" => Some(Self::Date),
122 "Decimal" => Some(Self::Decimal),
123 "Duration" => Some(Self::Duration),
124 "Enum" => Some(Self::Enum),
125 "Float32" => Some(Self::Float32),
126 "Float64" => Some(Self::Float64),
127 "Int" => Some(Self::Int64),
128 "Int128" => Some(Self::Int128),
129 "IntBig" => Some(Self::IntBig),
130 "List" => Some(Self::List),
131 "Map" => Some(Self::Map),
132 "Null" => Some(Self::Null),
133 "Principal" => Some(Self::Principal),
134 "Subaccount" => Some(Self::Subaccount),
135 "Text" => Some(Self::Text),
136 "Timestamp" => Some(Self::Timestamp),
137 "Nat" => Some(Self::Nat64),
138 "Nat128" => Some(Self::Nat128),
139 "NatBig" => Some(Self::NatBig),
140 "Ulid" => Some(Self::Ulid),
141 "Unit" => Some(Self::Unit),
142 _ => None,
143 }
144 }
145}
146
147#[derive(Clone, Copy, Debug, Eq, PartialEq)]
152pub enum TextMode {
153 Cs, Ci, }
156
157#[derive(CandidType, 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 IntBig(IntBig),
185 List(Vec<Self>),
189 Map(Vec<(Self, Self)>),
196 Null,
197 Principal(Principal),
198 Subaccount(Subaccount),
199 Text(String),
200 Timestamp(Timestamp),
201 Nat64(u64),
202 Nat128(u128),
203 NatBig(NatBig),
204 Ulid(Ulid),
205 Unit,
206}
207
208impl fmt::Debug for Value {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match self {
211 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
212 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
213 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
214 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
215 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
216 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
217 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
218 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
219 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
220 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
221 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
222 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
223 Self::List(value) => f.debug_tuple("List").field(value).finish(),
224 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
225 Self::Null => f.write_str("Null"),
226 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
227 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
228 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
229 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
230 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
231 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
232 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
233 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
234 Self::Unit => f.write_str("Unit"),
235 }
236 }
237}
238
239impl Value {
240 pub fn from_slice<T>(items: &[T]) -> Self
249 where
250 T: Into<Self> + Clone,
251 {
252 Self::List(items.iter().cloned().map(Into::into).collect())
253 }
254
255 pub fn from_list<T>(items: Vec<T>) -> Self
259 where
260 T: Into<Self>,
261 {
262 Self::List(items.into_iter().map(Into::into).collect())
263 }
264
265 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
273 let normalized = map::normalize_map_entries(entries)?;
274 Ok(Self::Map(normalized))
275 }
276
277 pub fn from_enum<E: EnumValue>(value: E) -> Self {
279 Self::Enum(value.to_value_enum())
280 }
281
282 #[must_use]
284 pub fn enum_strict<E: Path>(variant: &str) -> Self {
285 Self::Enum(ValueEnum::strict::<E>(variant))
286 }
287
288 #[must_use]
294 pub const fn is_text(&self) -> bool {
295 matches!(self, Self::Text(_))
296 }
297
298 #[must_use]
300 pub const fn is_unit(&self) -> bool {
301 matches!(self, Self::Unit)
302 }
303
304 #[must_use]
305 pub const fn is_scalar(&self) -> bool {
306 match self {
307 Self::List(_) | Self::Map(_) | Self::Unit => false,
309 _ => true,
310 }
311 }
312
313 #[must_use]
315 pub(crate) const fn canonical_tag(&self) -> ValueTag {
316 tag::canonical_tag(self)
317 }
318
319 #[must_use]
321 pub(crate) const fn canonical_rank(&self) -> u8 {
322 rank::canonical_rank(self)
323 }
324
325 #[must_use]
327 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
328 compare::canonical_cmp(left, right)
329 }
330
331 #[must_use]
333 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
334 compare::canonical_cmp_key(left, right)
335 }
336
337 #[must_use]
346 pub(crate) const fn as_primary_key_value(&self) -> Option<StorageKey> {
347 match self {
348 Self::Account(value) => Some(StorageKey::Account(*value)),
349 Self::Int64(value) => Some(StorageKey::Int(*value)),
350 Self::Principal(value) => Some(StorageKey::Principal(*value)),
351 Self::Subaccount(value) => Some(StorageKey::Subaccount(*value)),
352 Self::Timestamp(value) => Some(StorageKey::Timestamp(*value)),
353 Self::Nat64(value) => Some(StorageKey::Nat(*value)),
354 Self::Ulid(value) => Some(StorageKey::Ulid(*value)),
355 Self::Unit => Some(StorageKey::Unit),
356 _ => None,
357 }
358 }
359
360 #[must_use]
361 pub const fn as_text(&self) -> Option<&str> {
362 if let Self::Text(s) = self {
363 Some(s.as_str())
364 } else {
365 None
366 }
367 }
368
369 #[must_use]
370 pub const fn as_list(&self) -> Option<&[Self]> {
371 if let Self::List(xs) = self {
372 Some(xs.as_slice())
373 } else {
374 None
375 }
376 }
377
378 #[must_use]
379 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
380 if let Self::Map(entries) = self {
381 Some(entries.as_slice())
382 } else {
383 None
384 }
385 }
386}
387
388impl RuntimeValueMeta for Value {
389 fn kind() -> crate::traits::RuntimeValueKind {
390 crate::traits::RuntimeValueKind::Atomic
391 }
392}
393
394impl RuntimeValueEncode for Value {
395 fn to_value(&self) -> Value {
396 self.clone()
397 }
398}
399
400impl RuntimeValueDecode for Value {
401 fn from_value(value: &Value) -> Option<Self> {
402 Some(value.clone())
403 }
404}
405
406macro_rules! impl_from_for {
407 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
408 $(
409 impl From<$type> for Value {
410 fn from(v: $type) -> Self {
411 Self::$variant(v.into())
412 }
413 }
414 )*
415 };
416}
417
418impl_from_for! {
419 Account => Account,
420 Date => Date,
421 Decimal => Decimal,
422 Duration => Duration,
423 bool => Bool,
424 i8 => Int64,
425 i16 => Int64,
426 i32 => Int64,
427 i64 => Int64,
428 i128 => Int128,
429 IntBig => IntBig,
430 Principal => Principal,
431 Subaccount => Subaccount,
432 &str => Text,
433 String => Text,
434 Timestamp => Timestamp,
435 u8 => Nat64,
436 u16 => Nat64,
437 u32 => Nat64,
438 u64 => Nat64,
439 u128 => Nat128,
440 NatBig => NatBig,
441 Ulid => Ulid,
442}
443
444impl From<Vec<Self>> for Value {
445 fn from(vec: Vec<Self>) -> Self {
446 Self::List(vec)
447 }
448}
449
450impl TryFrom<Vec<(Self, Self)>> for Value {
451 type Error = SchemaInvariantError;
452
453 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
454 Self::from_map(entries).map_err(Self::Error::from)
455 }
456}
457
458impl From<()> for Value {
459 fn from((): ()) -> Self {
460 Self::Unit
461 }
462}
463
464#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, PartialOrd)]
470pub struct ValueEnum {
471 variant: String,
472 path: Option<String>,
473 payload: Option<Box<Value>>,
474}
475
476impl ValueEnum {
477 #[must_use]
479 pub fn new(variant: &str, path: Option<&str>) -> Self {
480 Self {
481 variant: variant.to_string(),
482 path: path.map(ToString::to_string),
483 payload: None,
484 }
485 }
486
487 #[must_use]
489 pub fn strict<E: Path>(variant: &str) -> Self {
490 Self::new(variant, Some(E::PATH))
491 }
492
493 #[must_use]
495 pub fn from_enum<E: EnumValue>(value: E) -> Self {
496 value.to_value_enum()
497 }
498
499 #[must_use]
502 pub fn loose(variant: &str) -> Self {
503 Self::new(variant, None)
504 }
505
506 #[must_use]
508 pub fn with_payload(mut self, payload: Value) -> Self {
509 self.payload = Some(Box::new(payload));
510 self
511 }
512
513 #[must_use]
514 pub fn variant(&self) -> &str {
515 &self.variant
516 }
517
518 #[must_use]
519 pub fn path(&self) -> Option<&str> {
520 self.path.as_deref()
521 }
522
523 #[must_use]
524 pub fn payload(&self) -> Option<&Value> {
525 self.payload.as_deref()
526 }
527
528 pub(crate) fn set_path(&mut self, path: Option<String>) {
529 self.path = path;
530 }
531}