wowlab_parsers/parsers/parcel/
errors.rs1wowlab_engine_macros::define_error! {
4#[derive(Clone, Debug)]
6pub struct ParcelError {
7 #[source]
8 kind: ParcelErrorKind,
9}
10
11#[derive(Clone, Debug, thiserror::Error, Eq, PartialEq)]
12enum ParcelErrorKind {
13 #[error("ERR_ENCODED_TOO_LARGE")]
14 EncodedTooLarge,
15 #[error("ERR_PREFIX")]
16 Prefix,
17 #[error("ERR_FIELDS")]
18 Fields,
19 #[error("ERR_CONTENT_TYPE")]
20 ContentType,
21 #[error("ERR_CHECKSUM_TOKEN")]
22 ChecksumToken,
23 #[error("ERR_BASE64_TOKEN")]
24 Base64Token,
25 #[error("ERR_BASE64_DECODE")]
26 Base64Decode {
27 #[source]
28 source: Option<base64::DecodeError>,
29 },
30 #[error("ERR_BODY_TOO_LARGE")]
31 BodyTooLarge,
32 #[error("ERR_DEFLATE_UNAVAILABLE")]
33 DeflateUnavailable,
34 #[error("ERR_DECOMPRESS")]
35 Decompress,
36 #[error("ERR_PAYLOAD_TOO_LARGE")]
37 PayloadTooLarge,
38 #[error("ERR_CHECKSUM_MISMATCH")]
39 ChecksumMismatch,
40 #[error("ERR_PAYLOAD_TYPE")]
41 PayloadType,
42 #[error("ERR_COMPRESS")]
43 Compress,
44}
45}
46
47#[expect(
48 non_upper_case_globals,
49 reason = "associated constants preserve the stable ParcelError category API"
50)]
51impl ParcelError {
52 pub const EncodedTooLarge: Self = Self::new(ParcelErrorKind::EncodedTooLarge);
53 pub const Prefix: Self = Self::new(ParcelErrorKind::Prefix);
54 pub const Fields: Self = Self::new(ParcelErrorKind::Fields);
55 pub const ContentType: Self = Self::new(ParcelErrorKind::ContentType);
56 pub const ChecksumToken: Self = Self::new(ParcelErrorKind::ChecksumToken);
57 pub const Base64Token: Self = Self::new(ParcelErrorKind::Base64Token);
58 pub const Base64Decode: Self = Self::new(ParcelErrorKind::Base64Decode { source: None });
59 pub const BodyTooLarge: Self = Self::new(ParcelErrorKind::BodyTooLarge);
60 pub const DeflateUnavailable: Self = Self::new(ParcelErrorKind::DeflateUnavailable);
61 pub const Decompress: Self = Self::new(ParcelErrorKind::Decompress);
62 pub const PayloadTooLarge: Self = Self::new(ParcelErrorKind::PayloadTooLarge);
63 pub const ChecksumMismatch: Self = Self::new(ParcelErrorKind::ChecksumMismatch);
64 pub const PayloadType: Self = Self::new(ParcelErrorKind::PayloadType);
65 pub const Compress: Self = Self::new(ParcelErrorKind::Compress);
66
67 const fn new(kind: ParcelErrorKind) -> Self {
68 Self { kind }
69 }
70
71 #[must_use]
73 pub const fn code(&self) -> &'static str {
74 match self.kind {
75 ParcelErrorKind::EncodedTooLarge => "ERR_ENCODED_TOO_LARGE",
76 ParcelErrorKind::Prefix => "ERR_PREFIX",
77 ParcelErrorKind::Fields => "ERR_FIELDS",
78 ParcelErrorKind::ContentType => "ERR_CONTENT_TYPE",
79 ParcelErrorKind::ChecksumToken => "ERR_CHECKSUM_TOKEN",
80 ParcelErrorKind::Base64Token => "ERR_BASE64_TOKEN",
81 ParcelErrorKind::Base64Decode { .. } => "ERR_BASE64_DECODE",
82 ParcelErrorKind::BodyTooLarge => "ERR_BODY_TOO_LARGE",
83 ParcelErrorKind::DeflateUnavailable => "ERR_DEFLATE_UNAVAILABLE",
84 ParcelErrorKind::Decompress => "ERR_DECOMPRESS",
85 ParcelErrorKind::PayloadTooLarge => "ERR_PAYLOAD_TOO_LARGE",
86 ParcelErrorKind::ChecksumMismatch => "ERR_CHECKSUM_MISMATCH",
87 ParcelErrorKind::PayloadType => "ERR_PAYLOAD_TYPE",
88 ParcelErrorKind::Compress => "ERR_COMPRESS",
89 }
90 }
91}
92
93impl From<base64::DecodeError> for ParcelError {
94 fn from(source: base64::DecodeError) -> Self {
95 Self::new(ParcelErrorKind::Base64Decode {
96 source: Some(source),
97 })
98 }
99}
100
101impl PartialEq for ParcelError {
102 fn eq(&self, other: &Self) -> bool {
103 self.code() == other.code()
104 }
105}
106
107impl Eq for ParcelError {}
108
109wowlab_engine_macros::define_error! {
110#[derive(Clone, Debug, Eq, PartialEq)]
112pub struct CodecBuildError(CodecBuildErrorKind);
113
114#[derive(Clone, Debug, thiserror::Error, Eq, PartialEq)]
115enum CodecBuildErrorKind {
116 #[error("`prefix` must be a non-empty string")]
117 EmptyPrefix,
118 #[error("prefix must not contain `.` (it is the field separator)")]
119 PrefixContainsDot,
120 #[error("`contentTypes` must be a non-empty array of strings")]
121 EmptyContentTypes,
122 #[error("contentType `{0}` must match ^[a-z][a-z0-9]*$")]
123 InvalidContentType(String),
124 #[error("defaultContentType `{0}` not in contentTypes")]
125 InvalidDefaultContentType(String),
126}
127}
128
129impl CodecBuildError {
130 pub(super) const fn empty_prefix() -> Self {
131 Self(CodecBuildErrorKind::EmptyPrefix)
132 }
133
134 pub(super) const fn prefix_contains_dot() -> Self {
135 Self(CodecBuildErrorKind::PrefixContainsDot)
136 }
137
138 pub(super) const fn empty_content_types() -> Self {
139 Self(CodecBuildErrorKind::EmptyContentTypes)
140 }
141
142 pub(super) fn invalid_content_type(content_type: String) -> Self {
143 Self(CodecBuildErrorKind::InvalidContentType(content_type))
144 }
145
146 pub(super) fn invalid_default_content_type(content_type: String) -> Self {
147 Self(CodecBuildErrorKind::InvalidDefaultContentType(content_type))
148 }
149}