minetest_protocol/wire/
deser.rs

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