luanti_protocol/wire/
deser.rs

1use crate::types::CommandDirection;
2use crate::types::ProtocolContext;
3use anyhow::bail;
4use std::fmt::Debug;
5use std::num::ParseIntError;
6use std::str::Utf8Error;
7
8#[derive(Debug, thiserror::Error)]
9pub enum DeserializeError {
10    #[error("Bad Packet Type {0:?} type={1}")]
11    BadPacketId(CommandDirection, u16),
12    #[error("Invalid value: {0}")]
13    InvalidValue(String),
14    #[error("Invalid Protocol id: {0}")]
15    InvalidProtocolId(u32),
16    #[error("Invalid channel: {0}")]
17    InvalidChannel(u8),
18    #[error("Invalid Packet Kind: {0}")]
19    InvalidPacketKind(u8),
20    #[error("DecompressionFailed: {0}")]
21    DecompressionFailed(String),
22    #[error("OtherError: {0}")]
23    OtherError(String),
24    #[error("EOF during deserialization: {0}")]
25    Eof(String), // Data ended prematurely
26}
27
28impl From<Utf8Error> for DeserializeError {
29    fn from(other: Utf8Error) -> DeserializeError {
30        DeserializeError::InvalidValue(format!("Utf8Error {other:?}"))
31    }
32}
33
34impl From<ParseIntError> for DeserializeError {
35    fn from(other: ParseIntError) -> DeserializeError {
36        DeserializeError::InvalidValue(format!("ParseIntError {other:?}"))
37    }
38}
39
40impl From<anyhow::Error> for DeserializeError {
41    fn from(value: anyhow::Error) -> Self {
42        DeserializeError::OtherError(format!("OtherError {value:?}"))
43    }
44}
45
46pub type DeserializeResult<R> = anyhow::Result<R>;
47
48pub struct Deserializer<'data> {
49    pub context: ProtocolContext,
50    pub data: &'data [u8], // Remaining data
51}
52
53impl<'data> Deserializer<'data> {
54    #[must_use]
55    pub fn new(context: ProtocolContext, data: &'data [u8]) -> Self {
56        Self { context, data }
57    }
58
59    /// Take a number of bytes, and return a sub-Deserializer which
60    /// only operates on those bytes
61    pub fn slice(&mut self, count: usize) -> DeserializeResult<Self> {
62        Ok(Self {
63            context: self.context,
64            data: self.take(count)?,
65        })
66    }
67
68    #[must_use]
69    pub fn context(&self) -> ProtocolContext {
70        self.context
71    }
72
73    #[must_use]
74    pub fn direction(&self) -> CommandDirection {
75        self.context.dir
76    }
77
78    /// reports whether there are still bytes left for deserialization
79    #[must_use]
80    pub fn has_remaining(&self) -> bool {
81        self.remaining() > 0
82    }
83
84    #[must_use]
85    pub fn remaining(&self) -> usize {
86        self.data.len()
87    }
88
89    /// Finds the first occurrence of the byte 'b'
90    /// from the current position in the stream.
91    pub fn find(&mut self, byte: u8) -> Option<usize> {
92        self.data.iter().position(|ch| *ch == byte)
93    }
94
95    pub fn peek(&mut self, count: usize) -> DeserializeResult<&'data [u8]> {
96        if count > self.data.len() {
97            bail!(DeserializeError::Eof(format!(
98                "Deserializer::peek({count})"
99            )))
100        }
101        Ok(&self.data[0..count])
102    }
103
104    pub fn peek_all(&mut self) -> &'data [u8] {
105        self.data
106    }
107
108    pub fn take(&mut self, count: usize) -> DeserializeResult<&'data [u8]> {
109        if count > self.data.len() {
110            bail!(DeserializeError::Eof(format!(
111                "Deserializer::take({count})"
112            )))
113        }
114        let (ret, data) = self.data.split_at(count);
115        self.data = data;
116        Ok(ret)
117    }
118
119    pub fn take_n<const N: usize>(&mut self) -> DeserializeResult<[u8; N]> {
120        Ok(self.take(N)?.try_into().unwrap())
121    }
122
123    pub fn take_all(&mut self) -> &'data [u8] {
124        let (ret, data) = self.data.split_at(self.data.len());
125        self.data = data;
126        ret
127    }
128
129    /// Peek the next line (including ending \n, if present)
130    /// If the stream is at end, this will be an empty slice.
131    pub fn peek_line(&mut self) -> DeserializeResult<&'data [u8]> {
132        let line_len = match self.find(b'\n') {
133            Some(pos) => pos + 1,
134            None => self.remaining(),
135        };
136        self.peek(line_len)
137    }
138
139    /// Take the next line (including ending \n, if present)
140    /// If the stream is at end, this will be an empty slice.
141    pub fn take_line(&mut self) -> DeserializeResult<&'data [u8]> {
142        let line_len = match self.find(b'\n') {
143            Some(pos) => pos + 1,
144            None => self.remaining(),
145        };
146        self.take(line_len)
147    }
148
149    /// Take bytes until whitespace or end of stream
150    /// If `skip_whitespace` is true, skips initial whitespace first.
151    /// If `skip_whitespace` is false, and the next byte is a space,
152    /// nothing is taken, and the returned will be empty.
153    pub fn take_word(&mut self, skip_whitespace: bool) -> &'data [u8] {
154        if skip_whitespace {
155            self.take_space();
156        }
157        match self.data.iter().position(|&ch| ch == b' ' || ch == b'\n') {
158            Some(end) => {
159                let (ret, data) = self.data.split_at(end);
160                self.data = data;
161                ret
162            }
163            None => self.take_all(),
164        }
165    }
166
167    /// Take whitespace from the current cursor.
168    /// Repositioning the cursor at the start of the next word (or end of stream)
169    pub fn take_space(&mut self) {
170        match self.data.iter().position(|&ch| ch != b' ' && ch != b'\n') {
171            Some(pos) => {
172                (_, self.data) = self.data.split_at(pos);
173            }
174            None => {
175                self.take_all();
176            }
177        };
178    }
179}
180
181pub trait Deserialize: Sized + Debug {
182    /// Output should be Self, except for wrapper types.
183    type Output;
184    fn deserialize(deserializer: &mut Deserializer<'_>) -> DeserializeResult<Self::Output>;
185}