Skip to content

Commit a430dff

Browse files
committed
Change internal representation of the Multiaddr main struct to Vec<Addr> instead of Vec<u8> (multiformats#19)
1 parent f7cda32 commit a430dff

File tree

3 files changed

+81
-119
lines changed

3 files changed

+81
-119
lines changed

Diff for: src/lib.rs

+48-38
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
1818
/// Representation of a Multiaddr.
1919
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
2020
pub struct Multiaddr {
21-
bytes: Vec<u8>,
21+
addr: Vec<Addr>,
22+
23+
#[deprecated]
24+
bytes: Vec<u8>
2225
}
2326

2427
impl ToString for Multiaddr {
@@ -34,10 +37,11 @@ impl ToString for Multiaddr {
3437
/// ```
3538
///
3639
fn to_string(&self) -> String {
37-
parser::address_from_bytes(self.as_slice()).expect("failed to validate at construction")
40+
parser::multiaddr_to_str(&self.addr)
3841
}
3942
}
4043

44+
#[allow(deprecated)] // We have to access our own deprecated `bytes` field
4145
impl Multiaddr {
4246
/// Create a new multiaddr based on a string representation, like
4347
/// `/ip4/127.0.0.1/udp/1234`.
@@ -57,17 +61,26 @@ impl Multiaddr {
5761
/// ```
5862
///
5963
pub fn new(input: &str) -> Result<Multiaddr> {
60-
let bytes = parser::multiaddr_from_str(input)?;
64+
let addr = parser::multiaddr_from_str(input)?;
65+
66+
Ok(Multiaddr { bytes: Self::_addr_to_bytes(&addr), addr: addr })
67+
}
6168

62-
Ok(Multiaddr { bytes: bytes })
69+
fn _addr_to_bytes(addr: &Vec<Addr>) -> Vec<u8> {
70+
let mut bytes = Vec::new();
71+
for addr_segment in addr {
72+
addr_segment.to_stream(&mut bytes).unwrap();
73+
}
74+
bytes
6375
}
6476

6577
/// Return a copy to disallow changing the bytes directly
6678
pub fn to_bytes(&self) -> Vec<u8> {
67-
self.bytes.to_owned()
79+
Self::_addr_to_bytes(&self.addr)
6880
}
6981

7082
/// Extracts a slice containing the entire underlying vector.
83+
#[deprecated(note="Use `.to_bytes()` instead")]
7184
pub fn as_slice(&self) -> &[u8] {
7285
&self.bytes
7386
}
@@ -85,8 +98,27 @@ impl Multiaddr {
8598
/// assert_eq!(address.protocol(), vec![Protocol::IP4]);
8699
/// ```
87100
///
101+
#[deprecated(note="Use `.segments()` instead")]
88102
pub fn protocol(&self) -> Vec<Protocol> {
89-
parser::protocol_from_bytes(&self.bytes[..]).expect("failed to validate at construction")
103+
self.addr.iter().map(|s| s.protocol()).collect()
104+
}
105+
106+
/// Return the individual address segments of this multiaddr
107+
///
108+
/// # Examples
109+
///
110+
/// A single protocol
111+
///
112+
/// ```
113+
/// use std::net::Ipv4Addr;
114+
/// use multiaddr::{Multiaddr, protocol};
115+
///
116+
/// let address = Multiaddr::new("/ip4/127.0.0.1").unwrap();
117+
/// assert_eq!(address.segments(), [protocol::Addr::IP4(protocol::IP4Addr(Ipv4Addr::new(127, 0, 0, 1)))]);
118+
/// ```
119+
///
120+
pub fn segments(&self) -> &[Addr] {
121+
&self.addr
90122
}
91123

92124
/// Wrap a given Multiaddr and return the combination.
@@ -102,12 +134,10 @@ impl Multiaddr {
102134
/// ```
103135
///
104136
pub fn encapsulate<T: ToMultiaddr>(&self, input: T) -> Result<Multiaddr> {
105-
let new = input.to_multiaddr()?;
106-
let mut bytes = self.bytes.clone();
107-
108-
bytes.extend(new.to_bytes());
109-
110-
Ok(Multiaddr { bytes: bytes })
137+
let mut multiaddr = self.clone();
138+
multiaddr.addr.extend(input.to_multiaddr()?.addr);
139+
multiaddr.bytes = Self::_addr_to_bytes(&multiaddr.addr);
140+
Ok(multiaddr)
111141
}
112142

113143
/// Remove the outer most address from itself.
@@ -138,36 +168,16 @@ impl Multiaddr {
138168
/// ```
139169
///
140170
pub fn decapsulate<T: ToMultiaddr>(&self, input: T) -> Result<Multiaddr> {
141-
let input = input.to_multiaddr()?.to_bytes();
142-
143-
let bytes_len = self.bytes.len();
144-
let input_length = input.len();
145-
146-
let mut input_pos = 0;
147-
let mut matches = false;
148-
149-
for (i, _) in self.bytes.iter().enumerate() {
150-
let next = i + input_length;
171+
let input = input.to_multiaddr()?;
151172

152-
if next > bytes_len {
153-
continue;
173+
for (idx, addr_window) in self.addr.windows(input.addr.len()).enumerate() {
174+
if addr_window == input.addr.as_slice() {
175+
let addr = self.addr.iter().take(idx).map(|s| s.clone()).collect();
176+
return Ok(Multiaddr { bytes: Self::_addr_to_bytes(&addr), addr: addr });
154177
}
155-
156-
if &self.bytes[i..next] == input.as_slice() {
157-
matches = true;
158-
input_pos = i;
159-
break;
160-
}
161-
}
162-
163-
if !matches {
164-
return Ok(Multiaddr { bytes: self.bytes.clone() });
165178
}
166179

167-
let mut bytes = self.bytes.clone();
168-
bytes.truncate(input_pos);
169-
170-
Ok(Multiaddr { bytes: bytes })
180+
Ok(self.clone())
171181
}
172182
}
173183

Diff for: src/parser.rs

+23-77
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,48 @@
11
use std::str::FromStr;
2+
use std::fmt::Write;
23

3-
use integer_encoding::{VarInt, VarIntWriter};
4-
5-
use protocol::Protocol;
4+
use protocol::{Addr, AddressSegment, Protocol};
65
use {Result, Error};
76

8-
pub fn multiaddr_from_str(input: &str) -> Result<Vec<u8>> {
9-
// drdop trailing slashes
7+
pub fn multiaddr_from_str(input: &str) -> Result<Vec<Addr>> {
8+
// Drop trailing slashes then split address into segment parts
109
let input = input.trim_right_matches('/');
11-
12-
let mut bytes = vec![];
1310
let mut parts = input.split('/');
14-
let next = parts.next().ok_or(Error::InvalidMultiaddr)?;
1511

16-
if !next.is_empty() {
12+
// Expect address to start with just a slash ('/')
13+
let first = parts.next().ok_or(Error::InvalidMultiaddr)?;
14+
if !first.is_empty() {
1715
return Err(Error::InvalidMultiaddr);
1816
}
1917

18+
let mut multiaddr = Vec::with_capacity(input.split('/').count());
2019
while let Some(n) = parts.next() {
20+
// Determine segment protocol number and possible extra data
2121
let p = Protocol::from_str(n)?;
22-
23-
bytes.write_varint(p as u64)?;
24-
25-
if p.size() == 0 {
26-
continue;
27-
}
28-
29-
let next = match parts.next() {
30-
Some(path) => path,
31-
None => return Err(Error::MissingAddress),
22+
let s = match p.size() {
23+
0 => &"",
24+
_ => parts.next().ok_or(Error::MissingAddress)?
3225
};
3326

34-
bytes.extend(p.string_to_bytes(next)?);
35-
}
36-
37-
Ok(bytes)
38-
}
39-
40-
fn read_varint_code(input: &[u8]) -> Result<(u64, usize)> {
41-
let res = u64::decode_var(input);
42-
43-
if res.0 == 0 {
44-
return Err(Error::ParsingError)
45-
}
46-
47-
Ok(res)
48-
}
49-
50-
fn size_for_addr(protocol: Protocol, input: &[u8]) -> Result<(usize, usize)> {
51-
if protocol.size() > 0 {
52-
Ok((protocol.size() as usize / 8, 0))
53-
} else if protocol.size() == 0 {
54-
Ok((0, 0))
55-
} else {
56-
let (size, n) = read_varint_code(input)?;
57-
Ok((size as usize, n))
58-
}
59-
}
60-
61-
pub fn protocol_from_bytes(input: &[u8]) -> Result<Vec<Protocol>> {
62-
let mut ps = vec![];
63-
let mut i = 0;
64-
65-
while i < input.len() {
66-
let (code, n) = read_varint_code(&input[i..])?;
67-
let p = Protocol::from(code)?;
68-
ps.push(p);
69-
70-
i += n;
71-
let (size, adv) = size_for_addr(p, &input[i..])?;
72-
i += size + adv;
27+
// Parse and store segment data
28+
multiaddr.push(Addr::from_protocol_str(p, s)?);
7329
}
7430

75-
Ok(ps)
31+
Ok(multiaddr)
7632
}
7733

7834

79-
pub fn address_from_bytes(input: &[u8]) -> Result<String> {
80-
let mut protos = vec!["".to_string()];
81-
let mut i = 0;
82-
83-
while i < input.len() {
35+
pub fn multiaddr_to_str(addr: &Vec<Addr>) -> String {
36+
let mut result = String::new();
8437

85-
let (code, n) = read_varint_code(&input[i..])?;
86-
i += n;
38+
for addr_segment in addr {
39+
result.push('/');
40+
result.push_str(addr_segment.protocol().as_str());
8741

88-
let p = Protocol::from(code)?;
89-
protos.push(p.to_string());
90-
91-
let (size, adv) = size_for_addr(p, &input[i..])?;
92-
i += adv;
93-
94-
if let Some(s) = p.bytes_to_string(&input[i..i + size])? {
95-
protos.push(s);
42+
if addr_segment.protocol().size() != 0 {
43+
write!(result, "/{}", addr_segment).unwrap();
9644
}
97-
98-
i += size;
9945
}
10046

101-
Ok(protos.join("/"))
47+
result
10248
}

Diff for: src/protocol.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -535,10 +535,7 @@ macro_rules! build_enums {
535535

536536
impl ToString for Protocol {
537537
fn to_string(&self) -> String {
538-
match *self {
539-
$( Protocol::$var => $alph.to_string(), )*
540-
_ => unreachable!()
541-
}
538+
self.as_str().to_string()
542539
}
543540
}
544541

@@ -588,6 +585,15 @@ macro_rules! build_enums {
588585
_ => unreachable!()
589586
}
590587
}
588+
589+
/// Obtain the name of this protocol variant as an human-readable
590+
/// string
591+
pub fn as_str(&self) -> &str {
592+
match *self {
593+
$( Protocol::$var => $alph, )*
594+
_ => unreachable!()
595+
}
596+
}
591597
}
592598

593599

0 commit comments

Comments
 (0)