Skip to main content

ion_rs/result/
conversion.rs

1use crate::{Bytes, Decimal, Int, IonType, Sequence, Str, Struct, Symbol, Timestamp};
2
3use std::fmt;
4use std::marker::PhantomData;
5use thiserror::Error;
6
7pub type ConversionOperationResult<FromType, ToType> =
8    Result<ToType, ConversionOperationError<FromType, ToType>>;
9
10/// Represents a mismatch during conversion between the expected type and the actual value's type.
11#[derive(Clone, Debug, Error, PartialEq)]
12#[error("Type conversion error; expected a(n) {output_type}, found a(n) {input_type}")]
13pub struct ConversionError {
14    input_type: String,
15    output_type: String,
16}
17
18impl<FromType, ToType> From<ConversionOperationError<FromType, ToType>> for ConversionError
19where
20    FromType: ValueTypeExpectation,
21    ToType: TypeExpectation,
22{
23    fn from(err: ConversionOperationError<FromType, ToType>) -> Self {
24        ConversionError {
25            input_type: err.input_value.expected_type_name(),
26            output_type: ToType::expected_type_name(),
27        }
28    }
29}
30
31/// Represents a mismatch during conversion between the expected type and the actual value's type;
32/// Holds the original value that was not able to be converted.
33#[derive(Clone, Debug, PartialEq)]
34pub struct ConversionOperationError<FromType, ToType> {
35    input_value: FromType,
36    output_type: PhantomData<ToType>,
37}
38
39impl<FromType, ToType> fmt::Display for ConversionOperationError<FromType, ToType>
40where
41    FromType: ValueTypeExpectation,
42    ToType: TypeExpectation,
43{
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(
46            f,
47            "Type conversion error; expected a(n) {}, found a(n) {}",
48            ToType::expected_type_name(),
49            self.input_value.expected_type_name()
50        )
51    }
52}
53
54impl<FromType, ToType> std::error::Error for ConversionOperationError<FromType, ToType>
55where
56    FromType: ValueTypeExpectation + fmt::Debug,
57    ToType: TypeExpectation + fmt::Debug,
58{
59}
60
61impl<FromType, ToType> ConversionOperationError<FromType, ToType> {
62    pub fn new(input_value: FromType) -> Self {
63        Self {
64            input_value,
65            output_type: PhantomData,
66        }
67    }
68
69    pub fn original_value(self) -> FromType {
70        self.input_value
71    }
72}
73
74impl<FromType, ToType> From<FromType> for ConversionOperationError<FromType, ToType>
75where
76    FromType: ValueTypeExpectation,
77    ToType: TypeExpectation,
78{
79    fn from(input_value: FromType) -> Self {
80        Self::new(input_value)
81    }
82}
83
84pub trait IonTypeExpectation {
85    fn ion_type(&self) -> IonType;
86}
87
88pub trait ValueTypeExpectation {
89    fn expected_type_name(&self) -> String;
90}
91
92pub trait TypeExpectation {
93    fn expected_type_name() -> String;
94}
95
96macro_rules! impl_type_expectation {
97    ($ty:ty, $e:expr) => {
98        impl TypeExpectation for $ty {
99            fn expected_type_name() -> String {
100                $e.to_string()
101            }
102        }
103    };
104}
105
106macro_rules! impl_type_and_ref_expectation {
107    ($ty:ty, $e:expr) => {
108        impl_type_expectation!($ty, $e);
109        impl_type_expectation!(&$ty, $e);
110    };
111}
112
113impl_type_and_ref_expectation!(Int, IonType::Int);
114impl_type_expectation!(i64, "i64 value");
115impl_type_expectation!(usize, "usize value");
116impl_type_expectation!(f64, IonType::Float);
117impl_type_and_ref_expectation!(Decimal, IonType::Decimal);
118impl_type_and_ref_expectation!(Timestamp, IonType::Timestamp);
119impl_type_and_ref_expectation!(String, "text value");
120impl_type_expectation!(&str, "text value");
121impl_type_and_ref_expectation!(Str, IonType::String);
122impl_type_and_ref_expectation!(Symbol, IonType::Symbol);
123impl_type_expectation!(bool, IonType::Bool);
124impl_type_and_ref_expectation!(Bytes, "lob value");
125impl_type_expectation!(&[u8], "lob value");
126impl_type_and_ref_expectation!(Sequence, "sequence value");
127impl_type_and_ref_expectation!(Struct, IonType::Struct);
128
129impl<T> ValueTypeExpectation for T
130where
131    T: IonTypeExpectation,
132{
133    fn expected_type_name(&self) -> String {
134        self.ion_type().to_string()
135    }
136}