feat(mysql): impl Type for i8, i16, i32, i64, i128, and isize

This commit is contained in:
Ryan Leckey 2021-02-26 00:38:27 -08:00
parent 01d4255137
commit 4c1d2fa679
No known key found for this signature in database
GPG Key ID: F8AA68C235AB08C9
2 changed files with 105 additions and 3 deletions

View File

@ -122,15 +122,13 @@
mod bool;
mod bytes;
mod int;
mod str;
mod uint;
// TODO: mod decimal;
// TODO: mod int;
// TODO: mod float;
// TODO: mod time;
// TODO: mod str;
// TODO: mod bytes;
// TODO: mod bit;
// TODO: mod uuid;
// TODO: mod json;

104
sqlx-mysql/src/types/int.rs Normal file
View File

@ -0,0 +1,104 @@
use sqlx_core::{decode, encode};
use sqlx_core::{Decode, Encode, Type};
use super::uint::decode_int_or_uint;
use crate::type_info::MySqlTypeInfo;
use crate::{MySql, MySqlOutput, MySqlRawValue, MySqlTypeId};
// check that the incoming value is not too large or too small
// to fit into the target SQL type
fn ensure_not_too_large_or_too_small(value: i128, ty: &MySqlTypeInfo) -> encode::Result<()> {
let max: i128 = match ty.id() {
MySqlTypeId::TINYINT => i8::MAX as _,
MySqlTypeId::SMALLINT => i16::MAX as _,
MySqlTypeId::MEDIUMINT => 0x7F_FF_FF as _,
MySqlTypeId::INT => i32::MAX as _,
MySqlTypeId::BIGINT => i64::MAX as _,
MySqlTypeId::TINYINT_UNSIGNED => u8::MAX as _,
MySqlTypeId::SMALLINT_UNSIGNED => u16::MAX as _,
MySqlTypeId::MEDIUMINT_UNSIGNED => 0xFF_FF_FF as _,
MySqlTypeId::INT_UNSIGNED => u32::MAX as _,
MySqlTypeId::BIGINT_UNSIGNED => u64::MAX as _,
// not an integer type
_ => unreachable!(),
};
let min: i128 = match ty.id() {
MySqlTypeId::TINYINT => i8::MIN as _,
MySqlTypeId::SMALLINT => i16::MIN as _,
MySqlTypeId::MEDIUMINT => 0x80_00_00 as _,
MySqlTypeId::INT => i32::MIN as _,
MySqlTypeId::BIGINT => i64::MIN as _,
MySqlTypeId::TINYINT_UNSIGNED => u8::MIN as _,
MySqlTypeId::SMALLINT_UNSIGNED => u16::MIN as _,
MySqlTypeId::MEDIUMINT_UNSIGNED => 0 as _,
MySqlTypeId::INT_UNSIGNED => u32::MIN as _,
MySqlTypeId::BIGINT_UNSIGNED => u64::MIN as _,
// not an integer type
_ => unreachable!(),
};
if value > max {
return Err(encode::Error::msg(format!(
"number `{}` too large to fit in SQL type `{}`",
value,
ty.name()
)));
}
if value < min {
return Err(encode::Error::msg(format!(
"number `{}` too small to fit in SQL type `{}`",
value,
ty.name()
)));
}
Ok(())
}
macro_rules! impl_type_int {
($ty:ty $(: $real:ty)? => $sql:ident) => {
impl Type<MySql> for $ty {
fn type_id() -> MySqlTypeId {
MySqlTypeId::$sql
}
fn compatible(ty: &MySqlTypeInfo) -> bool {
ty.id().is_integer()
}
}
impl Encode<MySql> for $ty {
fn encode(&self, ty: &MySqlTypeInfo, out: &mut MySqlOutput<'_>) -> encode::Result<()> {
ensure_not_too_large_or_too_small((*self $(as $real)?).into(), ty)?;
out.buffer().extend_from_slice(&self.to_le_bytes());
Ok(())
}
}
impl<'r> Decode<'r, MySql> for $ty {
fn decode(value: MySqlRawValue<'r>) -> decode::Result<Self> {
decode_int_or_uint(&value)
}
}
};
}
impl_type_int! { i8 => TINYINT }
impl_type_int! { i16 => SMALLINT }
impl_type_int! { i32 => INT }
impl_type_int! { i64 => BIGINT }
impl_type_int! { i128 => BIGINT }
#[cfg(target_pointer_width = "64")]
impl_type_int! { isize: i64 => BIGINT }
#[cfg(target_pointer_width = "32")]
impl_type_int! { isize: i32 => INT }