Skip to content

Commit 0051f5e

Browse files
authored
fix: Ip{,v4,v6}Addr::decode (#7)
* fix: `Ip{,v4,v6}Addr::decode` * chore: clippy * chore: gate helper fn
1 parent 977c56f commit 0051f5e

File tree

4 files changed

+69
-30
lines changed

4 files changed

+69
-30
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
12+
- `Ip{,v4,v6}Addr::decode` ([#6])
13+
14+
[#6]: https://github.com/alloy-rs/rlp/pull/6
15+
1016
## [0.3.2] - 2023-07-26
1117

1218
### Added

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ proc-macro2 = "1.0"
2626
quote = "1.0"
2727
syn = "2.0"
2828

29+
hex = { package = "const-hex", version = "1", default-features = false, features = ["alloc"] }
2930
hex-literal = "0.4"
3031

3132
# misc

crates/rlp/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ arrayvec = { workspace = true, optional = true }
2424
smol_str = { version = "0.2", default-features = false, optional = true }
2525

2626
[dev-dependencies]
27+
hex.workspace = true
2728
hex-literal.workspace = true
2829

2930
[features]

crates/rlp/src/decode.rs

+61-30
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,12 @@ mod std_impl {
145145
fn decode(buf: &mut &[u8]) -> Result<Self> {
146146
let bytes = Header::decode_bytes(buf, false)?;
147147
match bytes.len() {
148-
4 => static_left_pad(bytes).map(|octets| Self::V4(Ipv4Addr::from(octets))),
149-
16 => static_left_pad(bytes).map(|octets| Self::V6(Ipv6Addr::from(octets))),
148+
4 => Ok(Self::V4(Ipv4Addr::from(
149+
slice_to_array::<4>(bytes).expect("infallible"),
150+
))),
151+
16 => Ok(Self::V6(Ipv6Addr::from(
152+
slice_to_array::<16>(bytes).expect("infallible"),
153+
))),
150154
_ => Err(Error::UnexpectedLength),
151155
}
152156
}
@@ -156,15 +160,15 @@ mod std_impl {
156160
#[inline]
157161
fn decode(buf: &mut &[u8]) -> Result<Self> {
158162
let bytes = Header::decode_bytes(buf, false)?;
159-
static_left_pad::<4>(bytes).map(Self::from)
163+
slice_to_array::<4>(bytes).map(Self::from)
160164
}
161165
}
162166

163167
impl Decodable for Ipv6Addr {
164168
#[inline]
165169
fn decode(buf: &mut &[u8]) -> Result<Self> {
166170
let bytes = Header::decode_bytes(buf, false)?;
167-
static_left_pad::<16>(bytes).map(Self::from)
171+
slice_to_array::<16>(bytes).map(Self::from)
168172
}
169173
}
170174
}
@@ -195,33 +199,43 @@ pub(crate) fn static_left_pad<const N: usize>(data: &[u8]) -> Result<[u8; N]> {
195199
Ok(v)
196200
}
197201

202+
#[cfg(feature = "std")]
203+
#[inline]
204+
fn slice_to_array<const N: usize>(slice: &[u8]) -> Result<[u8; N]> {
205+
slice.try_into().map_err(|_| Error::UnexpectedLength)
206+
}
207+
198208
#[cfg(test)]
199209
mod tests {
200210
use super::*;
211+
use crate::Encodable;
201212
use alloc::{string::String, vec::Vec};
202213
use core::fmt::Debug;
203214
use hex_literal::hex;
204215

205216
fn check_decode<'a, T, IT>(fixtures: IT)
206217
where
207-
T: Decodable + PartialEq + Debug,
218+
T: Encodable + Decodable + PartialEq + Debug,
208219
IT: IntoIterator<Item = (Result<T>, &'a [u8])>,
209220
{
210221
for (expected, mut input) in fixtures {
211-
assert_eq!(T::decode(&mut input), expected);
212-
if expected.is_ok() {
213-
assert_eq!(input, &[]);
222+
if let Ok(expected) = &expected {
223+
assert_eq!(crate::encode(expected), input, "{expected:?}");
214224
}
215-
}
216-
}
217225

218-
fn check_decode_list<T, IT>(fixtures: IT)
219-
where
220-
T: Decodable + PartialEq + Debug,
221-
IT: IntoIterator<Item = (Result<Vec<T>>, &'static [u8])>,
222-
{
223-
for (expected, mut input) in fixtures {
224-
assert_eq!(Vec::<T>::decode(&mut input), expected);
226+
let orig = input;
227+
assert_eq!(
228+
T::decode(&mut input),
229+
expected,
230+
"input: {}{}",
231+
hex::encode(orig),
232+
if let Ok(expected) = &expected {
233+
format!("; expected: {}", hex::encode(crate::encode(expected)))
234+
} else {
235+
String::new()
236+
}
237+
);
238+
225239
if expected.is_ok() {
226240
assert_eq!(input, &[]);
227241
}
@@ -230,7 +244,7 @@ mod tests {
230244

231245
#[test]
232246
fn rlp_strings() {
233-
check_decode::<Bytes, _>(vec![
247+
check_decode::<Bytes, _>([
234248
(Ok(hex!("00")[..].to_vec().into()), &hex!("00")[..]),
235249
(
236250
Ok(hex!("6f62636465666768696a6b6c6d")[..].to_vec().into()),
@@ -249,15 +263,15 @@ mod tests {
249263

250264
let mut b = BytesMut::new();
251265
"test smol str".to_string().encode(&mut b);
252-
check_decode::<SmolStr, _>(vec![
266+
check_decode::<SmolStr, _>([
253267
(Ok(SmolStr::new("test smol str")), b.as_ref()),
254268
(Err(Error::UnexpectedList), &hex!("C0")[..]),
255269
])
256270
}
257271

258272
#[test]
259273
fn rlp_fixed_length() {
260-
check_decode(vec![
274+
check_decode([
261275
(
262276
Ok(hex!("6f62636465666768696a6b6c6d")),
263277
&hex!("8D6F62636465666768696A6B6C6D")[..],
@@ -275,7 +289,7 @@ mod tests {
275289

276290
#[test]
277291
fn rlp_u64() {
278-
check_decode(vec![
292+
check_decode([
279293
(Ok(9_u64), &hex!("09")[..]),
280294
(Ok(0_u64), &hex!("80")[..]),
281295
(Ok(0x0505_u64), &hex!("820505")[..]),
@@ -299,7 +313,7 @@ mod tests {
299313

300314
#[test]
301315
fn rlp_vectors() {
302-
check_decode_list(vec![
316+
check_decode::<Vec<u64>, _>([
303317
(Ok(vec![]), &hex!("C0")[..]),
304318
(
305319
Ok(vec![0xBBCCB5_u64, 0xFFC0B5_u64]),
@@ -308,34 +322,51 @@ mod tests {
308322
])
309323
}
310324

325+
#[cfg(feature = "std")]
326+
#[test]
327+
fn rlp_ip() {
328+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
329+
330+
let localhost4 = Ipv4Addr::new(127, 0, 0, 1);
331+
let localhost6 = localhost4.to_ipv6_mapped();
332+
let expected4 = &hex!("847F000001")[..];
333+
let expected6 = &hex!("9000000000000000000000ffff7f000001")[..];
334+
check_decode::<Ipv4Addr, _>([(Ok(localhost4), expected4)]);
335+
check_decode::<Ipv6Addr, _>([(Ok(localhost6), expected6)]);
336+
check_decode::<IpAddr, _>([
337+
(Ok(IpAddr::V4(localhost4)), expected4),
338+
(Ok(IpAddr::V6(localhost6)), expected6),
339+
]);
340+
}
341+
311342
#[test]
312343
fn malformed_rlp() {
313-
check_decode::<Bytes, _>(vec![
344+
check_decode::<Bytes, _>([
314345
(Err(Error::InputTooShort), &hex!("C1")[..]),
315346
(Err(Error::InputTooShort), &hex!("D7")[..]),
316347
]);
317-
check_decode::<[u8; 5], _>(vec![
348+
check_decode::<[u8; 5], _>([
318349
(Err(Error::InputTooShort), &hex!("C1")[..]),
319350
(Err(Error::InputTooShort), &hex!("D7")[..]),
320351
]);
321352
#[cfg(feature = "std")]
322-
check_decode::<std::net::IpAddr, _>(vec![
353+
check_decode::<std::net::IpAddr, _>([
323354
(Err(Error::InputTooShort), &hex!("C1")[..]),
324355
(Err(Error::InputTooShort), &hex!("D7")[..]),
325356
]);
326-
check_decode::<Vec<u8>, _>(vec![
357+
check_decode::<Vec<u8>, _>([
327358
(Err(Error::InputTooShort), &hex!("C1")[..]),
328359
(Err(Error::InputTooShort), &hex!("D7")[..]),
329360
]);
330-
check_decode::<String, _>(vec![
361+
check_decode::<String, _>([
331362
(Err(Error::InputTooShort), &hex!("C1")[..]),
332363
(Err(Error::InputTooShort), &hex!("D7")[..]),
333364
]);
334-
check_decode::<String, _>(vec![
365+
check_decode::<String, _>([
335366
(Err(Error::InputTooShort), &hex!("C1")[..]),
336367
(Err(Error::InputTooShort), &hex!("D7")[..]),
337368
]);
338-
check_decode::<u8, _>(vec![(Err(Error::InputTooShort), &hex!("82")[..])]);
339-
check_decode::<u64, _>(vec![(Err(Error::InputTooShort), &hex!("82")[..])]);
369+
check_decode::<u8, _>([(Err(Error::InputTooShort), &hex!("82")[..])]);
370+
check_decode::<u64, _>([(Err(Error::InputTooShort), &hex!("82")[..])]);
340371
}
341372
}

0 commit comments

Comments
 (0)