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