diff options
| author | wires <wires@noreply.wires.systems> | 2025-10-24 11:29:46 -0400 |
|---|---|---|
| committer | wires <wires@noreply.wires.systems> | 2025-10-24 11:29:46 -0400 |
| commit | 92e4cfc123a1d26265128634850a2b73bac761c2 (patch) | |
| tree | bdbab6c9ac4a8e981888700e16a7e79b1afb3b27 /wyrd_sqlite/src/from_sql.rs | |
| parent | initial commit (diff) | |
| download | wyrd-main.tar.gz | |
Diffstat (limited to 'wyrd_sqlite/src/from_sql.rs')
| -rw-r--r-- | wyrd_sqlite/src/from_sql.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/wyrd_sqlite/src/from_sql.rs b/wyrd_sqlite/src/from_sql.rs new file mode 100644 index 0000000..3b149e8 --- /dev/null +++ b/wyrd_sqlite/src/from_sql.rs @@ -0,0 +1,85 @@ +use std::num::{NonZero, TryFromIntError}; + +pub enum Value<'a> { + Int(i64), + Float(f64), + Text(&'a str), + Blob(&'a [u8]), + Null, +} + +// this is an owned trait to get around some problems with blanket implementations +pub trait FromSql: Sized { + type Error: std::error::Error; + + fn try_from_sql(value: Value<'_>) -> Result<Self, Self::Error>; +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid type")] +pub struct InvalidTypeError; + +#[derive(Debug, thiserror::Error)] +pub enum FromSqlIntError { + #[error(transparent)] + InvalidType(#[from] InvalidTypeError), + #[error(transparent)] + TryFromInt(#[from] TryFromIntError), +} + +impl FromSql for i64 { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value<'_>) -> Result<Self, Self::Error> { + if let Value::Int(i) = value { + Ok(i) + } else { + Err(InvalidTypeError.into()) + } + } +} + +impl FromSql for NonZero<i64> { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value) -> Result<Self, Self::Error> { + let i: i64 = FromSql::try_from_sql(value)?; + Ok(i.try_into()?) + } +} + +macro_rules! int_impl { + ($($source:ty),+) => {$( + impl FromSql for $source { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value<'_>) -> Result<Self, Self::Error> { + let i: i64 = FromSql::try_from_sql(value)?; + Ok(i.try_into()?) + } + } + + impl FromSql for NonZero<$source> { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value<'_>) -> Result<Self, Self::Error> { + let i: NonZero<i64> = FromSql::try_from_sql(value)?; + Ok(i.try_into()?) + } + } + )*} +} + +int_impl!(i8, i16, i32, u8, u16, u32, u64); + +impl<'a, T: FromSql> FromSql for Option<T> { + type Error = T::Error; + + fn try_from_sql(value: Value<'_>) -> Result<Self, Self::Error> { + if let Value::Null = value { + Ok(None) + } else { + FromSql::try_from_sql(value).map(Some) + } + } +} |