icydb_core/value/
output.rs1use crate::{
2 types::{
3 Account, Date, Decimal, Duration, Float32, Float64, IntBig, NatBig, Principal, Subaccount,
4 Timestamp, U256, Ulid,
5 },
6 value::PublicValue,
7};
8use candid::{CandidType, types::Serializer};
9use serde::{Deserialize, Deserializer};
10
11#[cfg(test)]
12use crate::value::Value;
13
14#[repr(transparent)]
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct OutputValue(PublicValue);
21
22impl OutputValue {
23 #[must_use]
25 pub const fn as_public(&self) -> &PublicValue {
26 &self.0
27 }
28
29 #[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 #[must_use]
41 pub const fn account(value: Account) -> Self {
42 Self(PublicValue::Account(value))
43 }
44
45 #[must_use]
47 pub const fn blob(value: Vec<u8>) -> Self {
48 Self(PublicValue::Blob(value))
49 }
50
51 #[must_use]
53 pub const fn boolean(value: bool) -> Self {
54 Self(PublicValue::Bool(value))
55 }
56
57 #[must_use]
59 pub const fn date(value: Date) -> Self {
60 Self(PublicValue::Date(value))
61 }
62
63 #[must_use]
65 pub const fn decimal(value: Decimal) -> Self {
66 Self(PublicValue::Decimal(value))
67 }
68
69 #[must_use]
71 pub const fn duration(value: Duration) -> Self {
72 Self(PublicValue::Duration(value))
73 }
74
75 #[must_use]
77 pub const fn float32(value: Float32) -> Self {
78 Self(PublicValue::Float32(value))
79 }
80
81 #[must_use]
83 pub const fn float64(value: Float64) -> Self {
84 Self(PublicValue::Float64(value))
85 }
86
87 #[must_use]
89 pub const fn int64(value: i64) -> Self {
90 Self(PublicValue::Int64(value))
91 }
92
93 #[must_use]
95 pub const fn int128(value: i128) -> Self {
96 Self(PublicValue::Int128(value))
97 }
98
99 #[must_use]
101 pub const fn int_big(value: IntBig) -> Self {
102 Self(PublicValue::IntBig(value))
103 }
104
105 #[must_use]
107 pub const fn list(values: Vec<PublicValue>) -> Self {
108 Self(PublicValue::List(values))
109 }
110
111 #[must_use]
113 pub const fn map(entries: Vec<(PublicValue, PublicValue)>) -> Self {
114 Self(PublicValue::Map(entries))
115 }
116
117 #[must_use]
119 pub const fn null() -> Self {
120 Self(PublicValue::Null)
121 }
122
123 #[must_use]
125 pub const fn principal(value: Principal) -> Self {
126 Self(PublicValue::Principal(value))
127 }
128
129 #[must_use]
131 pub const fn subaccount(value: Subaccount) -> Self {
132 Self(PublicValue::Subaccount(value))
133 }
134
135 #[must_use]
137 pub const fn text(value: String) -> Self {
138 Self(PublicValue::Text(value))
139 }
140
141 #[must_use]
143 pub const fn timestamp(value: Timestamp) -> Self {
144 Self(PublicValue::Timestamp(value))
145 }
146
147 #[must_use]
149 pub const fn nat64(value: u64) -> Self {
150 Self(PublicValue::Nat64(value))
151 }
152
153 #[must_use]
155 pub const fn nat128(value: u128) -> Self {
156 Self(PublicValue::Nat128(value))
157 }
158
159 #[must_use]
161 pub const fn nat_big(value: NatBig) -> Self {
162 Self(PublicValue::NatBig(value))
163 }
164
165 #[must_use]
167 pub const fn ulid(value: Ulid) -> Self {
168 Self(PublicValue::Ulid(value))
169 }
170
171 #[must_use]
173 pub const fn unit() -> Self {
174 Self(PublicValue::Unit)
175 }
176
177 #[must_use]
179 pub const fn u256(value: U256) -> Self {
180 Self(PublicValue::U256(value))
181 }
182}
183
184impl CandidType for OutputValue {
185 fn ty() -> candid::types::Type {
186 PublicValue::ty()
187 }
188
189 fn _ty() -> candid::types::Type {
190 PublicValue::_ty()
191 }
192
193 fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
194 where
195 S: Serializer,
196 {
197 self.0.idl_serialize(serializer)
198 }
199}
200
201impl<'de> Deserialize<'de> for OutputValue {
202 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
203 where
204 D: Deserializer<'de>,
205 {
206 PublicValue::deserialize(deserializer).map(Self)
207 }
208}
209
210#[cfg(test)]
211impl From<Value> for OutputValue {
212 fn from(value: Value) -> Self {
213 Self(
214 PublicValue::try_from_runtime_non_enum(&value)
215 .expect("test output conversion requires accepted enum catalog"),
216 )
217 }
218}
219
220#[must_use]
222pub fn render_output_value_text(value: &OutputValue) -> String {
223 value.as_public().render_text()
224}
225
226#[cfg(test)]
227mod tests {
228 use crate::value::{OutputValue, PublicValue, Value};
229
230 #[test]
231 fn output_value_from_runtime_value_keeps_recursive_collection_shape() {
232 let runtime = Value::List(vec![
233 Value::Nat64(7),
234 Value::Map(vec![(Value::Text("x".to_string()), Value::Bool(true))]),
235 ]);
236
237 assert_eq!(
238 OutputValue::from(runtime),
239 OutputValue::list(vec![
240 PublicValue::Nat64(7),
241 PublicValue::Map(vec![(
242 PublicValue::Text("x".to_string()),
243 PublicValue::Bool(true),
244 )]),
245 ]),
246 );
247 }
248}