mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-29 09:41:34 +00:00
Remove Transport::nat_traversal
and refactor multiaddr
. (#1052)
The functionality is available through `Multiaddr::replace`. What we currently call "nat_traversal" is merley a replacement of an IP address prefix in a `Multiaddr`, hence it can be done directly on `Multiaddr` values instead of having to go through a `Transport`. In addition this PR consolidates changes made to `Multiaddr` in previous commits which resulted in lots of deprecations. It adds some more (see below for the complete list of API changes) and removes all deprecated functionality, requiring a minor version bump. Here are the changes to `multiaddr` compared to the currently published version: 1. Removed `into_bytes` (use `to_vec` instead). 2. Renamed `to_bytes` to `to_vec`. 3. Removed `from_bytes` (use the `TryFrom` impl instead). 4. Added `with_capacity`. 5. Added `len`. 6. Removed `as_slice` (use `AsRef` impl instead). 7. Removed `encapsulate` (use `push` or `with` instead). 8. Removed `decapsulate` (use `pop` instead). 9. Renamed `append` to `push`. 10. Added `with`. 11. Added `replace`. 12. Removed `ToMultiaddr` trait (use `TryFrom` instead).
This commit is contained in:
@ -1,14 +1,12 @@
|
||||
///! # multiaddr
|
||||
///!
|
||||
///! Implementation of [multiaddr](https://github.com/jbenet/multiaddr)
|
||||
///! in Rust.
|
||||
///! Implementation of [multiaddr](https://github.com/jbenet/multiaddr) in Rust.
|
||||
|
||||
pub use multihash;
|
||||
|
||||
mod protocol;
|
||||
mod errors;
|
||||
mod util;
|
||||
|
||||
use bytes::Bytes;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Deserializer,
|
||||
@ -17,9 +15,10 @@ use serde::{
|
||||
de::{self, Error as DeserializerError}
|
||||
};
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
fmt,
|
||||
iter::FromIterator,
|
||||
net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr},
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||
result::Result as StdResult,
|
||||
str::FromStr
|
||||
};
|
||||
@ -30,6 +29,309 @@ pub use self::protocol::Protocol;
|
||||
#[derive(PartialEq, Eq, Clone, Hash)]
|
||||
pub struct Multiaddr { bytes: Bytes }
|
||||
|
||||
impl Multiaddr {
|
||||
/// Create a new, empty multiaddress.
|
||||
pub fn empty() -> Self {
|
||||
Self { bytes: Bytes::new() }
|
||||
}
|
||||
|
||||
/// Create a new, empty multiaddress with the given capacity.
|
||||
pub fn with_capacity(n: usize) -> Self {
|
||||
Self { bytes: Bytes::with_capacity(n) }
|
||||
}
|
||||
|
||||
/// Return the length in bytes of this multiaddress.
|
||||
pub fn len(&self) -> usize {
|
||||
self.bytes.len()
|
||||
}
|
||||
|
||||
/// Return a copy of this [`Multiaddr`]'s byte representation.
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
Vec::from(&self.bytes[..])
|
||||
}
|
||||
|
||||
/// Adds an already-parsed address component to the end of this multiaddr.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||
///
|
||||
/// let mut address: Multiaddr = "/ip4/127.0.0.1".parse().unwrap();
|
||||
/// address.push(Protocol::Tcp(10000));
|
||||
/// assert_eq!(address, "/ip4/127.0.0.1/tcp/10000".parse().unwrap());
|
||||
/// ```
|
||||
///
|
||||
pub fn push(&mut self, p: Protocol<'_>) {
|
||||
let mut w = Vec::new();
|
||||
p.write_bytes(&mut w).expect("Writing to a `Vec` never fails.");
|
||||
self.bytes.extend_from_slice(&w);
|
||||
}
|
||||
|
||||
/// Pops the last `Protocol` of this multiaddr, or `None` if the multiaddr is empty.
|
||||
/// ```
|
||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||
///
|
||||
/// let mut address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap();
|
||||
///
|
||||
/// assert_eq!(address.pop().unwrap(), Protocol::Sctp(5678));
|
||||
/// assert_eq!(address.pop().unwrap(), Protocol::Udt);
|
||||
/// ```
|
||||
///
|
||||
pub fn pop<'a>(&mut self) -> Option<Protocol<'a>> {
|
||||
let mut slice = &self.bytes[..]; // the remaining multiaddr slice
|
||||
if slice.is_empty() {
|
||||
return None
|
||||
}
|
||||
let protocol = loop {
|
||||
let (p, s) = Protocol::from_bytes(slice).expect("`slice` is a valid `Protocol`.");
|
||||
if s.is_empty() {
|
||||
break p.acquire()
|
||||
}
|
||||
slice = s
|
||||
};
|
||||
let remaining_len = self.bytes.len() - slice.len();
|
||||
self.bytes.truncate(remaining_len);
|
||||
Some(protocol)
|
||||
}
|
||||
|
||||
/// Like [`push`] but more efficient if this `Multiaddr` has no living clones.
|
||||
pub fn with(self, p: Protocol<'_>) -> Self {
|
||||
match self.bytes.try_mut() {
|
||||
Ok(bytes) => {
|
||||
let mut w = util::BytesWriter(bytes);
|
||||
p.write_bytes(&mut w).expect("Writing to a `BytesWriter` never fails.");
|
||||
Multiaddr { bytes: w.0.freeze() }
|
||||
}
|
||||
Err(mut bytes) => {
|
||||
let mut w = Vec::new();
|
||||
p.write_bytes(&mut w).expect("Writing to a `Vec` never fails.");
|
||||
bytes.extend_from_slice(&w);
|
||||
Multiaddr { bytes }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the components of this multiaddress.
|
||||
///
|
||||
/// ```
|
||||
/// use std::net::Ipv4Addr;
|
||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||
///
|
||||
/// let address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap();
|
||||
///
|
||||
/// let components = address.iter().collect::<Vec<_>>();
|
||||
/// assert_eq!(components[0], Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
/// assert_eq!(components[1], Protocol::Udt);
|
||||
/// assert_eq!(components[2], Protocol::Sctp(5678));
|
||||
/// ```
|
||||
///
|
||||
pub fn iter(&self) -> Iter<'_> {
|
||||
Iter(&self.bytes)
|
||||
}
|
||||
|
||||
/// Replace a [`Protocol`] at some position in this `Multiaddr`.
|
||||
///
|
||||
/// The parameter `at` denotes the index of the protocol at which the function
|
||||
/// `by` will be applied to the current protocol, returning an optional replacement.
|
||||
///
|
||||
/// If `at` is out of bounds or `by` does not yield a replacement value,
|
||||
/// `None` will be returned. Otherwise a copy of this `Multiaddr` with the
|
||||
/// updated `Protocol` at position `at` will be returned.
|
||||
pub fn replace<'a, F>(&self, at: usize, by: F) -> Option<Multiaddr>
|
||||
where
|
||||
F: FnOnce(&Protocol) -> Option<Protocol<'a>>
|
||||
{
|
||||
let mut address = Multiaddr::with_capacity(self.len());
|
||||
let mut fun = Some(by);
|
||||
let mut replaced = false;
|
||||
|
||||
for (i, p) in self.iter().enumerate() {
|
||||
if i == at {
|
||||
let f = fun.take().expect("i == at only happens once");
|
||||
if let Some(q) = f(&p) {
|
||||
address = address.with(q);
|
||||
replaced = true;
|
||||
continue
|
||||
}
|
||||
return None
|
||||
}
|
||||
address = address.with(p)
|
||||
}
|
||||
|
||||
if replaced { Some(address) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Multiaddr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.to_string().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Multiaddr {
|
||||
/// Convert a Multiaddr to a string
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::Multiaddr;
|
||||
///
|
||||
/// let address: Multiaddr = "/ip4/127.0.0.1/udt".parse().unwrap();
|
||||
/// assert_eq!(address.to_string(), "/ip4/127.0.0.1/udt");
|
||||
/// ```
|
||||
///
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for s in self.iter() {
|
||||
s.to_string().fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Multiaddr {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.bytes.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Multiaddr {
|
||||
type Item = Protocol<'a>;
|
||||
type IntoIter = Iter<'a>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a> {
|
||||
Iter(&self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<Protocol<'a>> for Multiaddr {
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where
|
||||
T: IntoIterator<Item = Protocol<'a>>,
|
||||
{
|
||||
let mut writer = Vec::new();
|
||||
for cmp in iter {
|
||||
cmp.write_bytes(&mut writer).expect("Writing to a `Vec` never fails.");
|
||||
}
|
||||
Multiaddr { bytes: writer.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Multiaddr {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(input: &str) -> Result<Self> {
|
||||
let mut writer = Vec::new();
|
||||
let mut parts = input.split('/').peekable();
|
||||
|
||||
if Some("") != parts.next() {
|
||||
// A multiaddr must start with `/`
|
||||
return Err(Error::InvalidMultiaddr)
|
||||
}
|
||||
|
||||
while parts.peek().is_some() {
|
||||
let p = Protocol::from_str_parts(&mut parts)?;
|
||||
p.write_bytes(&mut writer).expect("Writing to a `Vec` never fails.");
|
||||
}
|
||||
|
||||
Ok(Multiaddr { bytes: writer.into() })
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over `Multiaddr` [`Protocol`]s.
|
||||
pub struct Iter<'a>(&'a [u8]);
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = Protocol<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.0.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (p, next_data) =
|
||||
Protocol::from_bytes(self.0).expect("`Multiaddr` is known to be valid.");
|
||||
|
||||
self.0 = next_data;
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Protocol<'a>> for Multiaddr {
|
||||
fn from(p: Protocol<'a>) -> Multiaddr {
|
||||
let mut w = Vec::new();
|
||||
p.write_bytes(&mut w).expect("Writing to a `Vec` never fails.");
|
||||
Multiaddr { bytes: w.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IpAddr> for Multiaddr {
|
||||
fn from(v: IpAddr) -> Multiaddr {
|
||||
match v {
|
||||
IpAddr::V4(a) => a.into(),
|
||||
IpAddr::V6(a) => a.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ipv4Addr> for Multiaddr {
|
||||
fn from(v: Ipv4Addr) -> Multiaddr {
|
||||
Protocol::Ip4(v).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ipv6Addr> for Multiaddr {
|
||||
fn from(v: Ipv6Addr) -> Multiaddr {
|
||||
Protocol::Ip6(v).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Bytes> for Multiaddr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(v: Bytes) -> Result<Self> {
|
||||
// Check if the argument is a valid `Multiaddr` by reading its protocols.
|
||||
let mut slice = &v[..];
|
||||
while !slice.is_empty() {
|
||||
let (_, s) = Protocol::from_bytes(slice)?;
|
||||
slice = s
|
||||
}
|
||||
Ok(Multiaddr { bytes: v.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<BytesMut> for Multiaddr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(v: BytesMut) -> Result<Self> {
|
||||
Multiaddr::try_from(v.freeze())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<u8>> for Multiaddr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(v: Vec<u8>) -> Result<Self> {
|
||||
Multiaddr::try_from(Bytes::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Multiaddr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(s: String) -> Result<Multiaddr> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for Multiaddr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(s: &'a str) -> Result<Multiaddr> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Multiaddr {
|
||||
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||
where
|
||||
@ -38,7 +340,7 @@ impl Serialize for Multiaddr {
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(&self.to_string())
|
||||
} else {
|
||||
serializer.serialize_bytes(self.as_slice())
|
||||
serializer.serialize_bytes(self.as_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,7 +365,7 @@ impl<'de> Deserialize<'de> for Multiaddr {
|
||||
let s = String::from_utf8(buf).map_err(DeserializerError::custom)?;
|
||||
s.parse().map_err(DeserializerError::custom)
|
||||
} else {
|
||||
Multiaddr::try_from_vec(buf).map_err(DeserializerError::custom)
|
||||
Multiaddr::try_from(buf).map_err(DeserializerError::custom)
|
||||
}
|
||||
}
|
||||
fn visit_str<E: de::Error>(self, v: &str) -> StdResult<Self::Value, E> {
|
||||
@ -82,7 +384,7 @@ impl<'de> Deserialize<'de> for Multiaddr {
|
||||
self.visit_byte_buf(v.into())
|
||||
}
|
||||
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> StdResult<Self::Value, E> {
|
||||
Multiaddr::try_from_vec(v).map_err(DeserializerError::custom)
|
||||
Multiaddr::try_from(v).map_err(DeserializerError::custom)
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,384 +396,17 @@ impl<'de> Deserialize<'de> for Multiaddr {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Multiaddr {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.to_string().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Multiaddr {
|
||||
/// Convert a Multiaddr to a string
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::Multiaddr;
|
||||
///
|
||||
/// let address: Multiaddr = "/ip4/127.0.0.1/udt".parse().unwrap();
|
||||
/// assert_eq!(address.to_string(), "/ip4/127.0.0.1/udt");
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for s in self.iter() {
|
||||
s.to_string().fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Multiaddr {
|
||||
#[deprecated(since = "0.2.1", note = "Use `Multiaddr::to_vec` instead.")]
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
self.to_vec()
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.2.1", note = "Use `Multiaddr::to_vec` instead.")]
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.to_vec()
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.2.1", note = "Use `Multiaddr::try_from_vec` instead.")]
|
||||
pub fn from_bytes(bytes: Vec<u8>) -> Result<Multiaddr> {
|
||||
Self::try_from_vec(bytes)
|
||||
}
|
||||
|
||||
/// Create a new, empty multiaddress.
|
||||
pub fn empty() -> Multiaddr {
|
||||
Multiaddr { bytes: Bytes::new() }
|
||||
}
|
||||
|
||||
/// Return a copy to disallow changing the bytes directly
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
Vec::from(&self.bytes[..])
|
||||
}
|
||||
|
||||
/// Produces a `Multiaddr` from its bytes representation.
|
||||
pub fn try_from_vec(v: Vec<u8>) -> Result<Multiaddr> {
|
||||
// Check if the argument is a valid `Multiaddr`
|
||||
// by reading its protocols.
|
||||
let mut ptr = &v[..];
|
||||
while !ptr.is_empty() {
|
||||
let (_, new_ptr) = Protocol::from_bytes(ptr)?;
|
||||
ptr = new_ptr;
|
||||
}
|
||||
Ok(Multiaddr { bytes: v.into() })
|
||||
}
|
||||
|
||||
/// Extracts a slice containing the entire underlying vector.
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
&self.bytes
|
||||
}
|
||||
|
||||
/// Wrap a given Multiaddr and return the combination.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::Multiaddr;
|
||||
///
|
||||
/// let address: Multiaddr = "/ip4/127.0.0.1".parse().unwrap();
|
||||
/// let nested = address.encapsulate("/udt").unwrap();
|
||||
/// assert_eq!(nested, "/ip4/127.0.0.1/udt".parse().unwrap());
|
||||
/// ```
|
||||
///
|
||||
pub fn encapsulate<T: ToMultiaddr>(&self, input: T) -> Result<Multiaddr> {
|
||||
let new = input.to_multiaddr()?;
|
||||
let mut bytes = self.bytes.clone();
|
||||
bytes.extend_from_slice(&new.bytes);
|
||||
Ok(Multiaddr { bytes })
|
||||
}
|
||||
|
||||
/// Adds an already-parsed address component to the end of this multiaddr.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||
///
|
||||
/// let mut address: Multiaddr = "/ip4/127.0.0.1".parse().unwrap();
|
||||
/// address.append(Protocol::Tcp(10000));
|
||||
/// assert_eq!(address, "/ip4/127.0.0.1/tcp/10000".parse().unwrap());
|
||||
/// ```
|
||||
///
|
||||
pub fn append(&mut self, p: Protocol<'_>) {
|
||||
let mut w = Vec::new();
|
||||
p.write_bytes(&mut w).expect("writing to a Vec never fails");
|
||||
self.bytes.extend_from_slice(&w);
|
||||
}
|
||||
|
||||
/// Remove the outermost address.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::{Multiaddr, ToMultiaddr};
|
||||
///
|
||||
/// let address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap();
|
||||
/// let unwrapped = address.decapsulate("/udt").unwrap();
|
||||
/// assert_eq!(unwrapped, "/ip4/127.0.0.1".parse().unwrap());
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// address.decapsulate("/udt").unwrap(),
|
||||
/// "/ip4/127.0.0.1".to_multiaddr().unwrap()
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// Returns the original if the passed in address is not found
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::ToMultiaddr;
|
||||
///
|
||||
/// let address = "/ip4/127.0.0.1/udt/sctp/5678".to_multiaddr().unwrap();
|
||||
/// let unwrapped = address.decapsulate("/ip4/127.0.1.1").unwrap();
|
||||
/// assert_eq!(unwrapped, address);
|
||||
/// ```
|
||||
///
|
||||
pub fn decapsulate<T: ToMultiaddr>(&self, input: T) -> Result<Multiaddr> {
|
||||
let input = input.to_multiaddr()?.to_vec();
|
||||
|
||||
let bytes_len = self.bytes.len();
|
||||
let input_length = input.len();
|
||||
|
||||
let mut input_pos = 0;
|
||||
let mut matches = false;
|
||||
|
||||
for (i, _) in self.bytes.iter().enumerate() {
|
||||
let next = i + input_length;
|
||||
|
||||
if next > bytes_len {
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.bytes[i..next] == input[..] {
|
||||
matches = true;
|
||||
input_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !matches {
|
||||
return Ok(self.clone())
|
||||
}
|
||||
|
||||
let mut bytes = self.bytes.clone();
|
||||
bytes.truncate(input_pos);
|
||||
|
||||
Ok(Multiaddr { bytes })
|
||||
}
|
||||
|
||||
/// Returns the components of this multiaddress.
|
||||
///
|
||||
/// ```
|
||||
/// use std::net::Ipv4Addr;
|
||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||
///
|
||||
/// let address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap();
|
||||
///
|
||||
/// let components = address.iter().collect::<Vec<_>>();
|
||||
/// assert_eq!(components[0], Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
/// assert_eq!(components[1], Protocol::Udt);
|
||||
/// assert_eq!(components[2], Protocol::Sctp(5678));
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
pub fn iter(&self) -> Iter<'_> {
|
||||
Iter(&self.bytes)
|
||||
}
|
||||
|
||||
/// Pops the last `Protocol` of this multiaddr, or `None` if the multiaddr is empty.
|
||||
/// ```
|
||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||
///
|
||||
/// let mut address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap();
|
||||
///
|
||||
/// assert_eq!(address.pop().unwrap(), Protocol::Sctp(5678));
|
||||
/// assert_eq!(address.pop().unwrap(), Protocol::Udt);
|
||||
/// ```
|
||||
///
|
||||
pub fn pop<'a>(&mut self) -> Option<Protocol<'a>> {
|
||||
// Note: could be more optimized
|
||||
let mut list = self.iter().map(|p| p.acquire()).collect::<Vec<_>>();
|
||||
let last_elem = list.pop();
|
||||
*self = list.into_iter().collect();
|
||||
last_elem
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Protocol<'a>> for Multiaddr {
|
||||
fn from(p: Protocol<'a>) -> Multiaddr {
|
||||
let mut w = Vec::new();
|
||||
p.write_bytes(&mut w).expect("writing to a Vec never fails");
|
||||
Multiaddr { bytes: w.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Multiaddr {
|
||||
type Item = Protocol<'a>;
|
||||
type IntoIter = Iter<'a>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Iter<'a> {
|
||||
Iter(&self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<Protocol<'a>> for Multiaddr {
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where
|
||||
T: IntoIterator<Item = Protocol<'a>>,
|
||||
{
|
||||
let mut writer = Vec::new();
|
||||
for cmp in iter {
|
||||
cmp.write_bytes(&mut writer).expect("writing to a Vec never fails");
|
||||
}
|
||||
Multiaddr { bytes: writer.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Multiaddr {
|
||||
type Err = Error;
|
||||
|
||||
#[inline]
|
||||
fn from_str(input: &str) -> Result<Self> {
|
||||
let mut writer = Vec::new();
|
||||
let mut parts = input.split('/').peekable();
|
||||
|
||||
if Some("") != parts.next() {
|
||||
// A multiaddr must start with `/`
|
||||
return Err(Error::InvalidMultiaddr)
|
||||
}
|
||||
|
||||
while parts.peek().is_some() {
|
||||
let p = Protocol::from_str_parts(&mut parts)?;
|
||||
p.write_bytes(&mut writer).expect("writing to a Vec never fails");
|
||||
}
|
||||
|
||||
Ok(Multiaddr { bytes: writer.into() })
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for the address components in a multiaddr.
|
||||
pub struct Iter<'a>(&'a [u8]);
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = Protocol<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.0.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (p, next_data) =
|
||||
Protocol::from_bytes(self.0).expect("multiaddr is known to be valid");
|
||||
|
||||
self.0 = next_data;
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for objects which can be converted to a
|
||||
/// Multiaddr.
|
||||
///
|
||||
/// This trait is implemented by default for
|
||||
///
|
||||
/// * `SocketAddr`, `SocketAddrV4` and `SocketAddrV6`, assuming that the
|
||||
/// the given port is a tcp port.
|
||||
///
|
||||
/// * `Ipv4Addr`, `Ipv6Addr`
|
||||
///
|
||||
/// * `String` and `&str`, requiring the default string format for a Multiaddr.
|
||||
///
|
||||
pub trait ToMultiaddr {
|
||||
/// Converts this object to a Multiaddr
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Any errors encountered during parsing will be returned
|
||||
/// as an `Err`.
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr>;
|
||||
}
|
||||
|
||||
impl ToMultiaddr for SocketAddr {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
match *self {
|
||||
SocketAddr::V4(ref a) => (*a).to_multiaddr(),
|
||||
SocketAddr::V6(ref a) => (*a).to_multiaddr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMultiaddr for SocketAddrV4 {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
let mut m = self.ip().to_multiaddr()?;
|
||||
m.append(Protocol::Tcp(self.port()));
|
||||
Ok(m)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMultiaddr for SocketAddrV6 {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
// TODO: Should we handle `flowinfo` and `scope_id`?
|
||||
let mut m = self.ip().to_multiaddr()?;
|
||||
m.append(Protocol::Tcp(self.port()));
|
||||
Ok(m)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMultiaddr for IpAddr {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
match *self {
|
||||
IpAddr::V4(ref a) => (*a).to_multiaddr(),
|
||||
IpAddr::V6(ref a) => (*a).to_multiaddr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMultiaddr for Ipv4Addr {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
Ok(Protocol::Ip4(*self).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMultiaddr for Ipv6Addr {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
Ok(Protocol::Ip6(*self).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMultiaddr for String {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
self.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToMultiaddr for &'a str {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
self.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMultiaddr for Multiaddr {
|
||||
fn to_multiaddr(&self) -> Result<Multiaddr> {
|
||||
Ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Easy way for a user to create a `Multiaddr`.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use parity_multiaddr::multiaddr;
|
||||
/// # fn main() {
|
||||
/// let _addr = multiaddr![Ip4([127, 0, 0, 1]), Tcp(10500u16)];
|
||||
/// # }
|
||||
/// let addr = multiaddr!(Ip4([127, 0, 0, 1]), Tcp(10500u16));
|
||||
/// ```
|
||||
///
|
||||
/// Each element passed to `multiaddr![]` should be a variant of the `Protocol` enum. The
|
||||
/// optional parameter is casted into the proper type with the `Into` trait.
|
||||
/// Each element passed to `multiaddr!` should be a variant of the `Protocol` enum. The
|
||||
/// optional parameter is turned into the proper type with the `Into` trait.
|
||||
///
|
||||
/// For example, `Ip4([127, 0, 0, 1])` works because `Ipv4Addr` implements `From<[u8; 4]>`.
|
||||
#[macro_export]
|
||||
@ -490,3 +425,4 @@ macro_rules! multiaddr {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user