Skip to main content

icydb_core/value/
wire.rs

1//! Module: value::wire
2//! Defines serde-only decode helpers that rebuild public runtime value wrappers
3//! from the stable `Value` enum wire shape.
4
5use crate::{
6    types::*,
7    value::{VALUE_WIRE_TYPE_NAME, VALUE_WIRE_VARIANT_LABELS, Value, ValueWireVariant},
8};
9use num_bigint::{BigInt, BigUint, Sign as BigIntSign};
10use serde::{
11    Deserialize, Deserializer,
12    de::{self, EnumAccess, VariantAccess, Visitor},
13};
14use serde_bytes::ByteBuf;
15use std::{fmt, marker::PhantomData};
16
17///
18/// IntBigWire
19///
20/// IntBigWire accepts the persisted `Value::IntBig` `(sign, limbs)` payload
21/// shape and rebuilds the public `IntBig` wrapper without routing through the
22/// derived `Deserialize` form of `candid::Int`.
23///
24
25struct IntBigWire(IntBig);
26
27impl IntBigWire {
28    fn into_inner(self) -> IntBig {
29        self.0
30    }
31}
32
33impl<'de> Deserialize<'de> for IntBigWire {
34    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
35    where
36        D: Deserializer<'de>,
37    {
38        let (sign, limbs): (i8, Vec<u32>) = Deserialize::deserialize(deserializer)?;
39        let sign = match sign {
40            -1 => BigIntSign::Minus,
41            0 => BigIntSign::NoSign,
42            1 => BigIntSign::Plus,
43            _ => return Err(de::Error::custom(format!("invalid IntBig sign {sign}"))),
44        };
45        let magnitude = BigUint::new(limbs);
46
47        Ok(Self(IntBig::from_bigint(BigInt::from_biguint(
48            sign, magnitude,
49        ))))
50    }
51}
52
53///
54/// NatBigWire
55///
56/// NatBigWire accepts the persisted `Value::NatBig` limb payload shape and
57/// rebuilds the public `NatBig` wrapper without routing through the derived
58/// `Deserialize` form of `candid::Nat`.
59///
60
61struct NatBigWire(NatBig);
62
63impl NatBigWire {
64    fn into_inner(self) -> NatBig {
65        self.0
66    }
67}
68
69impl<'de> Deserialize<'de> for NatBigWire {
70    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
71    where
72        D: Deserializer<'de>,
73    {
74        let limbs: Vec<u32> = Deserialize::deserialize(deserializer)?;
75        Ok(Self(NatBig::from_biguint(BigUint::new(limbs))))
76    }
77}
78
79///
80/// ValueWireVisitor
81///
82/// ValueWireVisitor decodes the stable externally tagged `Value` wire shape
83/// directly through serde enum access and re-applies runtime map invariants.
84///
85
86struct ValueWireVisitor(PhantomData<()>);
87
88impl ValueWireVisitor {
89    fn decode_map_entries<E>(entries: Vec<(Value, Value)>) -> Result<Value, E>
90    where
91        E: de::Error,
92    {
93        Value::from_map(entries).map_err(E::custom)
94    }
95}
96
97impl<'de> Visitor<'de> for ValueWireVisitor {
98    type Value = Value;
99
100    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
101        formatter.write_str("the stable Value enum wire shape")
102    }
103
104    fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
105    where
106        A: EnumAccess<'de>,
107    {
108        let (variant, payload) = data.variant::<String>()?;
109
110        let Some(variant_tag) = ValueWireVariant::from_label(variant.as_str()) else {
111            return Err(de::Error::unknown_variant(
112                variant.as_str(),
113                VALUE_WIRE_VARIANT_LABELS,
114            ));
115        };
116
117        match variant_tag {
118            ValueWireVariant::Account => Ok(Value::Account(payload.newtype_variant()?)),
119            ValueWireVariant::Blob => Ok(Value::Blob(
120                payload.newtype_variant::<ByteBuf>()?.into_vec(),
121            )),
122            ValueWireVariant::Bool => Ok(Value::Bool(payload.newtype_variant()?)),
123            ValueWireVariant::Date => Ok(Value::Date(payload.newtype_variant()?)),
124            ValueWireVariant::Decimal => Ok(Value::Decimal(payload.newtype_variant()?)),
125            ValueWireVariant::Duration => Ok(Value::Duration(payload.newtype_variant()?)),
126            ValueWireVariant::Enum => Ok(Value::Enum(payload.newtype_variant()?)),
127            ValueWireVariant::Float32 => Ok(Value::Float32(payload.newtype_variant()?)),
128            ValueWireVariant::Float64 => Ok(Value::Float64(payload.newtype_variant()?)),
129            ValueWireVariant::Int64 => Ok(Value::Int64(payload.newtype_variant()?)),
130            ValueWireVariant::Int128 => Ok(Value::Int128(payload.newtype_variant()?)),
131            ValueWireVariant::IntBig => Ok(Value::IntBig(
132                payload.newtype_variant::<IntBigWire>()?.into_inner(),
133            )),
134            ValueWireVariant::List => Ok(Value::List(payload.newtype_variant()?)),
135            ValueWireVariant::Map => {
136                let entries = payload.newtype_variant::<Vec<(Value, Value)>>()?;
137                Self::decode_map_entries(entries)
138            }
139            ValueWireVariant::Null => {
140                payload.unit_variant()?;
141                Ok(Value::Null)
142            }
143            ValueWireVariant::Principal => Ok(Value::Principal(payload.newtype_variant()?)),
144            ValueWireVariant::Subaccount => Ok(Value::Subaccount(payload.newtype_variant()?)),
145            ValueWireVariant::Text => Ok(Value::Text(payload.newtype_variant()?)),
146            ValueWireVariant::Timestamp => Ok(Value::Timestamp(payload.newtype_variant()?)),
147            ValueWireVariant::Nat64 => Ok(Value::Nat64(payload.newtype_variant()?)),
148            ValueWireVariant::Nat128 => Ok(Value::Nat128(payload.newtype_variant()?)),
149            ValueWireVariant::NatBig => Ok(Value::NatBig(
150                payload.newtype_variant::<NatBigWire>()?.into_inner(),
151            )),
152            ValueWireVariant::Ulid => Ok(Value::Ulid(payload.newtype_variant()?)),
153            ValueWireVariant::Unit => {
154                payload.unit_variant()?;
155                Ok(Value::Unit)
156            }
157        }
158    }
159}
160
161impl<'de> Deserialize<'de> for Value {
162    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
163    where
164        D: Deserializer<'de>,
165    {
166        deserializer.deserialize_enum(
167            VALUE_WIRE_TYPE_NAME,
168            VALUE_WIRE_VARIANT_LABELS,
169            ValueWireVisitor(PhantomData),
170        )
171    }
172}