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::{
8 fmt,
9 io::{Read, Write},
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
14pub struct Boolean(pub bool);
15
16impl TypeCodec for Boolean {
17 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
18 let byte = if self.0 { 1u8 } else { 0u8 };
19 write_all_counted(writer, &[byte], CodecKind::Boolean, 0)
20 }
21
22 fn decode(reader: &mut impl Read) -> Result<Self, CodecError>
23 where
24 Self: Sized,
25 {
26 let mut buf = [0u8; 1];
27 read_exact_counted(reader, &mut buf, CodecKind::Boolean, 0)?;
28 match buf[0] {
29 0 => Ok(Boolean(false)),
30 1 => Ok(Boolean(true)),
31 _ => Err(CodecError::invalid_encoding(
32 CodecKind::Boolean,
33 1,
34 InvalidEncodingReason::InvalidBooleanValue { value: buf[0] },
35 )),
36 }
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
42pub struct Byte(pub i8);
43
44impl TypeCodec for Byte {
45 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
46 write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Byte, 0)
47 }
48
49 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
50 let mut bytes = [0; 1];
51 read_exact_counted(reader, &mut bytes, CodecKind::Byte, 0)?;
52 Ok(Self(i8::from_be_bytes(bytes)))
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
58pub struct UnsignedByte(pub u8);
59
60impl TypeCodec for UnsignedByte {
61 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
62 write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::UnsignedByte, 0)
63 }
64
65 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
66 let mut bytes = [0; 1];
67 read_exact_counted(reader, &mut bytes, CodecKind::UnsignedByte, 0)?;
68 Ok(Self(u8::from_be_bytes(bytes)))
69 }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
74pub struct Short(pub i16);
75
76impl TypeCodec for Short {
77 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
78 write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Short, 0)
79 }
80
81 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
82 let mut bytes = [0; 2];
83 read_exact_counted(reader, &mut bytes, CodecKind::Short, 0)?;
84 Ok(Self(i16::from_be_bytes(bytes)))
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
90pub struct UnsignedShort(pub u16);
91
92impl TypeCodec for UnsignedShort {
93 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
94 write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::UnsignedShort, 0)
95 }
96
97 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
98 let mut bytes = [0; 2];
99 read_exact_counted(reader, &mut bytes, CodecKind::UnsignedShort, 0)?;
100 Ok(Self(u16::from_be_bytes(bytes)))
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
106pub struct Int(pub i32);
107
108impl TypeCodec for Int {
109 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
110 write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Int, 0)
111 }
112
113 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
114 let mut bytes = [0; 4];
115 read_exact_counted(reader, &mut bytes, CodecKind::Int, 0)?;
116 Ok(Self(i32::from_be_bytes(bytes)))
117 }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
122pub struct Long(pub i64);
123
124impl TypeCodec for Long {
125 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
126 write_all_counted(writer, &self.0.to_be_bytes(), CodecKind::Long, 0)
127 }
128
129 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
130 let mut bytes = [0; 8];
131 read_exact_counted(reader, &mut bytes, CodecKind::Long, 0)?;
132 Ok(Self(i64::from_be_bytes(bytes)))
133 }
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
138pub struct PrefixedString(pub String);
139
140impl PrefixedString {
141 pub const MAX_UTF16_CODE_UNITS: usize = 0x7fff;
142 pub const MAX_BYTES: usize = Self::MAX_UTF16_CODE_UNITS * 3;
143
144 fn validate_value(
145 value: &str,
146 operation: CodecOperation,
147 bytes_processed: usize,
148 ) -> Result<(), CodecError> {
149 let bytes = value.as_bytes();
150 if bytes.len() > Self::MAX_BYTES {
151 return Err(CodecError::invalid_encoding_for_operation(
152 CodecKind::String,
153 operation,
154 bytes_processed,
155 InvalidEncodingReason::StringTooLong {
156 max_bytes: Self::MAX_BYTES,
157 },
158 ));
159 }
160
161 if value.encode_utf16().count() > Self::MAX_UTF16_CODE_UNITS {
162 return Err(CodecError::invalid_encoding_for_operation(
163 CodecKind::String,
164 operation,
165 bytes_processed,
166 InvalidEncodingReason::TooManyUtf16CodeUnits {
167 max_code_units: Self::MAX_UTF16_CODE_UNITS,
168 },
169 ));
170 }
171
172 Ok(())
173 }
174
175 fn encode_value(value: &str, writer: &mut impl Write) -> Result<(), CodecError> {
176 Self::validate_value(value, CodecOperation::Write, 0)?;
177
178 let bytes = value.as_bytes();
179 let prefix_size = writer
180 .write_varint_with_size(bytes.len() as i32)
181 .map_err(|error| error.with_context(CodecKind::String))?;
182 write_all_counted(writer, bytes, CodecKind::String, prefix_size)
183 }
184
185 fn decode_value(reader: &mut impl Read) -> Result<(String, usize), CodecError> {
186 let (byte_length, prefix_size) = reader
187 .read_varint_with_size()
188 .map_err(|error| error.with_context(CodecKind::String))?;
189 let byte_length = usize::try_from(byte_length).map_err(|_| {
190 CodecError::invalid_encoding(
191 CodecKind::String,
192 prefix_size,
193 InvalidEncodingReason::NegativeLength { value: byte_length },
194 )
195 })?;
196
197 if byte_length > Self::MAX_BYTES {
198 return Err(CodecError::invalid_encoding(
199 CodecKind::String,
200 prefix_size,
201 InvalidEncodingReason::StringTooLong {
202 max_bytes: Self::MAX_BYTES,
203 },
204 ));
205 }
206
207 let mut bytes = vec![0; byte_length];
208 read_exact_counted(reader, &mut bytes, CodecKind::String, prefix_size)?;
209 let bytes_processed = prefix_size + byte_length;
210 let value = String::from_utf8(bytes).map_err(|error| {
211 let utf8_error = error.utf8_error();
212 CodecError::invalid_encoding(
213 CodecKind::String,
214 bytes_processed,
215 InvalidEncodingReason::InvalidUtf8 {
216 valid_up_to: utf8_error.valid_up_to(),
217 error_len: utf8_error.error_len(),
218 },
219 )
220 })?;
221 Self::validate_value(&value, CodecOperation::Read, bytes_processed)?;
222 Ok((value, bytes_processed))
223 }
224}
225
226impl TypeCodec for PrefixedString {
227 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
228 Self::encode_value(&self.0, writer)
229 }
230
231 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
232 Self::decode_value(reader).map(|(value, _)| Self(value))
233 }
234}
235
236#[derive(Debug, Clone, PartialEq, Eq, Hash)]
238pub struct Identifier(String);
239
240impl Identifier {
241 pub const MAX_UTF16_CODE_UNITS: usize = PrefixedString::MAX_UTF16_CODE_UNITS;
242 pub const MAX_BYTES: usize = PrefixedString::MAX_BYTES;
243 pub const MAX_ENCODED_BYTES: usize = Self::MAX_BYTES + 3;
244
245 pub fn new(value: impl Into<String>) -> Result<Self, InvalidIdentifier> {
246 let value = value.into();
247 validate_identifier(&value)?;
248 Ok(Self(value))
249 }
250
251 pub fn as_str(&self) -> &str {
252 &self.0
253 }
254
255 pub fn into_inner(self) -> String {
256 self.0
257 }
258}
259
260impl TypeCodec for Identifier {
261 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
262 PrefixedString::encode_value(&self.0, writer)
263 .map_err(|error| error.with_context(CodecKind::Identifier))
264 }
265
266 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
267 let (value, bytes_processed) = PrefixedString::decode_value(reader)
268 .map_err(|error| error.with_context(CodecKind::Identifier))?;
269 Self::new(value).map_err(|_| {
270 CodecError::invalid_encoding(
271 CodecKind::Identifier,
272 bytes_processed,
273 InvalidEncodingReason::InvalidIdentifier,
274 )
275 })
276 }
277}
278
279fn validate_identifier(value: &str) -> Result<(), InvalidIdentifier> {
280 let (namespace, path) = match value.split_once(':') {
281 Some((namespace, path)) => (namespace, path),
282 None => ("minecraft", value),
283 };
284 let namespace_is_valid = !namespace.is_empty()
285 && namespace.bytes().all(|byte| {
286 byte.is_ascii_lowercase() || byte.is_ascii_digit() || b"_.-".contains(&byte)
287 });
288 let path_is_valid = !path.is_empty()
289 && path.bytes().all(|byte| {
290 byte.is_ascii_lowercase() || byte.is_ascii_digit() || b"/._-".contains(&byte)
291 });
292 if namespace_is_valid && path_is_valid && !path.contains(':') {
293 Ok(())
294 } else {
295 Err(InvalidIdentifier)
296 }
297}
298
299#[derive(Debug, Clone, Copy, PartialEq, Eq)]
300pub struct InvalidIdentifier;
301
302impl fmt::Display for InvalidIdentifier {
303 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
304 formatter.write_str("invalid Minecraft identifier")
305 }
306}
307
308impl std::error::Error for InvalidIdentifier {}