Skip to main content

mcproto_types/
basic.rs

1use crate::TypeCodec;
2use mcproto_codec::{
3    error::{CodecError, CodecKind, CodecOperation, InvalidEncodingReason},
4    io::{read_exact_counted, write_all_counted},
5    varint::{VarIntRead, VarIntWrite},
6};
7use std::io::{Read, Write};
8
9/// True is encoded as 0x01, false as 0x00.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
11pub struct Boolean(pub bool);
12
13impl TypeCodec for Boolean {
14    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
15        let byte = if self.0 { 1u8 } else { 0u8 };
16        write_all_counted(writer, &[byte], CodecKind::Boolean, 0)
17    }
18
19    fn decode(reader: &mut impl Read) -> Result<Self, CodecError>
20    where
21        Self: Sized,
22    {
23        let mut buf = [0u8; 1];
24        read_exact_counted(reader, &mut buf, CodecKind::Boolean, 0)?;
25        match buf[0] {
26            0 => Ok(Boolean(false)),
27            1 => Ok(Boolean(true)),
28            _ => Err(CodecError::invalid_encoding(
29                CodecKind::Boolean,
30                1,
31                InvalidEncodingReason::InvalidBooleanValue { value: buf[0] },
32            )),
33        }
34    }
35}
36
37/// Signed 8-bit integer, two's complement.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
39pub struct Byte(pub i8);
40
41impl TypeCodec for Byte {
42    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
43        write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Byte, 0)
44    }
45
46    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
47        let mut bytes = [0; 1];
48        read_exact_counted(reader, &mut bytes, CodecKind::Byte, 0)?;
49        Ok(Self(i8::from_be_bytes(bytes)))
50    }
51}
52
53/// Unsigned 8-bit integer.
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
55pub struct UnsignedByte(pub u8);
56
57impl TypeCodec for UnsignedByte {
58    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
59        write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::UnsignedByte, 0)
60    }
61
62    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
63        let mut bytes = [0; 1];
64        read_exact_counted(reader, &mut bytes, CodecKind::UnsignedByte, 0)?;
65        Ok(Self(u8::from_be_bytes(bytes)))
66    }
67}
68
69/// Signed 16-bit integer, big-endian two's complement.
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
71pub struct Short(pub i16);
72
73impl TypeCodec for Short {
74    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
75        write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Short, 0)
76    }
77
78    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
79        let mut bytes = [0; 2];
80        read_exact_counted(reader, &mut bytes, CodecKind::Short, 0)?;
81        Ok(Self(i16::from_be_bytes(bytes)))
82    }
83}
84
85/// Unsigned 16-bit integer, big-endian.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
87pub struct UnsignedShort(pub u16);
88
89impl TypeCodec for UnsignedShort {
90    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
91        write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::UnsignedShort, 0)
92    }
93
94    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
95        let mut bytes = [0; 2];
96        read_exact_counted(reader, &mut bytes, CodecKind::UnsignedShort, 0)?;
97        Ok(Self(u16::from_be_bytes(bytes)))
98    }
99}
100
101/// Signed 32-bit integer, big-endian two's complement.
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
103pub struct Int(pub i32);
104
105impl TypeCodec for Int {
106    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
107        write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Int, 0)
108    }
109
110    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
111        let mut bytes = [0; 4];
112        read_exact_counted(reader, &mut bytes, CodecKind::Int, 0)?;
113        Ok(Self(i32::from_be_bytes(bytes)))
114    }
115}
116
117/// Signed 64-bit integer, big-endian two's complement.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
119pub struct Long(pub i64);
120
121impl TypeCodec for Long {
122    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
123        write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Long, 0)
124    }
125
126    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
127        let mut bytes = [0; 8];
128        read_exact_counted(reader, &mut bytes, CodecKind::Long, 0)?;
129        Ok(Self(i64::from_be_bytes(bytes)))
130    }
131}
132
133/// A standard UTF-8 string prefixed by its byte length as a VarInt.
134#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
135pub struct PrefixedString(pub String);
136
137impl PrefixedString {
138    pub const MAX_UTF16_CODE_UNITS: usize = 0x7fff;
139    pub const MAX_BYTES: usize = Self::MAX_UTF16_CODE_UNITS * 3;
140
141    fn validate_value(
142        value: &str,
143        operation: CodecOperation,
144        bytes_processed: usize,
145    ) -> Result<(), CodecError> {
146        let bytes = value.as_bytes();
147        if bytes.len() > Self::MAX_BYTES {
148            return Err(CodecError::invalid_encoding_for_operation(
149                CodecKind::String,
150                operation,
151                bytes_processed,
152                InvalidEncodingReason::StringTooLong {
153                    max_bytes: Self::MAX_BYTES,
154                },
155            ));
156        }
157
158        if value.encode_utf16().count() > Self::MAX_UTF16_CODE_UNITS {
159            return Err(CodecError::invalid_encoding_for_operation(
160                CodecKind::String,
161                operation,
162                bytes_processed,
163                InvalidEncodingReason::TooManyUtf16CodeUnits {
164                    max_code_units: Self::MAX_UTF16_CODE_UNITS,
165                },
166            ));
167        }
168
169        Ok(())
170    }
171
172    fn encode_value(value: &str, writer: &mut impl Write) -> Result<(), CodecError> {
173        Self::validate_value(value, CodecOperation::Write, 0)?;
174
175        let bytes = value.as_bytes();
176        let prefix_size = writer
177            .write_varint_with_size(bytes.len() as i32)
178            .map_err(|error| error.with_context(CodecKind::String))?;
179        write_all_counted(writer, bytes, CodecKind::String, prefix_size)
180    }
181}
182
183impl TypeCodec for PrefixedString {
184    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
185        Self::encode_value(&self.0, writer)
186    }
187
188    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
189        let (byte_length, prefix_size) = reader
190            .read_varint_with_size()
191            .map_err(|error| error.with_context(CodecKind::String))?;
192        let byte_length = usize::try_from(byte_length).map_err(|_| {
193            CodecError::invalid_encoding(
194                CodecKind::String,
195                prefix_size,
196                InvalidEncodingReason::NegativeLength { value: byte_length },
197            )
198        })?;
199
200        if byte_length > Self::MAX_BYTES {
201            return Err(CodecError::invalid_encoding(
202                CodecKind::String,
203                prefix_size,
204                InvalidEncodingReason::StringTooLong {
205                    max_bytes: Self::MAX_BYTES,
206                },
207            ));
208        }
209
210        let mut bytes = vec![0; byte_length];
211        read_exact_counted(reader, &mut bytes, CodecKind::String, prefix_size)?;
212
213        let value = String::from_utf8(bytes).map_err(|error| {
214            let utf8_error = error.utf8_error();
215            CodecError::invalid_encoding(
216                CodecKind::String,
217                prefix_size + byte_length,
218                InvalidEncodingReason::InvalidUtf8 {
219                    valid_up_to: utf8_error.valid_up_to(),
220                    error_len: utf8_error.error_len(),
221                },
222            )
223        })?;
224        Self::validate_value(&value, CodecOperation::Read, prefix_size + byte_length)?;
225        Ok(Self(value))
226    }
227}
228
229/// Encoded as a String with max length of 32 767.
230#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
231pub struct Identifier(pub String);
232
233impl Identifier {
234    pub const MAX_UTF16_CODE_UNITS: usize = PrefixedString::MAX_UTF16_CODE_UNITS;
235    pub const MAX_BYTES: usize = PrefixedString::MAX_BYTES;
236    pub const MAX_ENCODED_BYTES: usize = Self::MAX_BYTES + 3;
237}
238
239impl TypeCodec for Identifier {
240    fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
241        PrefixedString::encode_value(&self.0, writer)
242            .map_err(|error| error.with_context(CodecKind::Identifier))
243    }
244
245    fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
246        PrefixedString::decode(reader)
247            .map(|value| Self(value.0))
248            .map_err(|error| error.with_context(CodecKind::Identifier))
249    }
250}