Skip to content

Commit 3a0bd85

Browse files
committed
add IpAddr type serailize to byte representation
1 parent 2b4140b commit 3a0bd85

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

src/bipaddr.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! Byte string which helps with the deserialization.
2+
3+
use core::{
4+
borrow::{Borrow, BorrowMut},
5+
fmt, net,
6+
ops::{Deref, DerefMut},
7+
};
8+
9+
use serde::{
10+
de::{self, Visitor},
11+
Deserialize, Deserializer,
12+
};
13+
14+
/// IpAddr serialize to and deserialize from big-endian bytes representation.
15+
///
16+
/// Bencoded "strings" are not necessarily UTF-8 encoded values so if a field is
17+
/// not guranteed to be a UTF-8 string, then you should use a `ByteString` or
18+
/// another equivalent type.
19+
///
20+
/// Due to a limitation within `serde` and Rust, a `IpAddr::V4` and `IpAddr::V6` will
21+
/// serialize and deserialize as a list of individual byte elements. Serializing `IpAddr`
22+
/// requires serialize enum which this bencode/library does not support yet.
23+
///
24+
/// # Examples
25+
///
26+
/// ```rust
27+
/// use bt_bencode::ByteIpAddr;
28+
/// use core::net;
29+
///
30+
/// let v4_bytes = [1,2,3,4];
31+
/// let v6_bytes = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
32+
/// let v4 = net::IpAddr::from(v4_bytes);
33+
/// let v6 = net::IpAddr::from(v6_bytes);
34+
/// let bip4 = ByteIpAddr::from(v4);
35+
///
36+
///
37+
/// let encoded = bt_bencode::to_vec(&bip4)?;
38+
/// assert_eq!(encoded, b"4:\x01\x02\x03\x04");
39+
///
40+
/// let decoded: ByteIpAddr = bt_bencode::from_slice(&encoded)?;
41+
/// assert_eq!(decoded, v4.into());
42+
///
43+
/// let bip6 = ByteIpAddr::from(v6);
44+
///
45+
/// let encoded = bt_bencode::to_vec(&bip6)?;
46+
/// assert_eq!(encoded, b"16:\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10");
47+
///
48+
/// let decoded: ByteIpAddr = bt_bencode::from_slice(&encoded)?;
49+
/// assert_eq!(decoded, v6.into());
50+
///
51+
/// // test invalid bytes
52+
/// assert!(bt_bencode::from_slice::<ByteIpAddr>(b"5:\x01\x02\x03\x04\x05").is_err());
53+
///
54+
/// # Ok::<(), bt_bencode::Error>(())
55+
/// ```
56+
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
57+
pub struct ByteIpAddr(net::IpAddr);
58+
59+
impl AsRef<net::IpAddr> for ByteIpAddr {
60+
fn as_ref(&self) -> &net::IpAddr {
61+
&self.0
62+
}
63+
}
64+
65+
impl AsMut<net::IpAddr> for ByteIpAddr {
66+
fn as_mut(&mut self) -> &mut net::IpAddr {
67+
&mut self.0
68+
}
69+
}
70+
71+
impl Borrow<net::IpAddr> for ByteIpAddr {
72+
fn borrow(&self) -> &net::IpAddr {
73+
&self.0
74+
}
75+
}
76+
77+
impl BorrowMut<net::IpAddr> for ByteIpAddr {
78+
fn borrow_mut(&mut self) -> &mut net::IpAddr {
79+
&mut self.0
80+
}
81+
}
82+
83+
impl fmt::Debug for ByteIpAddr {
84+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85+
fmt::Debug::fmt(&self.0, f)
86+
}
87+
}
88+
89+
impl Deref for ByteIpAddr {
90+
type Target = net::IpAddr;
91+
92+
fn deref(&self) -> &Self::Target {
93+
&self.0
94+
}
95+
}
96+
97+
impl DerefMut for ByteIpAddr {
98+
fn deref_mut(&mut self) -> &mut Self::Target {
99+
&mut self.0
100+
}
101+
}
102+
103+
impl<T> From<T> for ByteIpAddr
104+
where
105+
T: Into<net::IpAddr>,
106+
{
107+
fn from(value: T) -> Self {
108+
Self(value.into())
109+
}
110+
}
111+
112+
impl serde::Serialize for ByteIpAddr {
113+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
114+
where
115+
S: serde::Serializer,
116+
{
117+
match self.0 {
118+
net::IpAddr::V4(ip) => serializer.serialize_bytes(&ip.octets()),
119+
net::IpAddr::V6(ip) => serializer.serialize_bytes(&ip.octets()),
120+
}
121+
}
122+
}
123+
124+
struct IpAddrVisitor;
125+
126+
impl<'de> Visitor<'de> for IpAddrVisitor {
127+
type Value = ByteIpAddr;
128+
129+
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
130+
formatter.write_str("byte string of length 4(ipv4) or 16(ipv6)")
131+
}
132+
133+
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
134+
where
135+
E: de::Error,
136+
{
137+
match v.len() {
138+
4 => Ok(ByteIpAddr(net::IpAddr::V4(net::Ipv4Addr::from([
139+
v[0], v[1], v[2], v[3],
140+
])))),
141+
16 => Ok(ByteIpAddr(net::IpAddr::V6(net::Ipv6Addr::from([
142+
v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12],
143+
v[13], v[14], v[15],
144+
])))),
145+
other => Err(de::Error::invalid_value(
146+
de::Unexpected::Str(&format!("get byte string {v:02x?} of length {other}")),
147+
&self,
148+
)),
149+
}
150+
}
151+
}
152+
153+
impl<'de> Deserialize<'de> for ByteIpAddr {
154+
fn deserialize<D>(deserializer: D) -> Result<ByteIpAddr, D::Error>
155+
where
156+
D: Deserializer<'de>,
157+
{
158+
deserializer.deserialize_byte_buf(IpAddrVisitor)
159+
}
160+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ extern crate serde;
108108
mod bstring;
109109
mod de;
110110
mod error;
111+
mod bipaddr;
111112

112113
pub mod read;
113114
pub mod write;
@@ -122,6 +123,8 @@ pub use de::{from_slice, Deserializer};
122123
#[doc(inline)]
123124
pub use error::{Error, ErrorKind, Result};
124125
#[doc(inline)]
126+
pub use bipaddr::ByteIpAddr;
127+
#[doc(inline)]
125128
pub use value::{from_value, to_value, Value};
126129

127130
#[doc(inline)]

0 commit comments

Comments
 (0)