use std::{
borrow::Cow,
cmp::min,
io::{self},
};
use bytes::BufMut;
use saturating::Saturating as S;
use crate::{
binlog::{
BinlogCtx, BinlogEvent, BinlogStruct,
consts::{BinlogVersion, EventType, UserVarFlags},
},
constants::{ItemResult, UnknownItemResultType},
io::ParseBuf,
misc::raw::{RawBytes, RawConst, RawFlags, bytes::U32Bytes, int::*},
proto::{MyDeserialize, MySerialize},
};
use super::BinlogEventHeader;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct UserVarEvent<'a> {
name: RawBytes<'a, U32Bytes>,
is_null: bool,
value_type: RawConst<i8, ItemResult>,
charset: RawInt<LeU32>,
value: RawBytes<'a, U32Bytes>,
flags: RawFlags<UserVarFlags, u8>,
}
impl<'a> UserVarEvent<'a> {
pub fn name_raw(&'a self) -> &'a [u8] {
self.name.as_bytes()
}
pub fn name(&'a self) -> Cow<'a, str> {
self.name.as_str()
}
pub fn is_null(&self) -> bool {
self.is_null
}
pub fn value_type(&self) -> Result<ItemResult, UnknownItemResultType> {
self.value_type.get()
}
pub fn charset(&self) -> u32 {
self.charset.0
}
pub fn value(&'a self) -> &'a [u8] {
self.value.as_bytes()
}
pub fn flags_raw(&self) -> u8 {
self.flags.0
}
pub fn flags(&self) -> UserVarFlags {
self.flags.get()
}
pub fn into_owned(self) -> UserVarEvent<'static> {
UserVarEvent {
name: self.name.into_owned(),
is_null: self.is_null,
value_type: self.value_type,
charset: self.charset,
value: self.value.into_owned(),
flags: self.flags,
}
}
}
impl<'de> MyDeserialize<'de> for UserVarEvent<'de> {
const SIZE: Option<usize> = None;
type Ctx = BinlogCtx<'de>;
fn deserialize(_ctx: Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
let name = buf.parse(())?;
let is_null = buf.parse::<RawInt<u8>>(())?.0 != 0;
if is_null {
return Ok(Self {
name,
is_null,
value_type: RawConst::new(ItemResult::STRING_RESULT as i8),
charset: RawInt::new(63),
value: RawBytes::default(),
flags: RawFlags::default(),
});
}
let mut sbuf: ParseBuf<'_> = buf.parse(5)?;
let value_type = sbuf.parse_unchecked(())?;
let charset = sbuf.parse_unchecked(())?;
let value = buf.parse(())?;
let flags = if !buf.is_empty() {
buf.parse_unchecked(())?
} else {
Default::default()
};
Ok(Self {
name,
is_null,
value_type,
charset,
value,
flags,
})
}
}
impl MySerialize for UserVarEvent<'_> {
fn serialize(&self, buf: &mut Vec<u8>) {
self.name.serialize(&mut *buf);
buf.put_u8(self.is_null as u8);
if !self.is_null {
self.value_type.serialize(&mut *buf);
self.charset.serialize(&mut *buf);
self.value.serialize(&mut *buf);
self.flags.serialize(&mut *buf);
}
}
}
impl<'a> BinlogEvent<'a> for UserVarEvent<'a> {
const EVENT_TYPE: EventType = EventType::USER_VAR_EVENT;
}
impl<'a> BinlogStruct<'a> for UserVarEvent<'a> {
fn len(&self, _version: BinlogVersion) -> usize {
let mut len = S(0);
len += S(4);
len += S(min(self.name.0.len(), u32::MAX as usize));
len += S(1);
if !self.is_null {
len += S(1);
len += S(4);
len += S(4);
len += S(min(self.value.len(), u32::MAX as usize));
len += S(1);
}
min(len.0, u32::MAX as usize - BinlogEventHeader::LEN)
}
}