1#[non_exhaustive]
12#[derive(Debug, Clone, PartialEq)]
13pub enum Value {
14 Null,
16 Bool(bool),
18 I64(i64),
20 F64(f64),
22 Text(String),
24 Bytes(Vec<u8>),
26 #[cfg(feature = "json")]
28 Json(serde_json::Value),
29 #[cfg(feature = "uuid")]
31 Uuid(uuid::Uuid),
32 #[cfg(feature = "chrono")]
34 DateTimeUtc(chrono::DateTime<chrono::Utc>),
35 #[cfg(feature = "chrono")]
37 NaiveDateTime(chrono::NaiveDateTime),
38 #[cfg(feature = "chrono")]
40 NaiveDate(chrono::NaiveDate),
41 #[cfg(feature = "chrono")]
43 NaiveTime(chrono::NaiveTime),
44}
45
46pub trait IntoBind {
48 fn into_bind(self) -> Value;
50}
51
52macro_rules! impl_into_bind_i64 {
53 ($($t:ty),* $(,)?) => {
54 $(
55 impl IntoBind for $t {
56 fn into_bind(self) -> Value {
57 Value::I64(self as i64)
58 }
59 }
60 )*
61 };
62}
63
64impl_into_bind_i64!(i8, i16, i32, i64, u8, u16, u32);
66
67impl_into_bind_i64!(u64, usize, isize);
79
80impl IntoBind for f32 {
81 fn into_bind(self) -> Value {
82 Value::F64(self as f64)
83 }
84}
85
86impl IntoBind for f64 {
87 fn into_bind(self) -> Value {
88 Value::F64(self)
89 }
90}
91
92impl IntoBind for bool {
93 fn into_bind(self) -> Value {
94 Value::Bool(self)
95 }
96}
97
98impl IntoBind for &str {
99 fn into_bind(self) -> Value {
100 Value::Text(self.to_owned())
101 }
102}
103
104impl IntoBind for String {
105 fn into_bind(self) -> Value {
106 Value::Text(self)
107 }
108}
109
110impl IntoBind for &String {
111 fn into_bind(self) -> Value {
112 Value::Text(self.clone())
113 }
114}
115
116impl IntoBind for Vec<u8> {
117 fn into_bind(self) -> Value {
118 Value::Bytes(self)
119 }
120}
121
122impl IntoBind for &[u8] {
123 fn into_bind(self) -> Value {
124 Value::Bytes(self.to_vec())
125 }
126}
127
128impl IntoBind for Value {
129 fn into_bind(self) -> Value {
130 self
131 }
132}
133
134impl<T: IntoBind> IntoBind for Option<T> {
135 fn into_bind(self) -> Value {
136 match self {
137 None => Value::Null,
138 Some(inner) => inner.into_bind(),
139 }
140 }
141}
142
143#[cfg(feature = "json")]
144impl IntoBind for serde_json::Value {
145 fn into_bind(self) -> Value {
146 Value::Json(self)
147 }
148}
149
150#[cfg(feature = "uuid")]
151impl IntoBind for uuid::Uuid {
152 fn into_bind(self) -> Value {
153 Value::Uuid(self)
154 }
155}
156
157#[cfg(feature = "chrono")]
158impl IntoBind for chrono::DateTime<chrono::Utc> {
159 fn into_bind(self) -> Value {
160 Value::DateTimeUtc(self)
161 }
162}
163
164#[cfg(feature = "chrono")]
165impl IntoBind for chrono::NaiveDateTime {
166 fn into_bind(self) -> Value {
167 Value::NaiveDateTime(self)
168 }
169}
170
171#[cfg(feature = "chrono")]
172impl IntoBind for chrono::NaiveDate {
173 fn into_bind(self) -> Value {
174 Value::NaiveDate(self)
175 }
176}
177
178#[cfg(feature = "chrono")]
179impl IntoBind for chrono::NaiveTime {
180 fn into_bind(self) -> Value {
181 Value::NaiveTime(self)
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn integers_become_i64() {
191 assert_eq!(7i8.into_bind(), Value::I64(7));
192 assert_eq!(7i16.into_bind(), Value::I64(7));
193 assert_eq!(7i32.into_bind(), Value::I64(7));
194 assert_eq!(7i64.into_bind(), Value::I64(7));
195 assert_eq!(7u8.into_bind(), Value::I64(7));
196 assert_eq!(7u16.into_bind(), Value::I64(7));
197 assert_eq!(7u32.into_bind(), Value::I64(7));
198 assert_eq!(7u64.into_bind(), Value::I64(7));
199 assert_eq!(7usize.into_bind(), Value::I64(7));
200 assert_eq!(7isize.into_bind(), Value::I64(7));
201 }
202
203 #[test]
204 fn u64_above_i64_max_wraps_intentionally() {
205 assert_eq!(((i64::MAX as u64) + 1).into_bind(), Value::I64(i64::MIN));
207 assert_eq!(u64::MAX.into_bind(), Value::I64(-1));
208 }
209
210 #[test]
211 fn floats_become_f64() {
212 assert_eq!(1.5f32.into_bind(), Value::F64(1.5));
213 assert_eq!(1.5f64.into_bind(), Value::F64(1.5));
214 }
215
216 #[test]
217 fn bool_becomes_bool() {
218 assert_eq!(true.into_bind(), Value::Bool(true));
219 assert_eq!(false.into_bind(), Value::Bool(false));
220 }
221
222 #[test]
223 fn strings_become_text() {
224 assert_eq!("hi".into_bind(), Value::Text("hi".to_string()));
225 assert_eq!(
226 String::from("hi").into_bind(),
227 Value::Text("hi".to_string())
228 );
229 let owned = String::from("hi");
230 assert_eq!((&owned).into_bind(), Value::Text("hi".to_string()));
231 }
232
233 #[test]
234 fn bytes_become_bytes() {
235 assert_eq!(vec![1u8, 2, 3].into_bind(), Value::Bytes(vec![1, 2, 3]));
236 let slice: &[u8] = &[1, 2, 3];
237 assert_eq!(slice.into_bind(), Value::Bytes(vec![1, 2, 3]));
238 }
239
240 #[test]
241 fn option_none_becomes_null() {
242 assert_eq!(Option::<i64>::None.into_bind(), Value::Null);
243 }
244
245 #[test]
246 fn option_some_becomes_inner() {
247 assert_eq!(Some(5i64).into_bind(), Value::I64(5));
248 }
249
250 #[test]
251 fn value_into_bind_is_identity() {
252 assert_eq!(Value::I64(1).into_bind(), Value::I64(1));
253 }
254}