use std::io::{self, Read, Write};
use crate::util::io::*;
pub mod login;
pub mod reply;
pub mod base;
pub mod client;
pub mod entity;
pub trait Element: Sized {
type Config;
fn encode(&self, write: &mut impl Write, config: &Self::Config) -> io::Result<()>;
fn decode(read: &mut impl Read, len: usize, config: &Self::Config) -> io::Result<Self>;
}
pub trait TopElement: Element {
const LEN: ElementLength;
}
pub trait SimpleElement: Sized {
fn encode(&self, write: &mut impl Write) -> io::Result<()>;
fn decode(read: &mut impl Read, len: usize) -> io::Result<Self>;
}
impl<E: SimpleElement> Element for E {
type Config = ();
#[inline]
fn encode(&self, write: &mut impl Write, _config: &Self::Config) -> io::Result<()> {
SimpleElement::encode(self, write)
}
#[inline]
fn decode(read: &mut impl Read, len: usize, _config: &Self::Config) -> io::Result<Self> {
SimpleElement::decode(read, len)
}
}
pub trait NoopElement: Default {}
impl<E: NoopElement> SimpleElement for E {
fn encode(&self, _write: &mut impl Write) -> io::Result<()> {
Ok(())
}
fn decode(_read: &mut impl Read, _len: usize) -> io::Result<Self> {
Ok(Self::default())
}
}
impl NoopElement for () { }
impl TopElement for () {
const LEN: ElementLength = ElementLength::Fixed(0);
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum ElementLength {
Fixed(u32),
Variable8,
Variable16,
Variable24,
Variable32,
Callback(fn(id: u8) -> ElementLength),
}
impl ElementLength {
pub fn read(mut self, mut reader: impl Read, id: u8) -> std::io::Result<u32> {
if let Self::Callback(cb) = self {
self = cb(id);
}
match self {
Self::Fixed(len) => Ok(len),
Self::Variable8 => reader.read_u8().map(|n| n as u32),
Self::Variable16 => reader.read_u16().map(|n| n as u32),
Self::Variable24 => reader.read_u24().map(|n| n),
Self::Variable32 => reader.read_u32().map(|n| n),
Self::Callback(_) => panic!("cyclic callback")
}
}
pub fn write(self, mut writer: impl Write, len: u32) -> std::io::Result<()> {
match self {
Self::Fixed(expected_len) => {
assert_eq!(expected_len, len);
Ok(())
}
Self::Variable8 => writer.write_u8(len as u8),
Self::Variable16 => writer.write_u16(len as u16),
Self::Variable24 => writer.write_u24(len),
Self::Variable32 => writer.write_u32(len),
Self::Callback(_) => Ok(())
}
}
pub fn len(&self) -> usize {
match self {
Self::Fixed(_) => 0,
Self::Variable8 => 1,
Self::Variable16 => 2,
Self::Variable24 => 3,
Self::Variable32 => 4,
Self::Callback(_) => 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ElementIdRange {
pub first: u8,
pub last: u8,
}
impl ElementIdRange {
pub const fn new(first: u8, last: u8) -> Self {
Self { first, last }
}
#[inline]
pub const fn slots_count(self) -> u8 {
self.last - self.first + 1
}
#[inline]
pub const fn sub_slots_count(self, exposed_count: u16) -> u8 {
let excess_count = exposed_count as i32 - self.slots_count() as i32;
if excess_count > 0 {
(excess_count / 255 + 1) as u8
} else {
0
}
}
#[inline]
pub const fn full_slots_count(self, exposed_count: u16) -> u8 {
self.slots_count() - self.sub_slots_count(exposed_count)
}
pub fn from_exposed_id(self, exposed_count: u16, exposed_id: u16) -> (u8, Option<u8>) {
let full_slots = self.full_slots_count(exposed_count);
if exposed_id < full_slots as u16 {
(self.first + exposed_id as u8, None)
} else {
let overflow = exposed_id - full_slots as u16;
let first_sub_slot = self.first + full_slots;
((first_sub_slot as u16 + overflow / 256) as u8, Some((overflow % 256) as u8))
}
}
pub fn to_exposed_id_checked(self, exposed_count: u16, element_id: u8) -> Option<u16> {
let raw_exposed_id = element_id - self.first;
(raw_exposed_id < self.full_slots_count(exposed_count)).then_some(raw_exposed_id as u16)
}
pub fn to_exposed_id(self, exposed_count: u16, element_id: u8, sub_id_getter: impl FnOnce() -> u8) -> u16 {
let exposed_id = element_id - self.first;
let full_slots = self.full_slots_count(exposed_count);
if exposed_id < full_slots {
exposed_id as u16
} else {
let offset_id = exposed_id - full_slots;
let sub_id = sub_id_getter();
full_slots as u16 + 256 * offset_id as u16 + sub_id as u16
}
}
}