use std::collections::HashMap;
use std::io::{Cursor, Read};
use crate::Element;
use crate::error::{TychoError, TychoResult};
use crate::read::func::{read_byte, read_bytes};
use crate::read::length::read_length;
use crate::read::string::read_tstring;
use crate::read::value::{read_value, read_value_ident};
use crate::types::ident::{ElementIdent, ValueIdent};
#[cfg(feature="compression")]
use crate::read::compress::decompress;
pub(crate) fn read_element_ident<R: Read>(reader: &mut R) -> TychoResult<ElementIdent> {
parse_element_ident(read_byte(reader)?)
}
pub(crate) fn parse_element_ident(byte: u8) -> TychoResult<ElementIdent> {
match byte {
0x00 => Ok(ElementIdent::Unit),
0x01 => Ok(ElementIdent::Value),
0x02 => Ok(ElementIdent::None),
0x03 => Ok(ElementIdent::Some),
0x04 => Ok(ElementIdent::Variant),
0x05 => Ok(ElementIdent::Struct),
0x06 => Ok(ElementIdent::List),
0x07 => Ok(ElementIdent::Array),
0x08 => Ok(ElementIdent::Map),
0xF0 => Ok(ElementIdent::Compression),
_ => Err(TychoError::InvalidIdent { found: byte, expecting: "element ident".to_string() })
}
}
pub(crate) fn read_element<R: Read>(reader: &mut R) -> TychoResult<Element> {
let ident = read_element_ident(reader)?;
match ident {
ElementIdent::Unit => Ok(Element::Unit),
ElementIdent::Value => {
let ident = read_value_ident(reader)?;
Ok(Element::Value(read_value(reader, &ident)?))
},
ElementIdent::Some => Ok(Element::Option(Some(Box::new(read_element(reader)?)))),
ElementIdent::None => Ok(Element::Option(None)),
ElementIdent::Variant => Ok(Element::Variant(
read_tstring(reader)?,
Box::new(read_element(reader)?)
)),
ElementIdent::Struct => {
let size = read_length(reader)?;
let mut items = HashMap::new();
let mut buffer = Cursor::new(read_bytes(reader, size)?);
loop {
if buffer.position() == size as u64 { break; }
let key = read_tstring(&mut buffer)?;
let value = read_element(&mut buffer)?;
items.insert(key, value);
}
Ok(Element::Struct(items))
}
ElementIdent::List => {
let size = read_length(reader)?;
let mut items = Vec::new();
let mut buffer = Cursor::new(read_bytes(reader, size)?);
loop {
if buffer.position() == size as u64 { break; }
items.push(read_element(&mut buffer)?);
}
Ok(Element::List(items))
},
ElementIdent::Array => {
let array_type = read_value_ident(reader)?;
if let ValueIdent::Null = &array_type {
Ok(Element::Array(ValueIdent::Null, Vec::new()))
} else {
let size = read_length(reader)?;
let mut items = Vec::new();
let mut buffer = Cursor::new(read_bytes(reader, size)?);
loop {
if buffer.position() == size as u64 { break; }
items.push(read_value(&mut buffer, &array_type)?);
}
Ok(Element::Array(array_type, items))
}
},
ElementIdent::Map => {
let key_type = read_value_ident(reader)?;
if let ValueIdent::Null = &key_type {
Ok(Element::Map(ValueIdent::Null, HashMap::new()))
} else {
let size = read_length(reader)?;
let mut items = HashMap::new();
let mut buffer = Cursor::new(read_bytes(reader, size)?);
loop {
if buffer.position() == size as u64 { break; }
let key = read_value(&mut buffer, &key_type)?;
let value = read_element(&mut buffer)?;
items.insert(key, value);
}
Ok(Element::Map(key_type, items))
}
},
ElementIdent::Compression => {
let size = read_length(reader)?;
let bytes = read_bytes(reader, size)?;
#[cfg(not(feature="compression"))]
return Ok(Element::Compression(bytes));
#[cfg(feature="compression")]
let mut buffer = Cursor::new(decompress(bytes)?);
#[cfg(feature="compression")]
return Ok(Element::Compression(Box::new(read_element(&mut buffer)?)))
}
}
}