1mod canonical;
12mod canonical_enum;
13mod coercion;
14mod compare;
15#[cfg(any(test, feature = "query"))]
16mod hash;
17mod input;
18mod map;
19pub(crate) mod ops;
20mod output;
21mod rank;
22mod semantics;
23mod tag;
24mod wire;
25
26#[cfg(test)]
27mod tests;
28
29use crate::types::*;
30use serde::{Deserialize, Deserializer, de};
31use std::{cmp::Ordering, fmt};
32
33pub(crate) use canonical::canonicalize_value_set;
35pub(crate) use canonical_enum::{CanonicalEnumBody, CanonicalEnumValue, EnumTypeId, EnumVariantId};
36pub use coercion::CoercionFamily;
37#[cfg(test)]
38pub(crate) use hash::with_test_hash_override;
39#[cfg(any(test, feature = "query"))]
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, render_output_value_text};
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)]
164pub enum Value {
165 Account(Account),
166 Blob(Vec<u8>),
167 Bool(bool),
168 Date(Date),
169 Decimal(Decimal),
170 Duration(Duration),
171 Enum(ValueEnum),
172 Float32(Float32),
173 Float64(Float64),
174 Int64(i64),
175 Int128(i128),
176 IntBig(IntBig),
177 List(Vec<Self>),
181 Map(Vec<(Self, Self)>),
188 Null,
189 Principal(Principal),
190 Subaccount(Subaccount),
191 Text(String),
192 Timestamp(Timestamp),
193 Nat64(u64),
194 Nat128(u128),
195 NatBig(NatBig),
196 Ulid(Ulid),
197 Unit,
198}
199
200impl fmt::Debug for Value {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 match self {
203 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
204 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
205 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
206 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
207 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
208 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
209 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
210 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
211 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
212 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
213 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
214 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
215 Self::List(value) => f.debug_tuple("List").field(value).finish(),
216 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
217 Self::Null => f.write_str("Null"),
218 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
219 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
220 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
221 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
222 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
223 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
224 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
225 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
226 Self::Unit => f.write_str("Unit"),
227 }
228 }
229}
230
231impl Value {
232 pub fn from_slice<T>(items: &[T]) -> Self
241 where
242 T: Into<Self> + Clone,
243 {
244 Self::List(items.iter().cloned().map(Into::into).collect())
245 }
246
247 pub fn from_list<T>(items: Vec<T>) -> Self
251 where
252 T: Into<Self>,
253 {
254 Self::List(items.into_iter().map(Into::into).collect())
255 }
256
257 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
265 let normalized = map::normalize_map_entries(entries)?;
266 Ok(Self::Map(normalized))
267 }
268
269 #[must_use]
275 pub const fn is_text(&self) -> bool {
276 matches!(self, Self::Text(_))
277 }
278
279 #[must_use]
281 pub const fn is_unit(&self) -> bool {
282 matches!(self, Self::Unit)
283 }
284
285 #[must_use]
286 pub const fn is_scalar(&self) -> bool {
287 match self {
288 Self::List(_) | Self::Map(_) | Self::Unit => false,
290 _ => true,
291 }
292 }
293
294 #[must_use]
296 #[cfg(any(test, feature = "query"))]
297 pub(crate) fn contains_enum(&self) -> bool {
298 match self {
299 Self::Enum(_) => true,
300 Self::List(values) => values.iter().any(Self::contains_enum),
301 Self::Map(entries) => entries
302 .iter()
303 .any(|(key, value)| key.contains_enum() || value.contains_enum()),
304 _ => false,
305 }
306 }
307
308 #[must_use]
310 pub(crate) const fn canonical_tag(&self) -> ValueTag {
311 tag::canonical_tag(self)
312 }
313
314 #[must_use]
316 pub(crate) const fn canonical_rank(&self) -> u8 {
317 rank::canonical_rank(self)
318 }
319
320 #[must_use]
322 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
323 compare::canonical_cmp(left, right)
324 }
325
326 #[must_use]
328 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
329 compare::canonical_cmp_key(left, right)
330 }
331
332 #[must_use]
337 pub const fn as_text(&self) -> Option<&str> {
338 if let Self::Text(s) = self {
339 Some(s.as_str())
340 } else {
341 None
342 }
343 }
344
345 #[must_use]
346 pub const fn as_list(&self) -> Option<&[Self]> {
347 if let Self::List(xs) = self {
348 Some(xs.as_slice())
349 } else {
350 None
351 }
352 }
353
354 #[must_use]
355 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
356 if let Self::Map(entries) = self {
357 Some(entries.as_slice())
358 } else {
359 None
360 }
361 }
362}
363
364macro_rules! impl_from_for {
365 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
366 $(
367 impl From<$type> for Value {
368 fn from(v: $type) -> Self {
369 Self::$variant(v.into())
370 }
371 }
372 )*
373 };
374}
375
376impl_from_for! {
377 Account => Account,
378 Date => Date,
379 Decimal => Decimal,
380 Duration => Duration,
381 bool => Bool,
382 i8 => Int64,
383 i16 => Int64,
384 i32 => Int64,
385 i64 => Int64,
386 i128 => Int128,
387 IntBig => IntBig,
388 Principal => Principal,
389 Subaccount => Subaccount,
390 &str => Text,
391 String => Text,
392 Timestamp => Timestamp,
393 u8 => Nat64,
394 u16 => Nat64,
395 u32 => Nat64,
396 u64 => Nat64,
397 u128 => Nat128,
398 NatBig => NatBig,
399 Ulid => Ulid,
400}
401
402impl From<Vec<Self>> for Value {
403 fn from(vec: Vec<Self>) -> Self {
404 Self::List(vec)
405 }
406}
407
408impl TryFrom<Vec<(Self, Self)>> for Value {
409 type Error = SchemaInvariantError;
410
411 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
412 Self::from_map(entries).map_err(Self::Error::from)
413 }
414}
415
416impl From<()> for Value {
417 fn from((): ()) -> Self {
418 Self::Unit
419 }
420}
421
422#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
428pub struct ValueEnum(CanonicalEnumValue<Value>);
429
430impl ValueEnum {
431 #[cfg(test)]
432 pub(crate) const fn test_unit(type_id: u32, variant_id: u32) -> Self {
433 Self::new(
434 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
435 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
436 CanonicalEnumBody::Unit,
437 )
438 }
439
440 #[cfg(test)]
441 pub(crate) fn test_payload(type_id: u32, variant_id: u32, payload: Value) -> Self {
442 Self::new(
443 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
444 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
445 CanonicalEnumBody::Payload(Box::new(payload)),
446 )
447 }
448
449 #[cfg(test)]
450 pub(crate) fn test_with_payload(self, payload: Value) -> Self {
451 Self::new(
452 self.type_id(),
453 self.variant_id(),
454 CanonicalEnumBody::Payload(Box::new(payload)),
455 )
456 }
457
458 #[must_use]
459 pub(crate) const fn from_canonical(value: CanonicalEnumValue<Value>) -> Self {
460 Self(value)
461 }
462
463 #[must_use]
464 pub(crate) const fn new(
465 type_id: EnumTypeId,
466 variant_id: EnumVariantId,
467 body: CanonicalEnumBody<Value>,
468 ) -> Self {
469 Self(CanonicalEnumValue::new(type_id, variant_id, body))
470 }
471
472 #[must_use]
473 pub(crate) const fn canonical(&self) -> &CanonicalEnumValue<Value> {
474 &self.0
475 }
476
477 #[must_use]
478 pub(crate) const fn type_id(&self) -> EnumTypeId {
479 self.0.type_id()
480 }
481
482 #[must_use]
483 pub(crate) const fn variant_id(&self) -> EnumVariantId {
484 self.0.variant_id()
485 }
486
487 #[must_use]
488 pub(crate) const fn body(&self) -> &CanonicalEnumBody<Value> {
489 self.0.body()
490 }
491
492 #[must_use]
493 pub(crate) fn payload(&self) -> Option<&Value> {
494 match self.body() {
495 CanonicalEnumBody::Unit => None,
496 CanonicalEnumBody::Payload(payload) => Some(payload.as_ref()),
497 }
498 }
499}
500
501impl<'de> Deserialize<'de> for ValueEnum {
502 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
503 where
504 D: Deserializer<'de>,
505 {
506 let (type_id, variant_id, payload): (u32, u32, Option<Box<Value>>) =
507 Deserialize::deserialize(deserializer)?;
508 let type_id = EnumTypeId::new(type_id)
509 .ok_or_else(|| de::Error::custom("enum type ID must be non-zero"))?;
510 let variant_id = EnumVariantId::new(variant_id)
511 .ok_or_else(|| de::Error::custom("enum variant ID must be non-zero"))?;
512 let body = payload.map_or(CanonicalEnumBody::Unit, CanonicalEnumBody::Payload);
513 Ok(Self::new(type_id, variant_id, body))
514 }
515}