1use std::{
5 error,
6 fmt::{self, Display, Formatter},
7};
8
9use crate::value::{
10 Value,
11 blob::Blob,
12 date::Date,
13 datetime::DateTime,
14 decimal::Decimal,
15 duration::Duration,
16 identity::IdentityId,
17 int::Int,
18 ordered_f32::OrderedF32,
19 ordered_f64::OrderedF64,
20 time::Time,
21 uint::Uint,
22 uuid::{Uuid4, Uuid7},
23 value_type::ValueType,
24};
25
26#[derive(Debug, Clone, PartialEq)]
27pub enum FromValueError {
28 TypeMismatch {
29 expected: ValueType,
30 found: ValueType,
31 },
32
33 OutOfRange {
34 value: String,
35 target_type: &'static str,
36 },
37}
38
39impl Display for FromValueError {
40 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
41 match self {
42 FromValueError::TypeMismatch {
43 expected,
44 found,
45 } => {
46 write!(f, "type mismatch: expected {:?}, found {:?}", expected, found)
47 }
48 FromValueError::OutOfRange {
49 value,
50 target_type,
51 } => {
52 write!(f, "value {} out of range for type {}", value, target_type)
53 }
54 }
55 }
56}
57
58impl error::Error for FromValueError {}
59
60pub trait TryFromValue: Sized {
61 fn try_from_value(value: &Value) -> Result<Self, FromValueError>;
62
63 fn from_value(value: &Value) -> Option<Self> {
64 match value {
65 Value::None {
66 ..
67 } => None,
68 v => Self::try_from_value(v).ok(),
69 }
70 }
71}
72
73pub trait TryFromValueCoerce: Sized {
74 fn try_from_value_coerce(value: &Value) -> Result<Self, FromValueError>;
75
76 fn from_value_coerce(value: &Value) -> Option<Self> {
77 match value {
78 Value::None {
79 ..
80 } => None,
81 v => Self::try_from_value_coerce(v).ok(),
82 }
83 }
84}
85
86impl TryFromValue for Value {
87 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
88 Ok(value.clone())
89 }
90}
91
92impl TryFromValue for bool {
93 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
94 match value {
95 Value::Boolean(v) => Ok(*v),
96 _ => Err(FromValueError::TypeMismatch {
97 expected: ValueType::Boolean,
98 found: value.get_type(),
99 }),
100 }
101 }
102}
103
104impl TryFromValue for i8 {
105 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
106 match value {
107 Value::Int1(v) => Ok(*v),
108 _ => Err(FromValueError::TypeMismatch {
109 expected: ValueType::Int1,
110 found: value.get_type(),
111 }),
112 }
113 }
114}
115
116impl TryFromValue for i16 {
117 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
118 match value {
119 Value::Int2(v) => Ok(*v),
120 _ => Err(FromValueError::TypeMismatch {
121 expected: ValueType::Int2,
122 found: value.get_type(),
123 }),
124 }
125 }
126}
127
128impl TryFromValue for i32 {
129 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
130 match value {
131 Value::Int4(v) => Ok(*v),
132 _ => Err(FromValueError::TypeMismatch {
133 expected: ValueType::Int4,
134 found: value.get_type(),
135 }),
136 }
137 }
138}
139
140impl TryFromValue for i64 {
141 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
142 match value {
143 Value::Int8(v) => Ok(*v),
144 _ => Err(FromValueError::TypeMismatch {
145 expected: ValueType::Int8,
146 found: value.get_type(),
147 }),
148 }
149 }
150}
151
152impl TryFromValue for i128 {
153 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
154 match value {
155 Value::Int16(v) => Ok(*v),
156 _ => Err(FromValueError::TypeMismatch {
157 expected: ValueType::Int16,
158 found: value.get_type(),
159 }),
160 }
161 }
162}
163
164impl TryFromValue for u8 {
165 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
166 match value {
167 Value::Uint1(v) => Ok(*v),
168 _ => Err(FromValueError::TypeMismatch {
169 expected: ValueType::Uint1,
170 found: value.get_type(),
171 }),
172 }
173 }
174}
175
176impl TryFromValue for u16 {
177 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
178 match value {
179 Value::Uint2(v) => Ok(*v),
180 _ => Err(FromValueError::TypeMismatch {
181 expected: ValueType::Uint2,
182 found: value.get_type(),
183 }),
184 }
185 }
186}
187
188impl TryFromValue for u32 {
189 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
190 match value {
191 Value::Uint4(v) => Ok(*v),
192 _ => Err(FromValueError::TypeMismatch {
193 expected: ValueType::Uint4,
194 found: value.get_type(),
195 }),
196 }
197 }
198}
199
200impl TryFromValue for u64 {
201 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
202 match value {
203 Value::Uint8(v) => Ok(*v),
204 _ => Err(FromValueError::TypeMismatch {
205 expected: ValueType::Uint8,
206 found: value.get_type(),
207 }),
208 }
209 }
210}
211
212impl TryFromValue for u128 {
213 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
214 match value {
215 Value::Uint16(v) => Ok(*v),
216 _ => Err(FromValueError::TypeMismatch {
217 expected: ValueType::Uint16,
218 found: value.get_type(),
219 }),
220 }
221 }
222}
223
224impl TryFromValue for f32 {
225 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
226 match value {
227 Value::Float4(v) => Ok(v.value()),
228 _ => Err(FromValueError::TypeMismatch {
229 expected: ValueType::Float4,
230 found: value.get_type(),
231 }),
232 }
233 }
234}
235
236impl TryFromValue for f64 {
237 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
238 match value {
239 Value::Float8(v) => Ok(v.value()),
240 _ => Err(FromValueError::TypeMismatch {
241 expected: ValueType::Float8,
242 found: value.get_type(),
243 }),
244 }
245 }
246}
247
248impl TryFromValue for String {
249 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
250 match value {
251 Value::Utf8(v) => Ok(v.clone()),
252 _ => Err(FromValueError::TypeMismatch {
253 expected: ValueType::Utf8,
254 found: value.get_type(),
255 }),
256 }
257 }
258}
259
260impl TryFromValue for OrderedF32 {
261 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
262 match value {
263 Value::Float4(v) => Ok(*v),
264 _ => Err(FromValueError::TypeMismatch {
265 expected: ValueType::Float4,
266 found: value.get_type(),
267 }),
268 }
269 }
270}
271
272impl TryFromValue for OrderedF64 {
273 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
274 match value {
275 Value::Float8(v) => Ok(*v),
276 _ => Err(FromValueError::TypeMismatch {
277 expected: ValueType::Float8,
278 found: value.get_type(),
279 }),
280 }
281 }
282}
283
284impl TryFromValue for Blob {
285 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
286 match value {
287 Value::Blob(v) => Ok(v.clone()),
288 _ => Err(FromValueError::TypeMismatch {
289 expected: ValueType::Blob,
290 found: value.get_type(),
291 }),
292 }
293 }
294}
295
296impl TryFromValue for Uuid4 {
297 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
298 match value {
299 Value::Uuid4(v) => Ok(*v),
300 _ => Err(FromValueError::TypeMismatch {
301 expected: ValueType::Uuid4,
302 found: value.get_type(),
303 }),
304 }
305 }
306}
307
308impl TryFromValue for Uuid7 {
309 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
310 match value {
311 Value::Uuid7(v) => Ok(*v),
312 _ => Err(FromValueError::TypeMismatch {
313 expected: ValueType::Uuid7,
314 found: value.get_type(),
315 }),
316 }
317 }
318}
319
320impl TryFromValue for Date {
321 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
322 match value {
323 Value::Date(v) => Ok(*v),
324 _ => Err(FromValueError::TypeMismatch {
325 expected: ValueType::Date,
326 found: value.get_type(),
327 }),
328 }
329 }
330}
331
332impl TryFromValue for DateTime {
333 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
334 match value {
335 Value::DateTime(v) => Ok(*v),
336 _ => Err(FromValueError::TypeMismatch {
337 expected: ValueType::DateTime,
338 found: value.get_type(),
339 }),
340 }
341 }
342}
343
344impl TryFromValue for Time {
345 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
346 match value {
347 Value::Time(v) => Ok(*v),
348 _ => Err(FromValueError::TypeMismatch {
349 expected: ValueType::Time,
350 found: value.get_type(),
351 }),
352 }
353 }
354}
355
356impl TryFromValue for Duration {
357 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
358 match value {
359 Value::Duration(v) => Ok(*v),
360 _ => Err(FromValueError::TypeMismatch {
361 expected: ValueType::Duration,
362 found: value.get_type(),
363 }),
364 }
365 }
366}
367
368impl TryFromValue for IdentityId {
369 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
370 match value {
371 Value::IdentityId(v) => Ok(*v),
372 _ => Err(FromValueError::TypeMismatch {
373 expected: ValueType::IdentityId,
374 found: value.get_type(),
375 }),
376 }
377 }
378}
379
380impl TryFromValue for Int {
381 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
382 match value {
383 Value::Int(v) => Ok(v.clone()),
384 _ => Err(FromValueError::TypeMismatch {
385 expected: ValueType::Int,
386 found: value.get_type(),
387 }),
388 }
389 }
390}
391
392impl TryFromValue for Uint {
393 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
394 match value {
395 Value::Uint(v) => Ok(v.clone()),
396 _ => Err(FromValueError::TypeMismatch {
397 expected: ValueType::Uint,
398 found: value.get_type(),
399 }),
400 }
401 }
402}
403
404impl TryFromValue for Decimal {
405 fn try_from_value(value: &Value) -> Result<Self, FromValueError> {
406 match value {
407 Value::Decimal(v) => Ok(v.clone()),
408 _ => Err(FromValueError::TypeMismatch {
409 expected: ValueType::Decimal,
410 found: value.get_type(),
411 }),
412 }
413 }
414}
415
416macro_rules! coerce_int {
417 ($t:ty, $expected:expr, $name:literal) => {
418 impl TryFromValueCoerce for $t {
419 fn try_from_value_coerce(value: &Value) -> Result<Self, FromValueError> {
420 let out_of_range = |repr: String| FromValueError::OutOfRange {
421 value: repr,
422 target_type: $name,
423 };
424 match value {
425 Value::Int1(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
426 Value::Int2(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
427 Value::Int4(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
428 Value::Int8(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
429 Value::Int16(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
430 Value::Uint1(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
431 Value::Uint2(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
432 Value::Uint4(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
433 Value::Uint8(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
434 Value::Uint16(v) => <$t>::try_from(*v).map_err(|_| out_of_range(v.to_string())),
435 _ => Err(FromValueError::TypeMismatch {
436 expected: $expected,
437 found: value.get_type(),
438 }),
439 }
440 }
441 }
442 };
443}
444
445coerce_int!(i8, ValueType::Int1, "i8");
446coerce_int!(i16, ValueType::Int2, "i16");
447coerce_int!(i32, ValueType::Int4, "i32");
448coerce_int!(i64, ValueType::Int8, "i64");
449coerce_int!(i128, ValueType::Int16, "i128");
450coerce_int!(u8, ValueType::Uint1, "u8");
451coerce_int!(u16, ValueType::Uint2, "u16");
452coerce_int!(u32, ValueType::Uint4, "u32");
453coerce_int!(u64, ValueType::Uint8, "u64");
454coerce_int!(u128, ValueType::Uint16, "u128");
455coerce_int!(usize, ValueType::Uint8, "usize");
456
457impl TryFromValueCoerce for f32 {
458 fn try_from_value_coerce(value: &Value) -> Result<Self, FromValueError> {
459 match value {
460 Value::Float4(v) => Ok(v.value()),
461 Value::Float8(v) => Ok(v.value() as f32),
462
463 Value::Int1(v) => Ok(*v as f32),
464 Value::Int2(v) => Ok(*v as f32),
465 Value::Int4(v) => Ok(*v as f32),
466 Value::Int8(v) => Ok(*v as f32),
467 Value::Int16(v) => Ok(*v as f32),
468 Value::Uint1(v) => Ok(*v as f32),
469 Value::Uint2(v) => Ok(*v as f32),
470 Value::Uint4(v) => Ok(*v as f32),
471 Value::Uint8(v) => Ok(*v as f32),
472 Value::Uint16(v) => Ok(*v as f32),
473 _ => Err(FromValueError::TypeMismatch {
474 expected: ValueType::Float4,
475 found: value.get_type(),
476 }),
477 }
478 }
479}
480
481impl TryFromValueCoerce for f64 {
482 fn try_from_value_coerce(value: &Value) -> Result<Self, FromValueError> {
483 match value {
484 Value::Float4(v) => Ok(v.value() as f64),
485 Value::Float8(v) => Ok(v.value()),
486
487 Value::Int1(v) => Ok(*v as f64),
488 Value::Int2(v) => Ok(*v as f64),
489 Value::Int4(v) => Ok(*v as f64),
490 Value::Int8(v) => Ok(*v as f64),
491 Value::Int16(v) => Ok(*v as f64),
492 Value::Uint1(v) => Ok(*v as f64),
493 Value::Uint2(v) => Ok(*v as f64),
494 Value::Uint4(v) => Ok(*v as f64),
495 Value::Uint8(v) => Ok(*v as f64),
496 Value::Uint16(v) => Ok(*v as f64),
497 _ => Err(FromValueError::TypeMismatch {
498 expected: ValueType::Float8,
499 found: value.get_type(),
500 }),
501 }
502 }
503}
504
505#[cfg(test)]
506#[allow(clippy::approx_constant)]
507pub mod tests {
508 use super::*;
509 use crate::value::{ordered_f32::OrderedF32, ordered_f64::OrderedF64};
510
511 #[test]
512 fn test_try_from_value_primitives() {
513 assert_eq!(bool::try_from_value(&Value::Boolean(true)), Ok(true));
515 assert_eq!(bool::try_from_value(&Value::Boolean(false)), Ok(false));
516 assert!(bool::try_from_value(&Value::Int4(42)).is_err());
517
518 assert_eq!(i8::try_from_value(&Value::Int1(42)), Ok(42i8));
520 assert_eq!(i16::try_from_value(&Value::Int2(1234)), Ok(1234i16));
521 assert_eq!(i32::try_from_value(&Value::Int4(123456)), Ok(123456i32));
522 assert_eq!(i64::try_from_value(&Value::Int8(1234567890)), Ok(1234567890i64));
523
524 assert_eq!(u8::try_from_value(&Value::Uint1(42)), Ok(42u8));
526 assert_eq!(u16::try_from_value(&Value::Uint2(1234)), Ok(1234u16));
527 assert_eq!(u32::try_from_value(&Value::Uint4(123456)), Ok(123456u32));
528 assert_eq!(u64::try_from_value(&Value::Uint8(1234567890)), Ok(1234567890u64));
529
530 assert_eq!(String::try_from_value(&Value::Utf8("hello".to_string())), Ok("hello".to_string()));
532 }
533
534 #[test]
535 fn test_from_value_undefined() {
536 assert_eq!(bool::from_value(&Value::none()), None);
538 assert_eq!(i32::from_value(&Value::none()), None);
539 assert_eq!(String::from_value(&Value::none()), None);
540
541 assert_eq!(bool::from_value(&Value::Int4(42)), None);
543 assert_eq!(i32::from_value(&Value::Boolean(true)), None);
544 }
545
546 #[test]
547 fn test_try_from_value_coerce_i64() {
548 assert_eq!(i64::try_from_value_coerce(&Value::Int1(42)), Ok(42i64));
550 assert_eq!(i64::try_from_value_coerce(&Value::Int2(1234)), Ok(1234i64));
551 assert_eq!(i64::try_from_value_coerce(&Value::Int4(123456)), Ok(123456i64));
552 assert_eq!(i64::try_from_value_coerce(&Value::Int8(1234567890)), Ok(1234567890i64));
553 assert_eq!(i64::try_from_value_coerce(&Value::Uint4(42)), Ok(42i64));
554
555 assert!(i64::try_from_value_coerce(&Value::Uint8(u64::MAX)).is_err());
557 assert!(i64::try_from_value_coerce(&Value::Boolean(true)).is_err());
558 }
559
560 #[test]
561 fn test_try_from_value_coerce_u64() {
562 assert_eq!(u64::try_from_value_coerce(&Value::Uint1(42)), Ok(42u64));
564 assert_eq!(u64::try_from_value_coerce(&Value::Uint2(1234)), Ok(1234u64));
565 assert_eq!(u64::try_from_value_coerce(&Value::Uint4(123456)), Ok(123456u64));
566 assert_eq!(u64::try_from_value_coerce(&Value::Uint8(1234567890)), Ok(1234567890u64));
567
568 assert_eq!(u64::try_from_value_coerce(&Value::Int4(42)), Ok(42u64));
570
571 assert!(u64::try_from_value_coerce(&Value::Int4(-42)).is_err());
573 }
574
575 #[test]
576 fn test_try_from_value_coerce_f64() {
577 let f4 = OrderedF32::try_from(3.14f32).unwrap();
579 let f8 = OrderedF64::try_from(3.14159f64).unwrap();
580 assert!((f64::try_from_value_coerce(&Value::Float4(f4)).unwrap() - 3.14).abs() < 0.01);
581 assert!((f64::try_from_value_coerce(&Value::Float8(f8)).unwrap() - 3.14159).abs() < 0.00001);
582
583 assert_eq!(f64::try_from_value_coerce(&Value::Int4(42)), Ok(42.0f64));
585 assert_eq!(f64::try_from_value_coerce(&Value::Uint4(42)), Ok(42.0f64));
586 }
587
588 #[test]
589 fn test_from_value_coerce_undefined() {
590 assert_eq!(i64::from_value_coerce(&Value::none()), None);
592 assert_eq!(u64::from_value_coerce(&Value::none()), None);
593 assert_eq!(f64::from_value_coerce(&Value::none()), None);
594 }
595}