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