pso2packetlib 0.5.0

A library for working with the PSO2 network protocol
Documentation
use crate::{asciistring::StringRW, AsciiString};

use super::{read_magic, write_magic, HelperReadWrite, PacketError};
use half::f16;
use std::{net::Ipv4Addr, time::Duration};

macro_rules! helper_int {
    ($name:ty; $read:ident, $write:ident) => {
        impl HelperReadWrite for $name {
            fn read(
                reader: &mut (impl std::io::Read + std::io::Seek),
                _: super::PacketType,
                _: u32,
                _: u32,
            ) -> Result<Self, super::PacketError> {
                let mut buf = [0; std::mem::size_of::<$name>()];
                reader
                    .read_exact(&mut buf)
                    .map_err(|e| PacketError::FieldError {
                        packet_name: stringify!($name),
                        field_name: "value",
                        error: e,
                    })?;
                Ok(<$name>::$read(buf))
            }

            fn write(
                &self,
                writer: &mut impl std::io::Write,
                _: super::PacketType,
                _: u32,
                _: u32,
            ) -> Result<(), super::PacketError> {
                let buf = self.$write();
                writer.write_all(&buf).map_err(|e| PacketError::FieldError {
                    packet_name: stringify!($name),
                    field_name: "value",
                    error: e,
                })
            }
        }
    };
    ($name:ty, $($name_r:ty),+;$read:ident, $write:ident) => {
        helper_int!($name; $read, $write);
        helper_int!($($name_r),+; $read, $write);
    };
}

helper_int!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f16, f32, f64; from_le_bytes, to_le_bytes);
helper_int!(Ipv4Addr; from, octets);

impl<T: HelperReadWrite> HelperReadWrite for Box<T> {
    fn read(
        reader: &mut (impl std::io::Read + std::io::Seek),
        packet_type: super::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<Self, PacketError> {
        T::read(reader, packet_type, xor, sub).map(Box::new)
    }

    fn write(
        &self,
        writer: &mut impl std::io::Write,
        packet_type: super::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<(), PacketError> {
        self.as_ref().write(writer, packet_type, xor, sub)
    }
}

impl<T: HelperReadWrite, const N: usize> HelperReadWrite for [T; N] {
    fn read(
        reader: &mut (impl std::io::Read + std::io::Seek),
        packet_type: super::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<Self, PacketError> {
        let mut arr = vec![];
        arr.reserve_exact(N);

        for _ in 0..N {
            arr.push(T::read(reader, packet_type, xor, sub).map_err(|e| {
                PacketError::CompositeFieldError {
                    packet_name: "array",
                    field_name: "value",
                    error: e.into(),
                }
            })?);
        }

        if let Ok(arr) = arr.try_into() {
            Ok(arr)
        } else {
            unreachable!()
        }
    }

    fn write(
        &self,
        writer: &mut impl std::io::Write,
        packet_type: super::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<(), PacketError> {
        for i in self {
            i.write(writer, packet_type, xor, sub).map_err(|e| {
                PacketError::CompositeFieldError {
                    packet_name: "array",
                    field_name: "value",
                    error: e.into(),
                }
            })?;
        }
        Ok(())
    }
}

impl HelperReadWrite for Duration {
    fn read(
        reader: &mut (impl std::io::Read + std::io::Seek),
        packet_type: crate::protocol::PacketType,
        _: u32,
        _: u32,
    ) -> Result<Self, crate::protocol::PacketError> {
        Ok(Duration::from_secs(
            u32::read(reader, packet_type, 0, 0).map_err(|e| PacketError::CompositeFieldError {
                packet_name: "WinTime",
                field_name: "time",
                error: e.into(),
            })? as u64,
        ))
    }

    fn write(
        &self,
        writer: &mut impl std::io::Write,
        packet_type: crate::protocol::PacketType,
        _: u32,
        _: u32,
    ) -> Result<(), crate::protocol::PacketError> {
        (self.as_secs() as u32)
            .write(writer, packet_type, 0, 0)
            .map_err(|e| PacketError::CompositeFieldError {
                packet_name: "WinTime",
                field_name: "time",
                error: e.into(),
            })
    }
}

impl HelperReadWrite for String {
    fn read(
        reader: &mut (impl std::io::Read + std::io::Seek),
        _: crate::protocol::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<Self, crate::protocol::PacketError> {
        <String as StringRW>::read_variable(reader, sub, xor).map_err(|e| PacketError::FieldError {
            packet_name: "String",
            field_name: "str",
            error: e,
        })
    }

    fn write(
        &self,
        writer: &mut impl std::io::Write,
        _: crate::protocol::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<(), crate::protocol::PacketError> {
        writer
            .write_all(&self.write_variable(sub, xor))
            .map_err(|e| PacketError::FieldError {
                packet_name: "String",
                field_name: "str",
                error: e,
            })
    }
}

impl HelperReadWrite for AsciiString {
    fn read(
        reader: &mut (impl std::io::Read + std::io::Seek),
        _: crate::protocol::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<Self, crate::protocol::PacketError> {
        <AsciiString as StringRW>::read_variable(reader, sub, xor).map_err(|e| {
            PacketError::FieldError {
                packet_name: "AsciiString",
                field_name: "str",
                error: e,
            }
        })
    }

    fn write(
        &self,
        writer: &mut impl std::io::Write,
        _: crate::protocol::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<(), crate::protocol::PacketError> {
        writer
            .write_all(&self.write_variable(sub, xor))
            .map_err(|e| PacketError::FieldError {
                packet_name: "AsciiString",
                field_name: "str",
                error: e,
            })
    }
}

impl<T: HelperReadWrite> HelperReadWrite for Vec<T> {
    fn read(
        reader: &mut (impl std::io::Read + std::io::Seek),
        packet_type: crate::protocol::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<Self, crate::protocol::PacketError> {
        let len = read_magic(reader, sub, xor).map_err(|e| PacketError::FieldError {
            packet_name: "Vec",
            field_name: "len",
            error: e,
        })?;
        let mut data = vec![];
        data.reserve_exact(len as usize);

        let seek1 = reader
            .stream_position()
            .map_err(|e| PacketError::PaddingError {
                packet_name: "Vec",
                field_name: "pre_read",
                error: e,
            })?;
        for _ in 0..len {
            data.push(T::read(reader, packet_type, xor, sub).map_err(|e| {
                PacketError::CompositeFieldError {
                    packet_name: "Vec",
                    field_name: "value",
                    error: e.into(),
                }
            })?);
        }
        let seek2 = reader
            .stream_position()
            .map_err(|e| PacketError::PaddingError {
                packet_name: "Vec",
                field_name: "post_read",
                error: e,
            })?;
        let len = (seek2 - seek1) as usize;
        reader
            .seek(std::io::SeekFrom::Current(
                (len.next_multiple_of(4) - len) as i64,
            ))
            .map_err(|e| PacketError::PaddingError {
                packet_name: "Vec",
                field_name: "padding",
                error: e,
            })?;
        Ok(data)
    }

    fn write(
        &self,
        writer: &mut impl std::io::Write,
        packet_type: crate::protocol::PacketType,
        xor: u32,
        sub: u32,
    ) -> Result<(), crate::protocol::PacketError> {
        (write_magic(self.len() as u32, sub, xor))
            .write(writer, packet_type, xor, sub)
            .map_err(|e| PacketError::CompositeFieldError {
                packet_name: "Vec",
                field_name: "len",
                error: e.into(),
            })?;
        let mut buf = vec![];
        for i in self.iter() {
            i.write(&mut buf, packet_type, xor, sub).map_err(|e| {
                PacketError::CompositeFieldError {
                    packet_name: "Vec",
                    field_name: "value",
                    error: e.into(),
                }
            })?;
        }
        let len = buf.len();
        writer
            .write_all(&buf)
            .map_err(|e| PacketError::FieldError {
                packet_name: "Vec",
                field_name: "value",
                error: e,
            })?;
        writer
            .write_all(&vec![0; len.next_multiple_of(4) - len])
            .map_err(|e| PacketError::PaddingError {
                packet_name: "Vec",
                field_name: "padding",
                error: e,
            })?;

        Ok(())
    }
}