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 serde::Deserialize;
33use std::{cmp::Ordering, fmt};
34
35pub(crate) use canonical::canonicalize_value_set;
37pub use coercion::{CoercionFamily, CoercionFamilyExt};
38#[cfg(test)]
39pub(crate) use hash::with_test_hash_override;
40pub(crate) use hash::{ValueHashWriter, hash_single_list_identity_canonical_value, hash_value};
41pub use input::{InputValue, InputValueEnum};
42pub use map::{MapValueError, SchemaInvariantError};
43pub use output::{OutputValue, OutputValueEnum};
44pub use tag::ValueTag;
45
46const VALUE_WIRE_TYPE_NAME: &str = "Value";
51const VALUE_WIRE_VARIANT_LABELS: &[&str] = &[
52 "Account",
53 "Blob",
54 "Bool",
55 "Date",
56 "Decimal",
57 "Duration",
58 "Enum",
59 "Float32",
60 "Float64",
61 "Int",
62 "Int128",
63 "IntBig",
64 "List",
65 "Map",
66 "Null",
67 "Principal",
68 "Subaccount",
69 "Text",
70 "Timestamp",
71 "Nat",
72 "Nat128",
73 "NatBig",
74 "Ulid",
75 "Unit",
76];
77
78#[derive(Clone, Copy)]
80enum ValueWireVariant {
81 Account,
82 Blob,
83 Bool,
84 Date,
85 Decimal,
86 Duration,
87 Enum,
88 Float32,
89 Float64,
90 Int64,
91 Int128,
92 IntBig,
93 List,
94 Map,
95 Null,
96 Principal,
97 Subaccount,
98 Text,
99 Timestamp,
100 Nat64,
101 Nat128,
102 NatBig,
103 Ulid,
104 Unit,
105}
106
107impl ValueWireVariant {
108 fn from_label(label: &str) -> Option<Self> {
110 match label {
111 "Account" => Some(Self::Account),
112 "Blob" => Some(Self::Blob),
113 "Bool" => Some(Self::Bool),
114 "Date" => Some(Self::Date),
115 "Decimal" => Some(Self::Decimal),
116 "Duration" => Some(Self::Duration),
117 "Enum" => Some(Self::Enum),
118 "Float32" => Some(Self::Float32),
119 "Float64" => Some(Self::Float64),
120 "Int" => Some(Self::Int64),
121 "Int128" => Some(Self::Int128),
122 "IntBig" => Some(Self::IntBig),
123 "List" => Some(Self::List),
124 "Map" => Some(Self::Map),
125 "Null" => Some(Self::Null),
126 "Principal" => Some(Self::Principal),
127 "Subaccount" => Some(Self::Subaccount),
128 "Text" => Some(Self::Text),
129 "Timestamp" => Some(Self::Timestamp),
130 "Nat" => Some(Self::Nat64),
131 "Nat128" => Some(Self::Nat128),
132 "NatBig" => Some(Self::NatBig),
133 "Ulid" => Some(Self::Ulid),
134 "Unit" => Some(Self::Unit),
135 _ => None,
136 }
137 }
138}
139
140#[derive(Clone, Copy, Debug, Eq, PartialEq)]
145pub enum TextMode {
146 Cs, Ci, }
149
150#[derive(Clone, Eq, PartialEq)]
165pub enum Value {
166 Account(Account),
167 Blob(Vec<u8>),
168 Bool(bool),
169 Date(Date),
170 Decimal(Decimal),
171 Duration(Duration),
172 Enum(ValueEnum),
173 Float32(Float32),
174 Float64(Float64),
175 Int64(i64),
176 Int128(i128),
177 IntBig(IntBig),
178 List(Vec<Self>),
182 Map(Vec<(Self, Self)>),
189 Null,
190 Principal(Principal),
191 Subaccount(Subaccount),
192 Text(String),
193 Timestamp(Timestamp),
194 Nat64(u64),
195 Nat128(u128),
196 NatBig(NatBig),
197 Ulid(Ulid),
198 Unit,
199}
200
201impl fmt::Debug for Value {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 match self {
204 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
205 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
206 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
207 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
208 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
209 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
210 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
211 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
212 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
213 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
214 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
215 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
216 Self::List(value) => f.debug_tuple("List").field(value).finish(),
217 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
218 Self::Null => f.write_str("Null"),
219 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
220 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
221 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
222 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
223 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
224 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
225 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
226 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
227 Self::Unit => f.write_str("Unit"),
228 }
229 }
230}
231
232impl Value {
233 pub fn from_slice<T>(items: &[T]) -> Self
242 where
243 T: Into<Self> + Clone,
244 {
245 Self::List(items.iter().cloned().map(Into::into).collect())
246 }
247
248 pub fn from_list<T>(items: Vec<T>) -> Self
252 where
253 T: Into<Self>,
254 {
255 Self::List(items.into_iter().map(Into::into).collect())
256 }
257
258 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
266 let normalized = map::normalize_map_entries(entries)?;
267 Ok(Self::Map(normalized))
268 }
269
270 pub fn from_enum<E: EnumValue>(value: E) -> Self {
272 Self::Enum(value.to_value_enum())
273 }
274
275 #[must_use]
277 pub fn enum_strict<E: Path>(variant: &str) -> Self {
278 Self::Enum(ValueEnum::strict::<E>(variant))
279 }
280
281 #[must_use]
287 pub const fn is_text(&self) -> bool {
288 matches!(self, Self::Text(_))
289 }
290
291 #[must_use]
293 pub const fn is_unit(&self) -> bool {
294 matches!(self, Self::Unit)
295 }
296
297 #[must_use]
298 pub const fn is_scalar(&self) -> bool {
299 match self {
300 Self::List(_) | Self::Map(_) | Self::Unit => false,
302 _ => true,
303 }
304 }
305
306 #[must_use]
308 pub(crate) const fn canonical_tag(&self) -> ValueTag {
309 tag::canonical_tag(self)
310 }
311
312 #[must_use]
314 pub(crate) const fn canonical_rank(&self) -> u8 {
315 rank::canonical_rank(self)
316 }
317
318 #[must_use]
320 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
321 compare::canonical_cmp(left, right)
322 }
323
324 #[must_use]
326 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
327 compare::canonical_cmp_key(left, right)
328 }
329
330 #[must_use]
335 pub const fn as_text(&self) -> Option<&str> {
336 if let Self::Text(s) = self {
337 Some(s.as_str())
338 } else {
339 None
340 }
341 }
342
343 #[must_use]
344 pub const fn as_list(&self) -> Option<&[Self]> {
345 if let Self::List(xs) = self {
346 Some(xs.as_slice())
347 } else {
348 None
349 }
350 }
351
352 #[must_use]
353 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
354 if let Self::Map(entries) = self {
355 Some(entries.as_slice())
356 } else {
357 None
358 }
359 }
360}
361
362impl RuntimeValueMeta for Value {
363 fn kind() -> crate::traits::RuntimeValueKind {
364 crate::traits::RuntimeValueKind::Atomic
365 }
366}
367
368impl RuntimeValueEncode for Value {
369 fn to_value(&self) -> Value {
370 self.clone()
371 }
372}
373
374impl RuntimeValueDecode for Value {
375 fn from_value(value: &Value) -> Option<Self> {
376 Some(value.clone())
377 }
378}
379
380macro_rules! impl_from_for {
381 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
382 $(
383 impl From<$type> for Value {
384 fn from(v: $type) -> Self {
385 Self::$variant(v.into())
386 }
387 }
388 )*
389 };
390}
391
392impl_from_for! {
393 Account => Account,
394 Date => Date,
395 Decimal => Decimal,
396 Duration => Duration,
397 bool => Bool,
398 i8 => Int64,
399 i16 => Int64,
400 i32 => Int64,
401 i64 => Int64,
402 i128 => Int128,
403 IntBig => IntBig,
404 Principal => Principal,
405 Subaccount => Subaccount,
406 &str => Text,
407 String => Text,
408 Timestamp => Timestamp,
409 u8 => Nat64,
410 u16 => Nat64,
411 u32 => Nat64,
412 u64 => Nat64,
413 u128 => Nat128,
414 NatBig => NatBig,
415 Ulid => Ulid,
416}
417
418impl From<Vec<Self>> for Value {
419 fn from(vec: Vec<Self>) -> Self {
420 Self::List(vec)
421 }
422}
423
424impl TryFrom<Vec<(Self, Self)>> for Value {
425 type Error = SchemaInvariantError;
426
427 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
428 Self::from_map(entries).map_err(Self::Error::from)
429 }
430}
431
432impl From<()> for Value {
433 fn from((): ()) -> Self {
434 Self::Unit
435 }
436}
437
438#[derive(Clone, Debug, Deserialize, Eq, PartialEq, PartialOrd)]
444pub struct ValueEnum {
445 variant: String,
446 path: Option<String>,
447 payload: Option<Box<Value>>,
448}
449
450impl ValueEnum {
451 #[must_use]
453 pub fn new(variant: &str, path: Option<&str>) -> Self {
454 Self {
455 variant: variant.to_string(),
456 path: path.map(ToString::to_string),
457 payload: None,
458 }
459 }
460
461 #[must_use]
463 pub fn strict<E: Path>(variant: &str) -> Self {
464 Self::new(variant, Some(E::PATH))
465 }
466
467 #[must_use]
469 pub fn from_enum<E: EnumValue>(value: E) -> Self {
470 value.to_value_enum()
471 }
472
473 #[must_use]
476 pub fn loose(variant: &str) -> Self {
477 Self::new(variant, None)
478 }
479
480 #[must_use]
482 pub fn with_payload(mut self, payload: Value) -> Self {
483 self.payload = Some(Box::new(payload));
484 self
485 }
486
487 #[must_use]
488 pub fn variant(&self) -> &str {
489 &self.variant
490 }
491
492 #[must_use]
493 pub fn path(&self) -> Option<&str> {
494 self.path.as_deref()
495 }
496
497 #[must_use]
498 pub fn payload(&self) -> Option<&Value> {
499 self.payload.as_deref()
500 }
501
502 pub(crate) fn set_path(&mut self, path: Option<String>) {
503 self.path = path;
504 }
505}