use super::types::date_and_time::MysqlTime;
use super::MysqlType;
use crate::deserialize;
use std::error::Error;
#[derive(Clone, Debug)]
pub struct MysqlValue<'a> {
raw: &'a [u8],
tpe: MysqlType,
}
impl<'a> MysqlValue<'a> {
#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
pub fn new(raw: &'a [u8], tpe: MysqlType) -> Self {
Self::new_internal(raw, tpe)
}
pub(in crate::mysql) fn new_internal(raw: &'a [u8], tpe: MysqlType) -> Self {
Self { raw, tpe }
}
pub fn as_bytes(&self) -> &[u8] {
self.raw
}
pub fn value_type(&self) -> MysqlType {
self.tpe
}
#[allow(dead_code, clippy::cast_ptr_alignment)]
pub(crate) fn time_value(&self) -> deserialize::Result<MysqlTime> {
match self.tpe {
MysqlType::Time | MysqlType::Date | MysqlType::DateTime | MysqlType::Timestamp => {
let ptr = self.raw.as_ptr() as *const MysqlTime;
let result = unsafe { ptr.read_unaligned() };
if result.neg {
Err("Negative dates/times are not yet supported".into())
} else {
Ok(result)
}
}
_ => Err(self.invalid_type_code("timestamp")),
}
}
pub(crate) fn numeric_value(&self) -> deserialize::Result<NumericRepresentation<'_>> {
use std::convert::TryInto;
Ok(match self.tpe {
MysqlType::UnsignedTiny | MysqlType::Tiny => {
NumericRepresentation::Tiny(self.raw[0] as i8)
}
MysqlType::UnsignedShort | MysqlType::Short => {
NumericRepresentation::Small(i16::from_ne_bytes((&self.raw[..2]).try_into()?))
}
MysqlType::UnsignedLong | MysqlType::Long => {
NumericRepresentation::Medium(i32::from_ne_bytes((&self.raw[..4]).try_into()?))
}
MysqlType::UnsignedLongLong | MysqlType::LongLong => {
NumericRepresentation::Big(i64::from_ne_bytes(self.raw.try_into()?))
}
MysqlType::Float => {
NumericRepresentation::Float(f32::from_ne_bytes(self.raw.try_into()?))
}
MysqlType::Double => {
NumericRepresentation::Double(f64::from_ne_bytes(self.raw.try_into()?))
}
MysqlType::Numeric => NumericRepresentation::Decimal(self.raw),
_ => return Err(self.invalid_type_code("number")),
})
}
fn invalid_type_code(&self, expected: &str) -> Box<dyn Error + Send + Sync> {
format!(
"Invalid representation received for {}: {:?}",
expected, self.tpe
)
.into()
}
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum NumericRepresentation<'a> {
Tiny(i8),
Small(i16),
Medium(i32),
Big(i64),
Float(f32),
Double(f64),
Decimal(&'a [u8]),
}