use std::collections::HashMap;
use std::hash::Hash;
use super::{JceError, JceHead, JceResult, JceType, JceValue};
use bytes::{Buf, Bytes};
pub struct Jce<'a, B>
where
B: Buf + ?Sized,
{
inner: &'a mut B,
pub head: JceHead,
readed: bool,
}
pub trait JceGet: Sized {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self>;
fn empty() -> JceResult<Self>;
fn get_from_buf<B: Buf + ?Sized>(buf: &mut B) -> JceResult<Self> {
let mut jce = Jce::new(buf);
Self::jce_get(&mut jce)
}
fn get_by_tag<B: Buf + ?Sized>(jce: &mut Jce<B>, tag: u8) -> JceResult<Self> {
jce.get_by_tag(tag)
}
fn from_buf<B: Buf + ?Sized>(buf: &mut B) -> JceResult<Self> {
let mut jce = Jce::new(buf);
Self::jce_get(&mut jce)
}
fn from_boxed_buf<B: Buf + ?Sized>(buf: &mut B) -> JceResult<Self> {
buf.advance(1);
let mut jce = Jce::new(buf);
Self::jce_get(&mut jce)
}
}
impl<'a, B> Jce<'a, B>
where
B: Buf + ?Sized,
{
pub fn new(inner: &'a mut B) -> Self {
let mut jce = Jce {
inner,
head: JceHead::default(),
readed: false,
};
jce.read_head();
jce
}
pub fn sub_jce<'b>(&'b mut self) -> Jce<'b, B> {
Jce::new(self.inner)
}
pub fn has_remaining(&self) -> bool {
self.inner.has_remaining()
}
pub fn read_head(&mut self) -> JceHead {
let byte = self.inner.get_u8();
let ty = JceType::from(byte & 0xF);
let mut tag = (byte & 0xF0) >> 4;
if tag == 15 {
let next_byte = self.inner.get_u8();
tag = next_byte & 0xFF;
}
let head = JceHead { ty, tag };
self.head = head;
self.readed = false;
head
}
pub fn pass_a_tag(&mut self) -> JceResult<()> {
if self.head.ty != JceType::StructEnd {
JceValue::jce_get(self).map(|_| ())
} else {
Ok(())
}
}
pub fn go_to_tag(&mut self, tag: u8) -> JceResult<()> {
if !self.readed {
self.pass_a_tag()?;
}
while self.read_head().tag != tag {
self.pass_a_tag()?;
if !self.inner.has_remaining() {
return Err(JceError::TagNotFound(tag));
}
}
Ok(())
}
pub fn get_by_tag<T>(&mut self, tag: u8) -> JceResult<T>
where
T: JceGet,
{
if self.head.tag != tag {
self.go_to_tag(tag)?;
}
self.readed = true;
T::jce_get(self)
}
pub fn end_struct(&mut self) -> JceResult<()> {
while self.read_head().ty != JceType::StructEnd {
self.pass_a_tag()?;
}
Ok(())
}
}
impl JceGet for bool {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
match jce.head.ty {
JceType::Bool | JceType::U8 => Ok(jce.inner.get_u8() != 0),
_ => Err(JceError::ReadTypeError(JceType::Bool, jce.head.ty)),
}
}
fn empty() -> JceResult<Self> {
panic!() }
}
impl JceGet for u8 {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
match jce.head.ty {
JceType::Empty => Self::empty(),
JceType::U8 => Ok(jce.inner.get_u8()),
_ => Err(JceError::ReadTypeError(JceType::U8, jce.head.ty)),
}
}
fn empty() -> JceResult<Self> {
Ok(0)
}
}
impl JceGet for i16 {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
match jce.head.ty {
JceType::U8 => u8::jce_get(jce).map(|i| i as i16),
JceType::I16 => Ok(jce.inner.get_i16()),
JceType::Empty => Self::empty(),
_ => Err(JceError::ReadTypeError(JceType::I16, jce.head.ty)),
}
}
fn empty() -> JceResult<Self> {
Ok(0)
}
}
impl JceGet for i32 {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
match jce.head.ty {
JceType::U8 => u8::jce_get(jce).map(|i| i as i32),
JceType::I16 => i16::jce_get(jce).map(|i| i as i32),
JceType::I32 => Ok(jce.inner.get_i32()),
JceType::Empty => Self::empty(),
_ => Err(JceError::ReadTypeError(JceType::I32, jce.head.ty)),
}
}
fn empty() -> JceResult<Self> {
Ok(0)
}
}
impl JceGet for i64 {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
match jce.head.ty {
JceType::U8 => u8::jce_get(jce).map(|i| i as i64),
JceType::I16 => i16::jce_get(jce).map(|i| i as i64),
JceType::I32 => i32::jce_get(jce).map(|i| i as i64),
JceType::I64 => Ok(jce.inner.get_i64()),
JceType::Empty => Self::empty(),
_ => Err(JceError::ReadTypeError(JceType::I64, jce.head.ty)),
}
}
fn empty() -> JceResult<Self> {
Ok(0)
}
}
impl JceGet for f32 {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
match jce.head.ty {
JceType::F32 => Ok(jce.inner.get_f32()),
JceType::Empty => Self::empty(),
_ => Err(JceError::ReadTypeError(JceType::F32, jce.head.ty)),
}
}
fn empty() -> JceResult<Self> {
Ok(0.0)
}
}
impl JceGet for f64 {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
match jce.head.ty {
JceType::F64 => Ok(jce.inner.get_f64()),
JceType::Empty => Self::empty(),
_ => Err(JceError::ReadTypeError(JceType::F64, jce.head.ty)),
}
}
fn empty() -> JceResult<Self> {
Ok(0.0)
}
}
impl JceGet for String {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
let len = match jce.head.ty {
JceType::ShortString => jce.inner.get_u8() as usize,
JceType::LongString => jce.inner.get_i32() as usize,
_ => {
return Err(JceError::ReadLenError(jce.head.ty));
}
};
if len == 0 {
Self::empty()
} else {
let data = jce.inner.copy_to_bytes(len);
String::from_utf8(data.to_vec()).map_err(|_| JceError::Utf8Error)
}
}
fn empty() -> JceResult<Self> {
Ok(String::default())
}
}
impl<K, V> JceGet for HashMap<K, V>
where
K: JceGet + Eq + Hash,
V: JceGet,
{
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
if jce.head.ty != JceType::Map {
return Err(JceError::ReadTypeError(JceType::Map, jce.head.ty));
}
let mut jce = jce.sub_jce();
let len = jce.get_by_tag::<i32>(0)? as usize;
let mut map = HashMap::with_capacity(len);
for _ in 0..len {
let mut jce = jce.sub_jce();
let key = jce.get_by_tag(0)?;
let value = jce.get_by_tag(1)?;
map.insert(key, value);
}
Ok(map)
}
fn empty() -> JceResult<Self> {
Ok(HashMap::new())
}
}
impl<V> JceGet for Vec<V>
where
V: JceGet,
{
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
if jce.head.ty != JceType::List {
return Err(JceError::ReadTypeError(JceType::List, jce.head.ty));
}
let mut jce = jce.sub_jce();
let len = jce.get_by_tag::<i32>(0)? as usize;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
let mut jce = jce.sub_jce();
let value = jce.get_by_tag(0)?;
vec.push(value);
}
Ok(vec)
}
fn empty() -> JceResult<Self> {
Ok(Vec::new())
}
}
impl JceGet for Bytes {
fn jce_get<B: Buf + ?Sized>(jce: &mut Jce<B>) -> JceResult<Self> {
jce.inner.get_u8();
let mut jce = jce.sub_jce();
let len = jce.get_by_tag::<i32>(0)? as usize;
Ok(jce.inner.copy_to_bytes(len))
}
fn empty() -> JceResult<Self> {
Ok(Bytes::default())
}
}