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