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