use crate::{
bind::{Bind, BindResult, Writer},
constants::type_,
decode::{Column, Decode},
package_parser::{DecodeError, DecodeResult, PackageParser},
};
macro_rules! new_type_str {
( $b:ident, $o:ident, $name: ident) => {
#[doc = concat!("Type that represents a Mysql/Mariadb [type_::", stringify!($name), "]")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
#[repr(transparent)]
pub struct $b(str);
impl $b {
pub fn as_str(&self) -> &str {
self.into()
}
pub const fn new(v: &str) -> &$b {
unsafe { std::mem::transmute(v) }
}
}
impl std::borrow::ToOwned for $b {
type Owned = $o;
fn to_owned(&self) -> Self::Owned {
$o(self.0.to_owned())
}
}
impl<'a> From<&'a str> for &'a $b {
fn from(v: &'a str) -> Self {
unsafe { std::mem::transmute(v) }
}
}
impl<'a> From<&'a $b> for &'a str {
fn from(v: &'a $b) -> Self {
unsafe { std::mem::transmute(v) }
}
}
#[doc = concat!("Type that represents an owned Mysql/Mariadb [type_::", stringify!($name), "]")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
#[repr(transparent)]
pub struct $o(String);
impl $o {
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl std::borrow::Borrow<$b> for $o {
fn borrow(&self) -> &$b {
let v: &str = self.0.borrow();
v.into()
}
}
impl From<String> for $o {
fn from(v: String) -> Self {
$o(v)
}
}
impl From<$o> for String {
fn from(v: $o) -> Self {
v.0
}
}
impl Bind for $o {
const TYPE: u8 = <&$b as Bind>::TYPE;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
std::borrow::Borrow::<$b>::borrow(self).bind(writer)
}
}
impl<'a> Decode<'a> for $o {
fn decode_none_null(parser: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
let v: &'a $b = Decode::decode_none_null(parser, c)?;
Ok(v.to_owned())
}
}
};
}
macro_rules! new_type_bytes {
( $b:ident, $o:ident, $name: ident) => {
#[doc = concat!("Type that represents a Mysql/Mariadb [type_::", stringify!($name), "]")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
#[repr(transparent)]
pub struct $b([u8]);
impl $b {
pub fn as_bytes(&self) -> &[u8] {
self.into()
}
pub const fn new(v: &[u8]) -> &$b {
unsafe { std::mem::transmute(v) }
}
}
impl std::borrow::ToOwned for $b {
type Owned = $o;
fn to_owned(&self) -> Self::Owned {
$o(self.0.to_owned())
}
}
impl<'a> From<&'a [u8]> for &'a $b {
fn from(v: &'a [u8]) -> Self {
unsafe { std::mem::transmute(v) }
}
}
impl<'a> From<&'a $b> for &'a [u8] {
fn from(v: &'a $b) -> Self {
unsafe { std::mem::transmute(v) }
}
}
#[doc = concat!("Type that represents an owned Mysql/Mariadb [type_::", stringify!($name), "]")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
#[repr(transparent)]
pub struct $o(Vec<u8>);
impl $o {
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl std::borrow::Borrow<$b> for $o {
fn borrow(&self) -> &$b {
let v: &[u8] = self.0.borrow();
v.into()
}
}
impl From<Vec<u8>> for $o {
fn from(v: Vec<u8>) -> Self {
$o(v)
}
}
impl From<$o> for Vec<u8> {
fn from(v: $o) -> Self {
v.0
}
}
impl Bind for $o {
const TYPE: u8 = <&$b as Bind>::TYPE;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
std::borrow::Borrow::<$b>::borrow(self).bind(writer)
}
}
impl<'a> Decode<'a> for $o {
fn decode_none_null(parser: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
let v: &'a $b = Decode::decode_none_null(parser, c)?;
Ok(v.to_owned())
}
}
};
}
new_type_str!(Decimal, OwnedDecimal, DECIMAL);
impl Bind for &Decimal {
const TYPE: u8 = type_::DECIMAL;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
writer.put_lenenc(self.as_str().len() as u64);
writer.put_slice(self.as_str().as_bytes());
Ok(true)
}
}
impl<'a> Decode<'a> for &'a Decimal {
fn decode_none_null(parser: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::NEW_DECIMAL && c.r#type != type_::DECIMAL {
return Err(DecodeError::TypeError {
expected: type_::NEW_DECIMAL,
got: c.r#type,
});
}
Ok(parser.get_lenenc_str()?.into())
}
}
new_type_str!(Json, OwnedJson, JSON);
impl Bind for &Json {
const TYPE: u8 = type_::STRING;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
writer.put_lenenc(self.as_str().len() as u64);
writer.put_slice(self.as_str().as_bytes());
Ok(true)
}
}
impl<'a> Decode<'a> for &'a Json {
fn decode_none_null(parser: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::JSON
&& c.r#type != type_::STRING
&& !(c.r#type == type_::BLOB && c.character_set != 63)
{
return Err(DecodeError::TypeError {
expected: type_::JSON,
got: c.r#type,
});
}
Ok(parser.get_lenenc_str()?.into())
}
}
new_type_bytes!(Bit, OwnedBits, BIT);
impl Bind for &Bit {
const TYPE: u8 = type_::BLOB;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
writer.put_lenenc(self.as_bytes().len() as u64);
writer.put_slice(self.as_bytes());
Ok(true)
}
}
impl<'a> Decode<'a> for &'a Bit {
fn decode_none_null(parser: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::BIT {
return Err(DecodeError::TypeError {
expected: type_::BIT,
got: c.r#type,
});
}
Ok(parser.get_lenenc_blob()?.into())
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct Year(i16);
impl Year {
pub const fn new(v: i16) -> Self {
Year(v)
}
}
impl From<i16> for Year {
fn from(value: i16) -> Self {
Year(value)
}
}
impl From<Year> for i16 {
fn from(value: Year) -> Self {
value.0
}
}
impl Bind for Year {
const TYPE: u8 = type_::SHORT;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
writer.put_i16(self.0);
Ok(true)
}
}
impl<'a> Decode<'a> for Year {
fn decode_none_null(parser: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::YEAR {
return Err(DecodeError::TypeError {
expected: type_::YEAR,
got: c.r#type,
});
}
Ok(parser.get_i16()?.into())
}
}
#[derive(PartialEq, Eq, Debug, Default)]
pub struct Time {
pub positive: bool,
pub days: u32,
pub hours: u8,
pub minutes: u8,
pub seconds: u8,
pub microseconds: u32,
}
impl Bind for Time {
const TYPE: u8 = type_::TIME;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
writer.put_u8(if self.microseconds == 0 { 8 } else { 12 });
writer.put_u8(if self.positive { 0 } else { 1 });
writer.put_u32(self.days);
writer.put_u8(self.hours);
writer.put_u8(self.minutes);
writer.put_u8(self.seconds);
if self.microseconds != 0 {
writer.put_u32(self.microseconds);
}
Ok(true)
}
}
impl<'a> Decode<'a> for Time {
fn decode_none_null(parser: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::TIME {
return Err(DecodeError::TypeError {
expected: type_::TIME,
got: c.r#type,
});
}
let long = match parser.get_u8()? {
0 => {
return Ok(Time {
positive: true,
..Default::default()
});
}
8 => false,
12 => true,
len => return Err(DecodeError::InvalidSize(len)),
};
let positive = parser.get_u8()? == 0;
let days = parser.get_u32()?;
let hours = parser.get_u8()?;
let minutes = parser.get_u8()?;
let seconds = parser.get_u8()?;
let microseconds = if long { parser.get_u32()? } else { 0 };
Ok(Time {
positive,
days,
hours,
minutes,
seconds,
microseconds,
})
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct Timestamp {
pub year: i16,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
pub msec: u32,
}
impl Bind for Timestamp {
const TYPE: u8 = type_::TIMESTAMP;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
writer.put_u8(if self.msec == 0 { 7 } else { 11 });
writer.put_i16(self.year);
writer.put_u8(self.month);
writer.put_u8(self.day);
writer.put_u8(self.hour);
writer.put_u8(self.minute);
writer.put_u8(self.second);
if self.msec != 0 {
writer.put_u32(self.msec);
}
Ok(true)
}
}
impl<'a> Decode<'a> for Timestamp {
fn decode_none_null(p: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::TIMESTAMP {
return Err(DecodeError::TypeError {
expected: type_::TIMESTAMP,
got: c.r#type,
});
}
let len = p.get_u8().unwrap();
match len {
0 => Ok(Timestamp {
year: 0,
month: 0,
day: 0,
hour: 0,
minute: 0,
second: 0,
msec: 0,
}),
4 => {
let year = p.get_i16().unwrap();
let month = p.get_u8().unwrap();
let day = p.get_u8().unwrap();
Ok(Timestamp {
year,
month,
day,
hour: 0,
minute: 0,
second: 0,
msec: 0,
})
}
7 => {
let year = p.get_i16().unwrap();
let month = p.get_u8().unwrap();
let day = p.get_u8().unwrap();
let hour = p.get_u8().unwrap();
let minute = p.get_u8().unwrap();
let second = p.get_u8().unwrap();
Ok(Timestamp {
year,
month,
day,
hour,
minute,
second,
msec: 0,
})
}
11 => {
let year = p.get_i16().unwrap();
let month = p.get_u8().unwrap();
let day = p.get_u8().unwrap();
let hour = p.get_u8().unwrap();
let minute = p.get_u8().unwrap();
let second = p.get_u8().unwrap();
let msec = p.get_u32().unwrap();
Ok(Timestamp {
year,
month,
day,
hour,
minute,
second,
msec,
})
}
_ => Err(DecodeError::InvalidSize(len)),
}
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct DateTime {
pub year: i16,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
pub msec: u32,
}
impl Bind for DateTime {
const TYPE: u8 = type_::DATETIME;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
let ts = Timestamp {
year: self.year,
month: self.month,
day: self.day,
hour: self.hour,
minute: self.minute,
second: self.second,
msec: self.msec,
};
let ts = &ts;
ts.bind(writer)
}
}
impl<'a> Decode<'a> for DateTime {
fn decode_none_null(p: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::DATE && c.r#type != type_::DATETIME {
return Err(DecodeError::TypeError {
expected: type_::DATETIME,
got: c.r#type,
});
}
let len = p.get_u8().unwrap();
match len {
0 => Ok(DateTime {
year: 0,
month: 0,
day: 0,
hour: 0,
minute: 0,
second: 0,
msec: 0,
}),
4 => {
let year = p.get_i16().unwrap();
let month = p.get_u8().unwrap();
let day = p.get_u8().unwrap();
Ok(DateTime {
year,
month,
day,
hour: 0,
minute: 0,
second: 0,
msec: 0,
})
}
7 => {
let year = p.get_i16().unwrap();
let month = p.get_u8().unwrap();
let day = p.get_u8().unwrap();
let hour = p.get_u8().unwrap();
let minute = p.get_u8().unwrap();
let second = p.get_u8().unwrap();
Ok(DateTime {
year,
month,
day,
hour,
minute,
second,
msec: 0,
})
}
11 => {
let year = p.get_i16().unwrap();
let month = p.get_u8().unwrap();
let day = p.get_u8().unwrap();
let hour = p.get_u8().unwrap();
let minute = p.get_u8().unwrap();
let second = p.get_u8().unwrap();
let msec = p.get_u32().unwrap();
Ok(DateTime {
year,
month,
day,
hour,
minute,
second,
msec,
})
}
_ => Err(DecodeError::InvalidSize(len)),
}
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct Date {
pub year: i16,
pub month: u8,
pub day: u8,
}
impl Bind for Date {
const TYPE: u8 = type_::DATE;
#[inline]
fn bind(&self, writer: &mut Writer<'_>) -> BindResult<bool> {
writer.put_u8(4);
writer.put_i16(self.year);
writer.put_u8(self.month);
writer.put_u8(self.day);
Ok(true)
}
}
impl<'a> Decode<'a> for Date {
fn decode_none_null(p: &mut PackageParser<'a>, c: &Column) -> DecodeResult<Self> {
if c.r#type != type_::DATE {
return Err(DecodeError::TypeError {
expected: type_::DATE,
got: c.r#type,
});
}
let len = p.get_u8().unwrap();
match len {
0 => Ok(Date {
year: 0,
month: 0,
day: 0,
}),
4 => {
let year = p.get_i16().unwrap();
let month = p.get_u8().unwrap();
let day = p.get_u8().unwrap();
Ok(Date { year, month, day })
}
_ => Err(DecodeError::InvalidSize(len)),
}
}
}