dbase/field/
conversion.rs

1use super::{types, FieldType, FieldValue};
2
3/// Errors that can happen when trying to convert a FieldValue into
4/// a more concrete type
5#[derive(Debug)]
6pub enum FieldConversionError {
7    /// Happens when the conversion could not be mode because the FieldType
8    /// does not mat the expected one
9    FieldTypeNotAsExpected {
10        /// The expected FieldType of the FieldValue the conversion was tried on
11        expected: FieldType,
12        /// The actual FieldType of the FieldValue the conversion was tried on
13        actual: FieldType,
14    },
15    IncompatibleType,
16    /// The value written is the file was only pad bytes / uninitialized
17    /// and the user tried to convert it into a non Option-Type
18    NoneValue,
19}
20
21impl std::fmt::Display for FieldConversionError {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            FieldConversionError::FieldTypeNotAsExpected { expected, actual } => {
25                write!(f, "Cannot convert from {} to {}", expected, actual)
26            }
27            FieldConversionError::IncompatibleType => write!(f, "The type is not compatible"),
28            FieldConversionError::NoneValue => {
29                write!(f, "Value is not initialized, which is not allowed")
30            }
31        }
32    }
33}
34
35impl std::error::Error for FieldConversionError {}
36
37macro_rules! impl_try_from_field_value_for_ {
38    (FieldValue::$variant:ident => $out_type:ty) => {
39        impl TryFrom<FieldValue> for $out_type {
40            type Error = FieldConversionError;
41
42            fn try_from(value: FieldValue) -> Result<Self, Self::Error> {
43                if let FieldValue::$variant(v) = value {
44                    Ok(v)
45                } else {
46                    Err(FieldConversionError::FieldTypeNotAsExpected {
47                        expected: FieldType::$variant,
48                        actual: value.field_type(),
49                    })
50                }
51            }
52        }
53    };
54    (FieldValue::$variant:ident(Some($v:ident)) => $out_type:ty) => {
55        impl TryFrom<FieldValue> for $out_type {
56            type Error = FieldConversionError;
57
58            fn try_from(value: FieldValue) -> Result<Self, Self::Error> {
59                match value {
60                    FieldValue::$variant(Some($v)) => Ok($v),
61                    FieldValue::$variant(None) => Err(FieldConversionError::NoneValue),
62                    _ => Err(FieldConversionError::FieldTypeNotAsExpected {
63                        expected: FieldType::$variant,
64                        actual: value.field_type(),
65                    }),
66                }
67            }
68        }
69    };
70}
71
72impl_try_from_field_value_for_!(FieldValue::Numeric => Option<f64>);
73
74impl_try_from_field_value_for_!(FieldValue::Float => Option<f32>);
75impl_try_from_field_value_for_!(FieldValue::Float(Some(v)) => f32);
76
77impl_try_from_field_value_for_!(FieldValue::Date => Option<types::Date>);
78impl_try_from_field_value_for_!(FieldValue::Date(Some(v)) => types::Date);
79
80impl_try_from_field_value_for_!(FieldValue::Character => Option<String>);
81impl_try_from_field_value_for_!(FieldValue::Character(Some(string)) => String);
82
83impl_try_from_field_value_for_!(FieldValue::Logical => Option<bool>);
84impl_try_from_field_value_for_!(FieldValue::Logical(Some(b)) => bool);
85
86impl_try_from_field_value_for_!(FieldValue::Integer => i32);
87
88impl TryFrom<FieldValue> for f64 {
89    type Error = FieldConversionError;
90
91    fn try_from(value: FieldValue) -> Result<Self, Self::Error> {
92        match value {
93            FieldValue::Numeric(Some(v)) => Ok(v),
94            FieldValue::Numeric(None) => Err(FieldConversionError::NoneValue),
95            FieldValue::Currency(c) => Ok(c),
96            FieldValue::Double(d) => Ok(d),
97            _ => Err(FieldConversionError::IncompatibleType),
98        }
99    }
100}
101
102// Fox Pro types
103impl_try_from_field_value_for_!(FieldValue::DateTime => types::DateTime);
104
105macro_rules! impl_from_type_for_field_value (
106    ($t:ty => FieldValue::$variant:ident) => {
107        impl From<$t> for FieldValue {
108            fn from(v: $t) -> Self {
109                FieldValue::$variant(v)
110            }
111        }
112    };
113    ($t:ty => FieldValue::$variant:ident(Some($v:ident))) => {
114        impl From<$t> for FieldValue {
115            fn from(v: $t) -> Self {
116                FieldValue::$variant(Some(v))
117            }
118        }
119    }
120);
121
122impl_from_type_for_field_value!(Option<String> => FieldValue::Character);
123impl_from_type_for_field_value!(String => FieldValue::Character(Some(s)));
124
125impl_from_type_for_field_value!(Option<f64> => FieldValue::Numeric);
126impl_from_type_for_field_value!(f64 => FieldValue::Numeric(Some(v)));
127
128impl_from_type_for_field_value!(Option<f32> => FieldValue::Float);
129impl_from_type_for_field_value!(f32 => FieldValue::Float(Some(v)));
130
131impl_from_type_for_field_value!(Option<bool> => FieldValue::Logical);
132impl_from_type_for_field_value!(bool => FieldValue::Logical(Some(v)));
133
134impl_from_type_for_field_value!(Option<types::Date> => FieldValue::Date);
135impl_from_type_for_field_value!(types::Date => FieldValue::Date(Some(v)));
136
137// Fox Pro types
138impl_from_type_for_field_value!(types::DateTime => FieldValue::DateTime);