1use std::string::FromUtf8Error;
2
3pub type Result<T> = std::result::Result<T, Error>;
5
6#[derive(Debug, thiserror::Error)]
8pub enum Error {
9 #[error("buffer underflow: need {needed} bytes, got {available}")]
10 BufferUnderflow { needed: usize, available: usize },
11
12 #[error("invalid data: {0}")]
13 InvalidData(String),
14
15 #[error("varint too large")]
16 VarIntTooLarge,
17
18 #[error("string too long: {len} bytes, max {max}")]
19 StringTooLong { len: usize, max: usize },
20
21 #[error("invalid utf-8: {0}")]
22 InvalidUtf8(#[from] FromUtf8Error),
23
24 #[error("nbt error: {0}")]
25 Nbt(String),
26
27 #[error("{context}: {source}")]
30 Context {
31 context: String,
33 source: Box<Error>,
35 },
36}
37
38impl Error {
39 pub fn with_context(self, context: impl Into<String>) -> Self {
44 Self::Context {
45 context: context.into(),
46 source: Box::new(self),
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn display_buffer_underflow() {
57 let err = Error::BufferUnderflow {
58 needed: 4,
59 available: 2,
60 };
61 assert_eq!(err.to_string(), "buffer underflow: need 4 bytes, got 2");
62 }
63
64 #[test]
65 fn display_invalid_data() {
66 let err = Error::InvalidData("bad value".into());
67 assert_eq!(err.to_string(), "invalid data: bad value");
68 }
69
70 #[test]
71 fn display_varint_too_large() {
72 let err = Error::VarIntTooLarge;
73 assert_eq!(err.to_string(), "varint too large");
74 }
75
76 #[test]
77 fn display_string_too_long() {
78 let err = Error::StringTooLong {
79 len: 40000,
80 max: 32767,
81 };
82 assert_eq!(err.to_string(), "string too long: 40000 bytes, max 32767");
83 }
84
85 #[test]
86 fn display_nbt_error() {
87 let err = Error::Nbt("unexpected tag type".into());
88 assert_eq!(err.to_string(), "nbt error: unexpected tag type");
89 }
90
91 #[test]
92 fn context_wraps_error() {
93 let err = Error::BufferUnderflow {
94 needed: 8,
95 available: 3,
96 }
97 .with_context("decoding field 'x' of PlayerPosition");
98 assert_eq!(
99 err.to_string(),
100 "decoding field 'x' of PlayerPosition: buffer underflow: need 8 bytes, got 3"
101 );
102 }
103
104 #[test]
105 fn from_utf8_error() {
106 let invalid = vec![0xFF, 0xFE];
107 let utf8_err = String::from_utf8(invalid).unwrap_err();
108 let err: Error = utf8_err.into();
109 assert!(matches!(err, Error::InvalidUtf8(_)));
110 }
111}