use std::vec::Vec;
use failure::Error;
use log::{error, trace};
use crate::error::ProtocolError;
use crate::primitive;
use crate::primitive::StringList;
use crate::{Deserialize, DeserializeUTF8};
use crate::{Serialize, SerializeUTF8};
extern crate bytes;
use crate::primitive::{BufferInfo, Date, DateTime, Message, Time, VariantList, VariantMap};
#[allow(non_camel_case_types, dead_code)]
#[derive(Clone, Debug, std::cmp::PartialEq)]
pub enum Variant {
Unknown,
UserType(String, Vec<u8>),
BufferInfo(BufferInfo),
Message(Message),
Time(Time),
Date(Date),
DateTime(DateTime),
VariantMap(VariantMap),
VariantList(VariantList),
String(String),
StringUTF8(String),
StringList(StringList),
bool(bool),
u64(u64),
u32(u32),
u16(u16),
u8(u8),
i64(i64),
i32(i32),
i16(i16),
i8(i8),
}
impl Serialize for Variant {
fn serialize(&self) -> Result<Vec<u8>, Error> {
let unknown: u8 = 0x00;
let mut res: Vec<u8> = Vec::new();
match self {
Variant::Unknown => {
bail!(ProtocolError::UnknownVariant);
}
Variant::VariantMap(v) => {
res.extend(primitive::QVARIANTMAP.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.serialize()?.iter());
}
Variant::VariantList(v) => {
res.extend(primitive::QVARIANTLIST.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.serialize()?.iter());
}
Variant::String(v) => {
res.extend(primitive::QSTRING.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.serialize()?.iter());
}
Variant::StringUTF8(v) => {
res.extend(primitive::QBYTEARRAY.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.serialize_utf8()?.iter());
}
Variant::StringList(v) => {
res.extend(primitive::QSTRINGLIST.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.serialize()?.iter());
}
Variant::bool(v) => {
res.extend(primitive::BOOL.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
let i = *v as i8;
res.extend(i.to_be_bytes().iter());
}
Variant::u64(v) => {
res.extend(primitive::ULONG.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::u32(v) => {
res.extend(primitive::UINT.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::u16(v) => {
res.extend(primitive::USHORT.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::u8(v) => {
res.extend(primitive::UCHAR.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::i64(v) => {
res.extend(primitive::LONG.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::i32(v) => {
res.extend(primitive::INT.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::i16(v) => {
res.extend(primitive::SHORT.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::i8(v) => {
res.extend(primitive::CHAR.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.extend(v.to_be_bytes().iter());
}
Variant::UserType(name, bytes) => {
res.extend(primitive::USERTYPE.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.append(&mut name.serialize_utf8()?);
res.extend(bytes);
}
Variant::BufferInfo(v) => {
let bytes = BufferInfo::serialize(v)?;
let user = Variant::UserType("BufferInfo".to_string(), bytes);
Variant::serialize(&user).unwrap();
}
Variant::Message(v) => {
let bytes = Message::serialize(v)?;
let user = Variant::UserType("Message".to_string(), bytes);
Variant::serialize(&user).unwrap();
}
Variant::DateTime(v) => {
res.extend(primitive::QDATETIME.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.append(&mut v.serialize()?);
}
Variant::Time(v) => {
res.extend(primitive::QTIME.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.append(&mut v.serialize()?);
}
Variant::Date(v) => {
res.extend(primitive::QDATE.to_be_bytes().iter());
res.extend(unknown.to_be_bytes().iter());
res.append(&mut v.serialize()?);
}
}
return Ok(res);
}
}
impl Deserialize for Variant {
fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
let (_, qtype) = i32::parse(&b[0..4])?;
let qtype = qtype as u32;
#[allow(unused_variables)]
let unknown: u8 = b[4];
let len = 5;
match qtype {
primitive::QVARIANTMAP => {
trace!(target: "primitive::Variant", "Parsing Variant: VariantMap");
let (vlen, value) = VariantMap::parse(&b[len..])?;
return Ok((len + vlen, Variant::VariantMap(value)));
}
primitive::QVARIANTLIST => {
trace!(target: "primitive::Variant", "Parsing Variant: VariantList");
let (vlen, value) = VariantList::parse(&b[len..])?;
return Ok((len + vlen, Variant::VariantList(value)));
}
primitive::QSTRING => {
trace!(target: "primitive::Variant", "Parsing Variant: String");
let (vlen, value) = String::parse(&b[len..])?;
return Ok((len + vlen, Variant::String(value.clone())));
}
primitive::QBYTEARRAY => {
trace!(target: "primitive::Variant", "Parsing Variant: ByteArray");
let (vlen, value) = String::parse_utf8(&b[len..])?;
return Ok((len + vlen, Variant::StringUTF8(value.clone())));
}
primitive::QSTRINGLIST => {
trace!(target: "primitive::Variant", "Parsing Variant: StringList");
let (vlen, value) = StringList::parse(&b[len..])?;
return Ok((len + vlen, Variant::StringList(value.clone())));
}
primitive::QDATETIME => {
trace!(target: "primitive::Variant", "Parsing Variant: Date");
let (vlen, value): (usize, DateTime) = Deserialize::parse(&b[len..])?;
return Ok((len + vlen, Variant::DateTime(value.clone())));
}
primitive::QDATE => {
trace!(target: "primitive::Variant", "Parsing Variant: Date");
let (vlen, value): (usize, Date) = Deserialize::parse(&b[len..])?;
return Ok((len + vlen, Variant::Date(value.clone())));
}
primitive::QTIME => {
trace!(target: "primitive::Variant", "Parsing Variant: Time");
let (vlen, value): (usize, Time) = Deserialize::parse(&b[len..])?;
return Ok((len + vlen, Variant::Time(value.clone())));
}
primitive::BOOL => {
let (vlen, value) = bool::parse(&b[len..])?;
return Ok((len + vlen, Variant::bool(value)));
}
primitive::ULONG => {
let (vlen, value) = u64::parse(&b[len..])?;
return Ok((len + vlen, Variant::u64(value)));
}
primitive::UINT => {
let (vlen, value) = u32::parse(&b[len..])?;
return Ok((len + vlen, Variant::u32(value)));
}
primitive::USHORT => {
let (vlen, value) = u16::parse(&b[len..])?;
return Ok((len + vlen, Variant::u16(value)));
}
primitive::UCHAR => {
let (vlen, value) = u8::parse(&b[len..])?;
return Ok((len + vlen, Variant::u8(value)));
}
primitive::LONG => {
let (vlen, value) = i64::parse(&b[len..])?;
return Ok((len + vlen, Variant::i64(value)));
}
primitive::INT => {
let (vlen, value) = i32::parse(&b[len..])?;
return Ok((len + vlen, Variant::i32(value)));
}
primitive::SHORT => {
let (vlen, value) = i16::parse(&b[len..])?;
return Ok((len + vlen, Variant::i16(value)));
}
primitive::CHAR => {
let (vlen, value) = i8::parse(&b[len..])?;
return Ok((len + vlen, Variant::i8(value)));
}
primitive::USERTYPE => {
trace!(target: "primitive::Variant", "Parsing UserType");
let (user_type_len, user_type) = String::parse_utf8(&b[len..])?;
trace!(target: "primitive::Variant", "Parsing UserType: {:?}", user_type);
match user_type.as_str() {
"IrcUser" | "IrcChannel" | "Identity" | "NetworkInfo" | "Network::Server" => {
trace!(target: "primitive::Variant", "UserType is VariantMap");
let (vlen, value) = VariantMap::parse(&b[(len + user_type_len)..])?;
return Ok((len + user_type_len + vlen, Variant::VariantMap(value)));
}
"BufferId" | "IdentityId" | "NetworkId" | "MsgId" => {
trace!(target: "primitive::Variant", "UserType is i32");
let (vlen, value) = i32::parse(&b[(len + user_type_len)..])?;
return Ok((len + user_type_len + vlen, Variant::i32(value)));
}
"PeerPtr" => {
trace!(target: "primitive::Variant", "UserType is i64");
let (vlen, value) = i64::parse(&b[(len + user_type_len)..])?;
return Ok((len + user_type_len + vlen, Variant::i64(value)));
}
"BufferInfo" => {
trace!(target: "primitive::Variant", "UserType is BufferInfo");
let (vlen, value) = BufferInfo::parse(&b[(len + user_type_len)..])?;
return Ok((len + user_type_len + vlen, Variant::BufferInfo(value)));
}
"Message" => {
trace!(target: "primitive::Variant", "UserType is Message");
let (vlen, value) = Message::parse(&b[(len + user_type_len)..])?;
return Ok((len + user_type_len + vlen, Variant::Message(value)));
}
_ => unimplemented!(),
}
}
err => {
error!(target: "parser", "UnknownVariant: {:x?}", err);
bail!(ProtocolError::UnknownVariant);
}
}
}
}