1mod canonical;
12mod canonical_enum;
13mod coercion;
14mod compare;
15mod hash;
16mod input;
17mod map;
18pub(crate) mod ops;
19mod output;
20mod rank;
21mod semantics;
22mod tag;
23mod wire;
24
25#[cfg(test)]
26mod tests;
27
28use crate::types::*;
29use serde::{Deserialize, Deserializer, de};
30use std::{cmp::Ordering, fmt};
31
32pub(crate) use canonical::canonicalize_value_set;
34pub(crate) use canonical_enum::{CanonicalEnumBody, CanonicalEnumValue, EnumTypeId, EnumVariantId};
35pub use coercion::CoercionFamily;
36#[cfg(test)]
37pub(crate) use hash::with_test_hash_override;
38pub(crate) use hash::{ValueHashWriter, hash_single_list_identity_canonical_value, hash_value};
39pub use input::{InputValue, InputValueEnum};
40pub use map::{MapValueError, SchemaInvariantError};
41pub(crate) use ops::{casefold_text, lower_text, upper_text};
42pub use output::{OutputValue, OutputValueEnum, render_output_value_text};
43pub use tag::ValueTag;
44
45const VALUE_WIRE_TYPE_NAME: &str = "Value";
50const VALUE_WIRE_VARIANT_LABELS: &[&str] = &[
51 "Account",
52 "Blob",
53 "Bool",
54 "Date",
55 "Decimal",
56 "Duration",
57 "Enum",
58 "Float32",
59 "Float64",
60 "Int",
61 "Int128",
62 "IntBig",
63 "List",
64 "Map",
65 "Null",
66 "Principal",
67 "Subaccount",
68 "Text",
69 "Timestamp",
70 "Nat",
71 "Nat128",
72 "NatBig",
73 "Ulid",
74 "Unit",
75];
76
77#[derive(Clone, Copy)]
79enum ValueWireVariant {
80 Account,
81 Blob,
82 Bool,
83 Date,
84 Decimal,
85 Duration,
86 Enum,
87 Float32,
88 Float64,
89 Int64,
90 Int128,
91 IntBig,
92 List,
93 Map,
94 Null,
95 Principal,
96 Subaccount,
97 Text,
98 Timestamp,
99 Nat64,
100 Nat128,
101 NatBig,
102 Ulid,
103 Unit,
104}
105
106impl ValueWireVariant {
107 fn from_label(label: &str) -> Option<Self> {
109 match label {
110 "Account" => Some(Self::Account),
111 "Blob" => Some(Self::Blob),
112 "Bool" => Some(Self::Bool),
113 "Date" => Some(Self::Date),
114 "Decimal" => Some(Self::Decimal),
115 "Duration" => Some(Self::Duration),
116 "Enum" => Some(Self::Enum),
117 "Float32" => Some(Self::Float32),
118 "Float64" => Some(Self::Float64),
119 "Int" => Some(Self::Int64),
120 "Int128" => Some(Self::Int128),
121 "IntBig" => Some(Self::IntBig),
122 "List" => Some(Self::List),
123 "Map" => Some(Self::Map),
124 "Null" => Some(Self::Null),
125 "Principal" => Some(Self::Principal),
126 "Subaccount" => Some(Self::Subaccount),
127 "Text" => Some(Self::Text),
128 "Timestamp" => Some(Self::Timestamp),
129 "Nat" => Some(Self::Nat64),
130 "Nat128" => Some(Self::Nat128),
131 "NatBig" => Some(Self::NatBig),
132 "Ulid" => Some(Self::Ulid),
133 "Unit" => Some(Self::Unit),
134 _ => None,
135 }
136 }
137}
138
139#[derive(Clone, Copy, Debug, Eq, PartialEq)]
144pub enum TextMode {
145 Cs, Ci, }
148
149#[derive(Clone, Eq, PartialEq)]
163pub enum Value {
164 Account(Account),
165 Blob(Vec<u8>),
166 Bool(bool),
167 Date(Date),
168 Decimal(Decimal),
169 Duration(Duration),
170 Enum(ValueEnum),
171 Float32(Float32),
172 Float64(Float64),
173 Int64(i64),
174 Int128(i128),
175 IntBig(IntBig),
176 List(Vec<Self>),
180 Map(Vec<(Self, Self)>),
187 Null,
188 Principal(Principal),
189 Subaccount(Subaccount),
190 Text(String),
191 Timestamp(Timestamp),
192 Nat64(u64),
193 Nat128(u128),
194 NatBig(NatBig),
195 Ulid(Ulid),
196 Unit,
197}
198
199impl fmt::Debug for Value {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 match self {
202 Self::Account(value) => f.debug_tuple("Account").field(value).finish(),
203 Self::Blob(value) => write!(f, "Blob({} bytes)", value.len()),
204 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
205 Self::Date(value) => f.debug_tuple("Date").field(value).finish(),
206 Self::Decimal(value) => f.debug_tuple("Decimal").field(value).finish(),
207 Self::Duration(value) => f.debug_tuple("Duration").field(value).finish(),
208 Self::Enum(value) => f.debug_tuple("Enum").field(value).finish(),
209 Self::Float32(value) => f.debug_tuple("Float32").field(value).finish(),
210 Self::Float64(value) => f.debug_tuple("Float64").field(value).finish(),
211 Self::Int64(value) => f.debug_tuple("Int64").field(value).finish(),
212 Self::Int128(value) => f.debug_tuple("Int128").field(value).finish(),
213 Self::IntBig(value) => f.debug_tuple("IntBig").field(value).finish(),
214 Self::List(value) => f.debug_tuple("List").field(value).finish(),
215 Self::Map(value) => f.debug_tuple("Map").field(value).finish(),
216 Self::Null => f.write_str("Null"),
217 Self::Principal(value) => f.debug_tuple("Principal").field(value).finish(),
218 Self::Subaccount(value) => f.debug_tuple("Subaccount").field(value).finish(),
219 Self::Text(value) => f.debug_tuple("Text").field(value).finish(),
220 Self::Timestamp(value) => f.debug_tuple("Timestamp").field(value).finish(),
221 Self::Nat64(value) => f.debug_tuple("Nat64").field(value).finish(),
222 Self::Nat128(value) => f.debug_tuple("Nat128").field(value).finish(),
223 Self::NatBig(value) => f.debug_tuple("NatBig").field(value).finish(),
224 Self::Ulid(value) => f.debug_tuple("Ulid").field(value).finish(),
225 Self::Unit => f.write_str("Unit"),
226 }
227 }
228}
229
230impl Value {
231 pub fn from_slice<T>(items: &[T]) -> Self
240 where
241 T: Into<Self> + Clone,
242 {
243 Self::List(items.iter().cloned().map(Into::into).collect())
244 }
245
246 pub fn from_list<T>(items: Vec<T>) -> Self
250 where
251 T: Into<Self>,
252 {
253 Self::List(items.into_iter().map(Into::into).collect())
254 }
255
256 pub fn from_map(entries: Vec<(Self, Self)>) -> Result<Self, MapValueError> {
264 let normalized = map::normalize_map_entries(entries)?;
265 Ok(Self::Map(normalized))
266 }
267
268 #[must_use]
274 pub const fn is_text(&self) -> bool {
275 matches!(self, Self::Text(_))
276 }
277
278 #[must_use]
279 pub const fn is_scalar(&self) -> bool {
280 match self {
281 Self::List(_) | Self::Map(_) | Self::Unit => false,
283 _ => true,
284 }
285 }
286
287 #[must_use]
289 pub(crate) fn contains_enum(&self) -> bool {
290 match self {
291 Self::Enum(_) => true,
292 Self::List(values) => values.iter().any(Self::contains_enum),
293 Self::Map(entries) => entries
294 .iter()
295 .any(|(key, value)| key.contains_enum() || value.contains_enum()),
296 _ => false,
297 }
298 }
299
300 #[must_use]
302 pub(crate) const fn canonical_tag(&self) -> ValueTag {
303 tag::canonical_tag(self)
304 }
305
306 #[must_use]
308 pub(crate) const fn canonical_rank(&self) -> u8 {
309 rank::canonical_rank(self)
310 }
311
312 #[must_use]
314 pub(crate) fn canonical_cmp(left: &Self, right: &Self) -> Ordering {
315 compare::canonical_cmp(left, right)
316 }
317
318 #[must_use]
320 pub(crate) fn canonical_cmp_key(left: &Self, right: &Self) -> Ordering {
321 compare::canonical_cmp_key(left, right)
322 }
323
324 #[must_use]
329 pub const fn as_text(&self) -> Option<&str> {
330 if let Self::Text(s) = self {
331 Some(s.as_str())
332 } else {
333 None
334 }
335 }
336
337 #[must_use]
338 pub const fn as_list(&self) -> Option<&[Self]> {
339 if let Self::List(xs) = self {
340 Some(xs.as_slice())
341 } else {
342 None
343 }
344 }
345
346 #[must_use]
347 pub const fn as_map(&self) -> Option<&[(Self, Self)]> {
348 if let Self::Map(entries) = self {
349 Some(entries.as_slice())
350 } else {
351 None
352 }
353 }
354}
355
356macro_rules! impl_from_for {
357 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
358 $(
359 impl From<$type> for Value {
360 fn from(v: $type) -> Self {
361 Self::$variant(v.into())
362 }
363 }
364 )*
365 };
366}
367
368impl_from_for! {
369 Account => Account,
370 Date => Date,
371 Decimal => Decimal,
372 Duration => Duration,
373 bool => Bool,
374 i8 => Int64,
375 i16 => Int64,
376 i32 => Int64,
377 i64 => Int64,
378 i128 => Int128,
379 IntBig => IntBig,
380 Principal => Principal,
381 Subaccount => Subaccount,
382 &str => Text,
383 String => Text,
384 Timestamp => Timestamp,
385 u8 => Nat64,
386 u16 => Nat64,
387 u32 => Nat64,
388 u64 => Nat64,
389 u128 => Nat128,
390 NatBig => NatBig,
391 Ulid => Ulid,
392}
393
394impl From<Vec<Self>> for Value {
395 fn from(vec: Vec<Self>) -> Self {
396 Self::List(vec)
397 }
398}
399
400impl TryFrom<Vec<(Self, Self)>> for Value {
401 type Error = SchemaInvariantError;
402
403 fn try_from(entries: Vec<(Self, Self)>) -> Result<Self, Self::Error> {
404 Self::from_map(entries).map_err(Self::Error::from)
405 }
406}
407
408impl From<()> for Value {
409 fn from((): ()) -> Self {
410 Self::Unit
411 }
412}
413
414#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
420pub struct ValueEnum(CanonicalEnumValue<Value>);
421
422impl ValueEnum {
423 #[cfg(test)]
424 pub(crate) const fn test_unit(type_id: u32, variant_id: u32) -> Self {
425 Self::new(
426 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
427 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
428 CanonicalEnumBody::Unit,
429 )
430 }
431
432 #[cfg(test)]
433 pub(crate) fn test_payload(type_id: u32, variant_id: u32, payload: Value) -> Self {
434 Self::new(
435 EnumTypeId::new(type_id).expect("test enum type ID must be non-zero"),
436 EnumVariantId::new(variant_id).expect("test enum variant ID must be non-zero"),
437 CanonicalEnumBody::Payload(Box::new(payload)),
438 )
439 }
440
441 #[cfg(test)]
442 pub(crate) fn test_with_payload(self, payload: Value) -> Self {
443 Self::new(
444 self.type_id(),
445 self.variant_id(),
446 CanonicalEnumBody::Payload(Box::new(payload)),
447 )
448 }
449
450 #[must_use]
451 pub(crate) const fn from_canonical(value: CanonicalEnumValue<Value>) -> Self {
452 Self(value)
453 }
454
455 #[must_use]
456 pub(crate) const fn new(
457 type_id: EnumTypeId,
458 variant_id: EnumVariantId,
459 body: CanonicalEnumBody<Value>,
460 ) -> Self {
461 Self(CanonicalEnumValue::new(type_id, variant_id, body))
462 }
463
464 #[must_use]
465 pub(crate) const fn canonical(&self) -> &CanonicalEnumValue<Value> {
466 &self.0
467 }
468
469 #[must_use]
470 pub(crate) const fn type_id(&self) -> EnumTypeId {
471 self.0.type_id()
472 }
473
474 #[must_use]
475 pub(crate) const fn variant_id(&self) -> EnumVariantId {
476 self.0.variant_id()
477 }
478
479 #[must_use]
480 pub(crate) const fn body(&self) -> &CanonicalEnumBody<Value> {
481 self.0.body()
482 }
483
484 #[must_use]
485 pub(crate) fn payload(&self) -> Option<&Value> {
486 match self.body() {
487 CanonicalEnumBody::Unit => None,
488 CanonicalEnumBody::Payload(payload) => Some(payload.as_ref()),
489 }
490 }
491}
492
493impl<'de> Deserialize<'de> for ValueEnum {
494 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
495 where
496 D: Deserializer<'de>,
497 {
498 let (type_id, variant_id, payload): (u32, u32, Option<Box<Value>>) =
499 Deserialize::deserialize(deserializer)?;
500 let type_id = EnumTypeId::new(type_id)
501 .ok_or_else(|| de::Error::custom("enum type ID must be non-zero"))?;
502 let variant_id = EnumVariantId::new(variant_id)
503 .ok_or_else(|| de::Error::custom("enum variant ID must be non-zero"))?;
504 let body = payload.map_or(CanonicalEnumBody::Unit, CanonicalEnumBody::Payload);
505 Ok(Self::new(type_id, variant_id, body))
506 }
507}