Skip to content

Commit 3a5e837

Browse files
committed
Add full Decodable support
1 parent 58e0cb5 commit 3a5e837

6 files changed

Lines changed: 466 additions & 62 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ impl From<PacketId> for u16 {
7878
}
7979
}
8080

81-
// We annotate our packet with the #[Encode] macro to enable automatic
82-
// encoding and decoding to or from a `Bufferfish`.
81+
// We annotate our packet with the #[Encode] and #[Decode] macros to enable
82+
// automatic encoding and decoding to or from a `Bufferfish`.
8383
//
8484
// Additionally, we use the #[bufferfish] attribute to specify the packet ID.
8585
#[derive(Encode)]

rust/bufferfish-core/src/decodable.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,78 +6,186 @@ use crate::{Bufferfish, BufferfishError};
66
pub trait Decodable: Sized {
77
/// Decode the type from a `Bufferfish`.
88
fn decode(bf: &mut Bufferfish) -> Result<Self, BufferfishError>;
9+
10+
/// Get the minimum number of bytes required to decode this type.
11+
/// Returns None if the size can't be determined statically.
12+
fn min_bytes_required() -> Option<usize> {
13+
None
14+
}
15+
16+
/// Get the maximum number of bytes this type can occupy.
17+
/// Returns None if the size can't be determined statically.
18+
fn max_bytes_allowed() -> Option<usize> {
19+
None
20+
}
921
}
1022

1123
impl Decodable for u8 {
1224
fn decode(bf: &mut Bufferfish) -> Result<u8, BufferfishError> {
1325
bf.read_u8()
1426
}
27+
28+
fn min_bytes_required() -> Option<usize> {
29+
Some(1)
30+
}
31+
32+
fn max_bytes_allowed() -> Option<usize> {
33+
Some(1)
34+
}
1535
}
1636

1737
impl Decodable for u16 {
1838
fn decode(bf: &mut Bufferfish) -> Result<u16, BufferfishError> {
1939
bf.read_u16()
2040
}
41+
42+
fn min_bytes_required() -> Option<usize> {
43+
Some(2)
44+
}
45+
46+
fn max_bytes_allowed() -> Option<usize> {
47+
Some(2)
48+
}
2149
}
2250

2351
impl Decodable for u32 {
2452
fn decode(bf: &mut Bufferfish) -> Result<u32, BufferfishError> {
2553
bf.read_u32()
2654
}
55+
56+
fn min_bytes_required() -> Option<usize> {
57+
Some(4)
58+
}
59+
60+
fn max_bytes_allowed() -> Option<usize> {
61+
Some(4)
62+
}
2763
}
2864

2965
impl Decodable for u64 {
3066
fn decode(bf: &mut Bufferfish) -> Result<u64, BufferfishError> {
3167
bf.read_u64()
3268
}
69+
70+
fn min_bytes_required() -> Option<usize> {
71+
Some(8)
72+
}
73+
74+
fn max_bytes_allowed() -> Option<usize> {
75+
Some(8)
76+
}
3377
}
3478

3579
impl Decodable for u128 {
3680
fn decode(bf: &mut Bufferfish) -> Result<u128, BufferfishError> {
3781
bf.read_u128()
3882
}
83+
84+
fn min_bytes_required() -> Option<usize> {
85+
Some(16)
86+
}
87+
88+
fn max_bytes_allowed() -> Option<usize> {
89+
Some(16)
90+
}
3991
}
4092

4193
impl Decodable for i8 {
4294
fn decode(bf: &mut Bufferfish) -> Result<i8, BufferfishError> {
4395
bf.read_i8()
4496
}
97+
98+
fn min_bytes_required() -> Option<usize> {
99+
Some(1)
100+
}
101+
102+
fn max_bytes_allowed() -> Option<usize> {
103+
Some(1)
104+
}
45105
}
46106

47107
impl Decodable for i16 {
48108
fn decode(bf: &mut Bufferfish) -> Result<i16, BufferfishError> {
49109
bf.read_i16()
50110
}
111+
112+
fn min_bytes_required() -> Option<usize> {
113+
Some(2)
114+
}
115+
116+
fn max_bytes_allowed() -> Option<usize> {
117+
Some(2)
118+
}
51119
}
52120

53121
impl Decodable for i32 {
54122
fn decode(bf: &mut Bufferfish) -> Result<i32, BufferfishError> {
55123
bf.read_i32()
56124
}
125+
126+
fn min_bytes_required() -> Option<usize> {
127+
Some(4)
128+
}
129+
130+
fn max_bytes_allowed() -> Option<usize> {
131+
Some(4)
132+
}
57133
}
58134

59135
impl Decodable for i64 {
60136
fn decode(bf: &mut Bufferfish) -> Result<i64, BufferfishError> {
61137
bf.read_i64()
62138
}
139+
140+
fn min_bytes_required() -> Option<usize> {
141+
Some(8)
142+
}
143+
144+
fn max_bytes_allowed() -> Option<usize> {
145+
Some(8)
146+
}
63147
}
64148

65149
impl Decodable for i128 {
66150
fn decode(bf: &mut Bufferfish) -> Result<i128, BufferfishError> {
67151
bf.read_i128()
68152
}
153+
154+
fn min_bytes_required() -> Option<usize> {
155+
Some(16)
156+
}
157+
158+
fn max_bytes_allowed() -> Option<usize> {
159+
Some(16)
160+
}
69161
}
70162

71163
impl Decodable for bool {
72164
fn decode(bf: &mut Bufferfish) -> Result<bool, BufferfishError> {
73165
bf.read_bool()
74166
}
167+
168+
fn min_bytes_required() -> Option<usize> {
169+
Some(1)
170+
}
171+
172+
fn max_bytes_allowed() -> Option<usize> {
173+
Some(1)
174+
}
75175
}
76176

77177
impl Decodable for String {
78178
fn decode(bf: &mut Bufferfish) -> Result<String, BufferfishError> {
79179
bf.read_string()
80180
}
181+
182+
fn min_bytes_required() -> Option<usize> {
183+
Some(2)
184+
}
185+
186+
fn max_bytes_allowed() -> Option<usize> {
187+
Some(u16::MAX as usize + 2)
188+
}
81189
}
82190

83191
impl<T: Decodable> Decodable for Vec<T> {
@@ -89,4 +197,12 @@ impl<T: Decodable> Decodable for Vec<T> {
89197
}
90198
Ok(vec)
91199
}
200+
201+
fn min_bytes_required() -> Option<usize> {
202+
T::min_bytes_required().map(|min_t_size| 2 + (u16::MAX as usize * min_t_size))
203+
}
204+
205+
fn max_bytes_allowed() -> Option<usize> {
206+
T::max_bytes_allowed().map(|max_t_size| 2 + (u16::MAX as usize * max_t_size))
207+
}
92208
}

rust/bufferfish-core/src/lib.rs

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,38 @@ use std::{
99
pub use decodable::Decodable;
1010
pub use encodable::Encodable;
1111

12+
/// Trait for types that can be created from bytes.
13+
pub trait FromBytes: Sized {
14+
/// Create a new instance from bytes.
15+
fn from_bytes(bytes: &[u8]) -> Result<Self, BufferfishError>;
16+
}
17+
18+
impl<T: Decodable> FromBytes for T {
19+
fn from_bytes(bytes: &[u8]) -> Result<Self, BufferfishError> {
20+
if let Some(required) = T::min_bytes_required() {
21+
if bytes.len() < required {
22+
return Err(BufferfishError::InsufficientBytes {
23+
available: bytes.len(),
24+
required,
25+
});
26+
}
27+
}
28+
29+
if let Some(max_allowed) = T::max_bytes_allowed() {
30+
if bytes.len() > max_allowed {
31+
return Err(BufferfishError::ExcessiveBytes {
32+
available: bytes.len(),
33+
max_allowed,
34+
});
35+
}
36+
}
37+
38+
let mut bf = Bufferfish::from(bytes);
39+
bf.start_reading();
40+
T::decode(&mut bf)
41+
}
42+
}
43+
1244
/// Errors that can occur when encoding or decoding a `Bufferfish`.
1345
#[derive(Debug)]
1446
pub enum BufferfishError {
@@ -18,14 +50,35 @@ pub enum BufferfishError {
1850
InvalidPacketId,
1951
/// Invalid enum variant encountered during encoding/decoding.
2052
InvalidEnumVariant,
53+
/// The buffer doesn't contain enough bytes for the requested operation.
54+
InsufficientBytes { available: usize, required: usize },
55+
/// The buffer contains too many bytes for the requested operation.
56+
ExcessiveBytes {
57+
available: usize,
58+
max_allowed: usize,
59+
},
2160
}
2261

2362
impl std::fmt::Display for BufferfishError {
2463
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2564
match self {
26-
BufferfishError::FailedWrite(e) => write!(f, "failed to write to buffer: {}", e),
65+
BufferfishError::FailedWrite(e) => write!(f, "failed to write to buffer: {e}"),
2766
BufferfishError::InvalidPacketId => write!(f, "invalid packet id"),
2867
BufferfishError::InvalidEnumVariant => write!(f, "invalid enum variant"),
68+
BufferfishError::InsufficientBytes {
69+
available,
70+
required,
71+
} => write!(
72+
f,
73+
"insufficient bytes in buffer: available {available}, required {required}"
74+
),
75+
BufferfishError::ExcessiveBytes {
76+
available,
77+
max_allowed,
78+
} => write!(
79+
f,
80+
"excessive bytes in buffer: available {available}, maximum allowed {max_allowed}"
81+
),
2982
}
3083
}
3184
}
@@ -42,6 +95,8 @@ impl std::error::Error for BufferfishError {
4295
BufferfishError::FailedWrite(e) => Some(e),
4396
BufferfishError::InvalidPacketId => None,
4497
BufferfishError::InvalidEnumVariant => None,
98+
BufferfishError::InsufficientBytes { .. } => None,
99+
BufferfishError::ExcessiveBytes { .. } => None,
45100
}
46101
}
47102
}
@@ -87,6 +142,62 @@ impl Seek for Bufferfish {
87142
}
88143

89144
impl Bufferfish {
145+
/// Decode a value from this `Bufferfish`.
146+
///
147+
/// This function will start reading from the beginning of the buffer.
148+
/// Performs validation to check if the buffer's content is within acceptable size limits.
149+
pub fn decode<T: Decodable>(&mut self) -> Result<T, BufferfishError> {
150+
let bytes = self.as_bytes();
151+
152+
if let Some(required) = T::min_bytes_required() {
153+
if bytes.len() < required {
154+
return Err(BufferfishError::InsufficientBytes {
155+
available: bytes.len(),
156+
required,
157+
});
158+
}
159+
}
160+
161+
if let Some(max_allowed) = T::max_bytes_allowed() {
162+
if bytes.len() > max_allowed {
163+
return Err(BufferfishError::ExcessiveBytes {
164+
available: bytes.len(),
165+
max_allowed,
166+
});
167+
}
168+
}
169+
170+
self.start_reading();
171+
T::decode(self)
172+
}
173+
174+
/// Convert this Bufferfish into a value of type T.
175+
/// Performs validation to check if the buffer's content is within acceptable size limits.
176+
pub fn into_value<T: Decodable>(mut self) -> Result<T, BufferfishError> {
177+
let bytes = self.as_bytes();
178+
179+
if let Some(required) = T::min_bytes_required() {
180+
if bytes.len() < required {
181+
return Err(BufferfishError::InsufficientBytes {
182+
available: bytes.len(),
183+
required,
184+
});
185+
}
186+
}
187+
188+
if let Some(max_allowed) = T::max_bytes_allowed() {
189+
if bytes.len() > max_allowed {
190+
return Err(BufferfishError::ExcessiveBytes {
191+
available: bytes.len(),
192+
max_allowed,
193+
});
194+
}
195+
}
196+
197+
self.start_reading();
198+
T::decode(&mut self)
199+
}
200+
90201
/// Creates a new `Bufferfish` with a default max capacity (1024 bytes).
91202
pub fn new() -> Self {
92203
Self {
@@ -514,7 +625,7 @@ impl std::fmt::Display for Bufferfish {
514625
write!(f, " Byte: ")?;
515626

516627
for val in inner {
517-
write!(f, " {} ", val)?;
628+
write!(f, " {val} ")?;
518629
}
519630

520631
write!(f, "\nIndex: ")?;
@@ -526,7 +637,7 @@ impl std::fmt::Display for Bufferfish {
526637
#[cfg(not(feature = "pretty-print"))]
527638
let width = 1;
528639

529-
write!(f, " {:width$} ", i, width = width)?;
640+
write!(f, " {i:width$} ")?;
530641
}
531642

532643
Ok(())

0 commit comments

Comments
 (0)