Skip to main content

icydb_core/value/
output.rs

1use crate::{
2    types::{
3        Account, Date, Decimal, Duration, Float32, Float64, Principal, Subaccount, Timestamp, U256,
4        Ulid,
5    },
6    value::PublicValue,
7};
8
9use serde::{Deserialize, Deserializer};
10
11#[cfg(test)]
12use crate::value::Value;
13
14/// Public output-side root value boundary.
15///
16/// Recursive data is owned by `PublicValue`; this sealed wrapper keeps
17/// accepted output distinct from caller-authored `InputValue`.
18#[repr(transparent)]
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct OutputValue(PublicValue);
21
22impl OutputValue {
23    /// Borrow the canonical recursive public value.
24    #[must_use]
25    pub const fn as_public(&self) -> &PublicValue {
26        &self.0
27    }
28
29    /// Consume this boundary wrapper without conversion.
30    #[must_use]
31    pub fn into_public(self) -> PublicValue {
32        self.0
33    }
34
35    pub(crate) const fn from_public(value: PublicValue) -> Self {
36        Self(value)
37    }
38
39    /// Build an account output value.
40    #[must_use]
41    pub const fn account(value: Account) -> Self {
42        Self(PublicValue::Account(value))
43    }
44
45    /// Build a blob output value.
46    #[must_use]
47    pub const fn blob(value: Vec<u8>) -> Self {
48        Self(PublicValue::Blob(value))
49    }
50
51    /// Build a boolean output value.
52    #[must_use]
53    pub const fn boolean(value: bool) -> Self {
54        Self(PublicValue::Bool(value))
55    }
56
57    /// Build a date output value.
58    #[must_use]
59    pub const fn date(value: Date) -> Self {
60        Self(PublicValue::Date(value))
61    }
62
63    /// Build a decimal output value.
64    #[must_use]
65    pub const fn decimal(value: Decimal) -> Self {
66        Self(PublicValue::Decimal(value))
67    }
68
69    /// Build a duration output value.
70    #[must_use]
71    pub const fn duration(value: Duration) -> Self {
72        Self(PublicValue::Duration(value))
73    }
74
75    /// Build a finite 32-bit floating-point output value.
76    #[must_use]
77    pub const fn float32(value: Float32) -> Self {
78        Self(PublicValue::Float32(value))
79    }
80
81    /// Build a finite 64-bit floating-point output value.
82    #[must_use]
83    pub const fn float64(value: Float64) -> Self {
84        Self(PublicValue::Float64(value))
85    }
86
87    /// Build a 64-bit signed integer output value.
88    #[must_use]
89    pub const fn int64(value: i64) -> Self {
90        Self(PublicValue::Int64(value))
91    }
92
93    /// Build a 128-bit signed integer output value.
94    #[must_use]
95    pub const fn int128(value: i128) -> Self {
96        Self(PublicValue::Int128(value))
97    }
98
99    /// Build a recursive list output value.
100    #[must_use]
101    pub const fn list(values: Vec<PublicValue>) -> Self {
102        Self(PublicValue::List(values))
103    }
104
105    /// Build a recursive map output value.
106    #[must_use]
107    pub const fn map(entries: Vec<(PublicValue, PublicValue)>) -> Self {
108        Self(PublicValue::Map(entries))
109    }
110
111    /// Build a null output value.
112    #[must_use]
113    pub const fn null() -> Self {
114        Self(PublicValue::Null)
115    }
116
117    /// Build a principal output value.
118    #[must_use]
119    pub const fn principal(value: Principal) -> Self {
120        Self(PublicValue::Principal(value))
121    }
122
123    /// Build a fixed subaccount output value.
124    #[must_use]
125    pub const fn subaccount(value: Subaccount) -> Self {
126        Self(PublicValue::Subaccount(value))
127    }
128
129    /// Build a text output value.
130    #[must_use]
131    pub const fn text(value: String) -> Self {
132        Self(PublicValue::Text(value))
133    }
134
135    /// Build a timestamp output value.
136    #[must_use]
137    pub const fn timestamp(value: Timestamp) -> Self {
138        Self(PublicValue::Timestamp(value))
139    }
140
141    /// Build a 64-bit natural output value.
142    #[must_use]
143    pub const fn nat64(value: u64) -> Self {
144        Self(PublicValue::Nat64(value))
145    }
146
147    /// Build a 128-bit natural output value.
148    #[must_use]
149    pub const fn nat128(value: u128) -> Self {
150        Self(PublicValue::Nat128(value))
151    }
152
153    /// Build a ULID output value.
154    #[must_use]
155    pub const fn ulid(value: Ulid) -> Self {
156        Self(PublicValue::Ulid(value))
157    }
158
159    /// Build a unit output value.
160    #[must_use]
161    pub const fn unit() -> Self {
162        Self(PublicValue::Unit)
163    }
164
165    /// Build a fixed-width unsigned integer output value.
166    #[must_use]
167    pub const fn u256(value: U256) -> Self {
168        Self(PublicValue::U256(value))
169    }
170}
171
172impl<'de> Deserialize<'de> for OutputValue {
173    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
174    where
175        D: Deserializer<'de>,
176    {
177        PublicValue::deserialize(deserializer).map(Self)
178    }
179}
180
181#[cfg(test)]
182impl From<Value> for OutputValue {
183    fn from(value: Value) -> Self {
184        Self(
185            PublicValue::try_from_runtime_non_enum(&value)
186                .expect("test output conversion requires accepted enum catalog"),
187        )
188    }
189}
190
191/// Render one accepted output value into the stable row-projection text form.
192#[must_use]
193pub fn render_output_value_text(value: &OutputValue) -> String {
194    value.as_public().render_text()
195}
196
197impl serde::Serialize for OutputValue {
198    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
199        serde::Serialize::serialize(&self.0, serializer)
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use crate::value::{OutputValue, PublicValue, Value};
206
207    #[test]
208    fn output_value_from_runtime_value_keeps_recursive_collection_shape() {
209        let runtime = Value::List(vec![
210            Value::Nat64(7),
211            Value::Map(vec![(Value::Text("x".to_string()), Value::Bool(true))]),
212        ]);
213
214        assert_eq!(
215            OutputValue::from(runtime),
216            OutputValue::list(vec![
217                PublicValue::Nat64(7),
218                PublicValue::Map(vec![(
219                    PublicValue::Text("x".to_string()),
220                    PublicValue::Bool(true),
221                )]),
222            ]),
223        );
224    }
225}