use crate::codec::{Codec, CodecError, CodecResult, Reader};
use crate::tag::{TaggedValue, ValueType};
use std::borrow::Borrow;
use std::collections::HashMap;
use std::fmt::Debug;
use std::slice::Iter;
pub trait TdfGroup: Codec + Debug {
fn start_two() -> bool;
}
#[derive(Debug, PartialEq, Eq)]
pub struct VarInt(pub u64);
trait AsVarInt: PartialEq + Eq + Debug {
fn to_var_int(self) -> VarInt;
fn from_var_int(value: VarInt) -> Self;
}
macro_rules! into_var_int {
($($ty:ty),*) => {
$(
impl From<$ty> for VarInt {
fn from(value: $ty) -> VarInt {
VarInt(value as u64)
}
}
impl Into<$ty> for VarInt {
fn into(self) -> $ty {
self.0 as $ty
}
}
)*
};
}
macro_rules! as_var_int {
($($ty:ty),*) => {
$(
impl AsVarInt for $ty {
#[inline]
fn to_var_int(self) -> VarInt {
VarInt::from(self)
}
#[inline]
fn from_var_int(value: VarInt) -> $ty {
value.into()
}
}
)*
};
}
into_var_int!(i8, i16, i32, i64, u8, u16, u32, u64);
as_var_int!(i8, i16, i32, i64, u8, u16, u32, u64);
#[derive(Debug, PartialEq, Eq)]
pub struct VarIntList(pub Vec<VarInt>);
impl VarIntList {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
pub fn insert(&mut self, value: impl Into<VarInt>) {
self.0.push(value.into())
}
pub fn remove(&mut self, index: usize) -> Option<VarInt> {
if index < self.0.len() {
Some(self.0.remove(index))
} else {
None
}
}
pub fn get(&mut self, index: usize) -> Option<&VarInt> {
self.0.get(index)
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum TdfOptional<T: Codec> {
Some(u8, TaggedValue<T>),
None,
}
impl<T: Codec> TdfOptional<T> {
pub fn is_some(&self) -> bool {
matches!(self, Self::Some(_, _))
}
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
}
pub const EMPTY_OPTIONAL: u8 = 0x7F;
pub trait MapKey: PartialEq + Eq + Debug + Codec {}
impl MapKey for String {}
impl MapKey for VarInt {}
#[derive(Debug, Clone)]
pub struct TdfMap<K: MapKey, V: Codec> {
keys: Vec<K>,
values: Vec<V>,
}
impl<K: MapKey, V: Codec> Codec for TdfMap<K, V> {
fn encode(&self, output: &mut Vec<u8>) {
let key_type = K::value_type();
let value_type = V::value_type();
key_type.encode(output);
value_type.encode(output);
let size = self.len();
VarInt(size as u64).encode(output);
for (key, value) in self {
key.encode(output);
value.encode(output);
}
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let expected_key = K::value_type();
let expected_value = V::value_type();
let key_type = ValueType::decode(reader)?;
let value_type = ValueType::decode(reader)?;
if expected_key != key_type {
return Err(CodecError::UnexpectedType(expected_key, key_type));
}
if expected_value != value_type {
return Err(CodecError::UnexpectedType(expected_value, value_type));
}
let length = VarInt::decode(reader)?.0 as usize;
let mut map = TdfMap::with_capacity(length);
for _ in 0..length {
let key = K::decode(reader)?;
let value = V::decode(reader)?;
map.insert(key, value);
}
Ok(map)
}
fn value_type() -> ValueType {
ValueType::Map
}
}
impl<K: MapKey, V: Codec> From<HashMap<K, V>> for TdfMap<K, V> {
fn from(map: HashMap<K, V>) -> Self {
let mut keys = Vec::with_capacity(map.len());
let mut values = Vec::with_capacity(map.len());
for (key, value) in map {
keys.push(key);
values.push(value)
}
Self { keys, values }
}
}
impl<K: MapKey, V: Codec> TdfMap<K, V> {
pub fn new() -> TdfMap<K, V> {
Self {
keys: Vec::new(),
values: Vec::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
keys: Vec::with_capacity(capacity),
values: Vec::with_capacity(capacity),
}
}
pub fn insert(&mut self, key: impl Into<K>, value: impl Into<V>) {
self.keys.push(key.into());
self.values.push(value.into())
}
pub fn insert_multiple(&mut self, entries: impl IntoIterator<Item = (K, V)>) {
for (key, value) in entries {
self.keys.push(key);
self.values.push(value);
}
}
fn index_of_key<Q: ?Sized>(&self, key: &Q) -> Option<usize>
where
K: Borrow<Q>,
Q: Eq,
{
for i in 0..self.keys.len() {
let key_at = self.keys[i].borrow();
if key_at.eq(key) {
return Some(i);
}
}
None
}
pub fn remove(&mut self, key: &K) -> Option<(K, V)> {
let index = self.index_of_key(key)?;
let key = self.keys.remove(index);
let value = self.values.remove(index);
Some((key, value))
}
#[inline]
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Eq,
{
let index = self.index_of_key(key)?;
let value = self.values.get(index)?;
Some(value)
}
pub fn take(&mut self, key: &K) -> Option<V> {
let index = self.index_of_key(key)?;
let value = self.values.remove(index);
self.keys.remove(index);
Some(value)
}
pub fn keys(&self) -> Iter<'_, K> {
self.keys.iter()
}
pub fn values(&self) -> Iter<'_, V> {
self.values.iter()
}
pub fn len(&self) -> usize {
self.keys.len()
}
fn at_index(&self, index: usize) -> Option<(&K, &V)> {
let key = self.keys.get(index)?;
let value = self.values.get(index)?;
Some((key, value))
}
}
pub struct TdfMapIter<'a, K: MapKey, V: Codec> {
map: &'a TdfMap<K, V>,
index: usize,
}
impl<'a, K: MapKey, V: Codec> Iterator for TdfMapIter<'a, K, V> {
type Item = (&'a K, &'a V);
fn next(&mut self) -> Option<Self::Item> {
let value = self.map.at_index(self.index);
self.index += 1;
value
}
}
impl<'a, K: MapKey, V: Codec> IntoIterator for &'a TdfMap<K, V> {
type Item = (&'a K, &'a V);
type IntoIter = TdfMapIter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
TdfMapIter {
map: self,
index: 0,
}
}
}
impl Codec for f32 {
fn encode(&self, output: &mut Vec<u8>) {
let bytes: [u8; 4] = self.to_be_bytes();
output.extend_from_slice(&bytes);
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let bytes = reader.take(4)?;
Ok(f32::from_be_bytes(
bytes.try_into().map_err(|_| CodecError::UnknownError)?,
))
}
}
impl<T: AsVarInt + Copy> Codec for T {
fn encode(&self, output: &mut Vec<u8>) {
(*self).to_var_int().encode(output);
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let value = VarInt::decode(reader)?;
Ok(T::from_var_int(value))
}
fn value_type() -> ValueType {
ValueType::VarInt
}
}
impl Codec for VarInt {
fn encode(&self, output: &mut Vec<u8>) {
let value = self.0;
if value < 64 {
output.push(value as u8);
} else {
let mut cur_byte = ((value & 63) as u8) | 128;
output.push(cur_byte);
let mut cur_shift = value >> 6;
while cur_shift >= 128 {
cur_byte = ((cur_shift & 127) | 128) as u8;
cur_shift >>= 7;
output.push(cur_byte);
}
output.push(cur_shift as u8)
}
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let first = reader.take_one()?;
let mut result = (first & 63) as u64;
if first < 128 {
return Ok(VarInt(result));
}
let mut shift = 6;
let mut byte: u8;
loop {
byte = reader.take_one()?;
result |= ((byte & 127) as u64) << shift;
shift += 7;
if byte < 128 {
break;
}
}
Ok(VarInt(result))
}
fn value_type() -> ValueType {
ValueType::VarInt
}
}
impl Codec for String {
fn encode(&self, output: &mut Vec<u8>) {
let mut bytes = self.as_bytes().to_vec();
match bytes.last() {
Some(0) => {}
_ => bytes.push(0),
}
VarInt::encode(&VarInt(bytes.len() as u64), output);
output.extend_from_slice(&bytes);
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let length = VarInt::decode(reader)?.0 as usize;
let bytes = reader.take(length)?;
let text = String::from_utf8_lossy(bytes);
let mut text = text.to_string();
text.pop();
Ok(text)
}
fn value_type() -> ValueType {
ValueType::String
}
}
impl Codec for Vec<u8> {
fn encode(&self, output: &mut Vec<u8>) {
VarInt(self.len() as u64).encode(output);
output.extend_from_slice(self)
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let length = VarInt::decode(reader)?.0 as usize;
let bytes = reader.take(length)?;
Ok(bytes.to_vec())
}
fn value_type() -> ValueType {
ValueType::Blob
}
}
pub trait Listable: Codec {}
impl Listable for VarInt {}
impl Listable for String {}
impl Listable for (VarInt, VarInt, VarInt) {}
impl<T: Listable> Codec for Vec<T> {
fn encode(&self, output: &mut Vec<u8>) {
T::value_type().encode(output);
VarInt(self.len() as u64).encode(output);
for value in self {
value.encode(output);
}
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let value_type = ValueType::decode(reader)?;
let expected_type = T::value_type();
if value_type != expected_type {
return Err(CodecError::UnexpectedType(value_type, expected_type));
}
let length = VarInt::decode(reader)?.0 as usize;
let mut out = Vec::with_capacity(length);
for _ in 0..length {
out.push(T::decode(reader)?);
}
Ok(out)
}
fn value_type() -> ValueType {
ValueType::List
}
}
impl<T: Codec> Codec for TdfOptional<T> {
fn encode(&self, output: &mut Vec<u8>) {
match self {
TdfOptional::Some(ty, value) => {
output.push(*ty);
value.encode(output);
}
TdfOptional::None => output.push(EMPTY_OPTIONAL),
}
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let ty = reader.take_one()?;
Ok(if ty != 0x7F {
let value = TaggedValue::<T>::decode(reader)?;
TdfOptional::Some(ty, value)
} else {
TdfOptional::None
})
}
fn value_type() -> ValueType {
ValueType::Optional
}
}
impl Codec for VarIntList {
fn encode(&self, output: &mut Vec<u8>) {
VarInt(self.0.len() as u64).encode(output);
for value in &self.0 {
value.encode(output);
}
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let length = VarInt::decode(reader)?.0 as usize;
let mut out = Vec::with_capacity(length);
for _ in 0..length {
out.push(VarInt::decode(reader)?)
}
Ok(VarIntList(out))
}
fn value_type() -> ValueType {
ValueType::VarIntList
}
}
impl Codec for (VarInt, VarInt) {
fn encode(&self, output: &mut Vec<u8>) {
self.0.encode(output);
self.1.encode(output);
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let a = VarInt::decode(reader)?;
let b = VarInt::decode(reader)?;
Ok((a, b))
}
fn value_type() -> ValueType {
ValueType::Pair
}
}
impl Codec for (VarInt, VarInt, VarInt) {
fn encode(&self, output: &mut Vec<u8>) {
self.0.encode(output);
self.1.encode(output);
self.2.encode(output);
}
fn decode(reader: &mut Reader) -> CodecResult<Self> {
let a = VarInt::decode(reader)?;
let b = VarInt::decode(reader)?;
let c = VarInt::decode(reader)?;
Ok((a, b, c))
}
fn value_type() -> ValueType {
ValueType::Triple
}
}
#[cfg(test)]
mod test {
use crate::types::TdfMap;
#[test]
fn test() {
let mut map = TdfMap::<String, String>::new();
map.insert("Test", "Abc");
let value = map.get("Test");
assert_eq!(value.unwrap(), "Abc");
println!("{value:?}")
}
}