1use std::any::type_name;
2use std::fmt::{self, Display};
3
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6use crate::{Cast, ColumnReader, ColumnSpec, Error, Result, SqlType, SqlValue};
7
8pub trait Value: Sized {
9 type Inner: Cast;
10 const SENSITIVE: bool = false;
11
12 fn inner(&self) -> &Self::Inner;
13
14 fn try_from_inner(inner: Self::Inner) -> Result<Self, impl Display>;
15
16 fn decode_stored(inner: Self::Inner) -> Result<Self> {
18 stored(Self::try_from_inner(inner))
19 }
20}
21
22impl<V: Value> Cast for V {
23 const COLUMNS: &'static [ColumnSpec] = V::Inner::COLUMNS;
24 const NULLABLE: bool = V::Inner::NULLABLE;
25 const SENSITIVE: bool = V::SENSITIVE || V::Inner::SENSITIVE;
26
27 fn encode(&self, out: &mut Vec<SqlValue>) {
28 self.inner().encode(out);
29 }
30
31 fn decode(row: &mut dyn ColumnReader) -> Result<Self> {
32 V::decode_stored(V::Inner::decode(row)?)
33 }
34}
35
36pub fn stored<V>(built: Result<V, impl Display>) -> Result<V> {
38 built.map_err(|error| {
39 Error::internal_message(format!(
40 "a stored {} is not valid: {error}",
41 type_name::<V>()
42 ))
43 })
44}
45
46#[must_use]
48pub const fn single_column(columns: &[ColumnSpec]) -> SqlType {
49 assert!(
50 columns.len() == 1,
51 "every field of a value with several fields must span one column"
52 );
53 columns[0].ty
54}
55
56pub fn write_masked(formatter: &mut fmt::Formatter<'_>, type_name: &str) -> fmt::Result {
57 write!(formatter, "{type_name}(***)")
58}
59
60pub fn serialize<V: Value, S: Serializer>(value: &V, serializer: S) -> Result<S::Ok, S::Error>
61where
62 V::Inner: Serialize,
63{
64 value.inner().serialize(serializer)
65}
66
67pub fn deserialize<'de, V: Value, D: Deserializer<'de>>(deserializer: D) -> Result<V, D::Error>
68where
69 V::Inner: Deserialize<'de>,
70{
71 let inner = V::Inner::deserialize(deserializer)?;
72 V::try_from_inner(inner).map_err(|error| serde::de::Error::custom(format_args!("{error:#}")))
73}
74
75#[doc(hidden)]
76pub use serde;
77
78#[doc(hidden)]
81#[macro_export]
82macro_rules! text_value {
83 ($value:ty, $field:ident) => {
84 $crate::text_value!($value, $field, |text: String| <$value>::parse(&text));
85 };
86 ($value:ty, $field:ident, $from_stored:expr) => {
87 impl $crate::value::Value for $value {
88 type Inner = String;
89
90 fn inner(&self) -> &String {
91 &self.$field
92 }
93
94 fn try_from_inner(text: String) -> $crate::Result<Self, impl ::std::fmt::Display> {
95 <$value>::parse(&text)
96 }
97
98 fn decode_stored(text: String) -> $crate::Result<Self> {
99 $crate::value::stored($from_stored(text))
100 }
101 }
102
103 impl $crate::value::serde::Serialize for $value {
104 fn serialize<S: $crate::value::serde::Serializer>(
105 &self,
106 serializer: S,
107 ) -> Result<S::Ok, S::Error> {
108 $crate::value::serialize(self, serializer)
109 }
110 }
111
112 impl<'de> $crate::value::serde::Deserialize<'de> for $value {
113 fn deserialize<D: $crate::value::serde::Deserializer<'de>>(
114 deserializer: D,
115 ) -> Result<Self, D::Error> {
116 $crate::value::deserialize(deserializer)
117 }
118 }
119 };
120}
121
122#[cfg(test)]
123mod tests {
124 use serde_json::json;
125
126 use super::*;
127
128 #[derive(Debug, PartialEq)]
129 struct Even(i64);
130
131 impl Value for Even {
132 type Inner = i64;
133
134 fn inner(&self) -> &i64 {
135 &self.0
136 }
137
138 fn try_from_inner(inner: i64) -> Result<Self, impl Display> {
139 if inner % 2 == 0 {
140 return Ok(Self(inner));
141 }
142 Err(Error::invalid("even", "must be even"))
143 }
144 }
145
146 struct Pin(String);
147
148 impl Value for Pin {
149 type Inner = String;
150 const SENSITIVE: bool = true;
151
152 fn inner(&self) -> &String {
153 &self.0
154 }
155
156 fn try_from_inner(inner: String) -> Result<Self, impl Display> {
157 Ok::<_, Error>(Self(inner))
158 }
159 }
160
161 #[test]
162 fn a_sensitive_value_is_a_sensitive_column_even_when_optional() {
163 const { assert!(<Pin as Cast>::SENSITIVE) };
164 const { assert!(<Option<Pin> as Cast>::SENSITIVE) };
165 const { assert!(!<Even as Cast>::SENSITIVE) };
166 }
167
168 #[test]
169 fn is_stored_as_its_inner_value_and_decoded_through_its_check() {
170 let mut values = Vec::new();
171 Even(4).encode(&mut values);
172 values.push(SqlValue::Int(3));
173 let mut row = crate::RowReader::new(&values);
174
175 assert_eq!(Even::decode(&mut row).unwrap(), Even(4));
176 assert!(matches!(
177 Even::decode(&mut row),
178 Err(Error::Internal { context, .. }) if context.contains("Even")
179 ));
180 }
181
182 #[derive(Debug, PartialEq)]
183 struct Small(i64);
184
185 impl Value for Small {
186 type Inner = i64;
187
188 fn inner(&self) -> &i64 {
189 &self.0
190 }
191
192 fn try_from_inner(inner: i64) -> Result<Self, impl Display> {
193 if inner < 10 {
194 return Ok(Self(inner));
195 }
196 Err(Error::invalid("small", "must be below 10"))
197 }
198
199 fn decode_stored(inner: i64) -> Result<Self> {
200 Ok(Self(inner))
201 }
202 }
203
204 #[test]
205 fn a_row_written_under_a_looser_rule_reads_while_input_stays_strict() {
206 let values = [SqlValue::Int(12)];
207
208 assert_eq!(
209 Small::decode(&mut crate::RowReader::new(&values)).unwrap(),
210 Small(12)
211 );
212 assert!(deserialize::<Small, _>(json!(12)).is_err());
213 }
214
215 #[test]
216 fn deserializing_reports_only_the_refusal_message() {
217 let accepted: Even = deserialize(json!(2)).unwrap();
218 let refused = deserialize::<Even, _>(json!(3)).unwrap_err();
219
220 assert_eq!(accepted, Even(2));
221 assert_eq!(refused.to_string(), "must be even");
222 }
223
224 #[test]
225 fn masks_a_sensitive_value() {
226 struct Pin;
227 impl fmt::Debug for Pin {
228 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
229 write_masked(formatter, "Pin")
230 }
231 }
232
233 assert_eq!(format!("{Pin:?}"), "Pin(***)");
234 }
235
236 #[test]
237 fn a_field_of_a_value_with_several_fields_spans_one_column() {
238 assert_eq!(single_column(i64::COLUMNS), SqlType::Int);
239 }
240}