Refactor multiaddr crate. (#498)

Refactor multiaddr crate.

- Remove `AddrComponent`. Instead `Protocol` directly contains its
associated data.

- Various smaller changes around conversions to Multiaddr from other
types, e.g. socket addresses.

- Expand tests to include property tests which test encoding/decoding
identity.
This commit is contained in:
Toralf Wittner
2018-09-20 19:51:00 +02:00
committed by GitHub
parent 1969bde4fe
commit 84b089cacc
18 changed files with 669 additions and 748 deletions

View File

@ -9,23 +9,25 @@ pub type Result<T> = ::std::result::Result<T, Error>;
/// Error types
#[derive(Debug)]
pub enum Error {
UnknownProtocol,
UnknownProtocolString,
DataLessThanLen,
InvalidMultiaddr,
MissingAddress,
ParsingError(Box<error::Error + Send + Sync>),
InvalidUvar(decode::Error)
InvalidProtocolString,
InvalidUvar(decode::Error),
ParsingError(Box<dyn error::Error + Send + Sync>),
UnknownProtocolId(u32),
UnknownProtocolString
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::UnknownProtocol => f.write_str("unknown protocol"),
Error::UnknownProtocolString => f.write_str("unknown protocol string"),
Error::DataLessThanLen => f.write_str("we have less data than indicated by length"),
Error::InvalidMultiaddr => f.write_str("invalid multiaddr"),
Error::MissingAddress => f.write_str("protocol requires address, none given"),
Error::InvalidProtocolString => f.write_str("invalid protocol string"),
Error::InvalidUvar(e) => write!(f, "failed to decode unsigned varint: {}", e),
Error::ParsingError(e) => write!(f, "failed to parse: {}", e),
Error::InvalidUvar(e) => write!(f, "failed to decode unsigned varint: {}", e)
Error::UnknownProtocolId(id) => write!(f, "unknown protocol id: {}", id),
Error::UnknownProtocolString => f.write_str("unknown protocol string")
}
}
}

View File

@ -12,22 +12,26 @@ pub extern crate multihash;
mod protocol;
mod errors;
use serde::{
Deserialize,
Deserializer,
Serialize,
Serializer,
de::{self, Error as DeserializerError}
};
use std::{
fmt,
iter::FromIterator,
net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr},
result::Result as StdResult,
str::FromStr
};
pub use errors::{Result, Error};
pub use protocol::{Protocol, ProtocolArgSize, AddrComponent};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeserializerError};
use std::fmt;
use std::result::Result as StdResult;
use std::iter::FromIterator;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
pub use protocol::Protocol;
/// Representation of a Multiaddr.
#[derive(PartialEq, Eq, Clone, Hash)]
pub struct Multiaddr {
bytes: Vec<u8>,
}
pub struct Multiaddr { bytes: Vec<u8> }
impl Serialize for Multiaddr {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
@ -35,7 +39,6 @@ impl Serialize for Multiaddr {
S: Serializer,
{
if serializer.is_human_readable() {
// Serialize to a human-readable string "2015-05-15T17:01:00Z".
self.to_string().serialize(serializer)
} else {
self.to_bytes().serialize(serializer)
@ -48,12 +51,38 @@ impl<'de> Deserialize<'de> for Multiaddr {
where
D: Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Multiaddr;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("multiaddress")
}
fn visit_str<E: de::Error>(self, v: &str) -> StdResult<Self::Value, E> {
v.parse().map_err(DeserializerError::custom)
}
fn visit_borrowed_str<E: de::Error>(self, v: &'de str) -> StdResult<Self::Value, E> {
self.visit_str(v)
}
fn visit_string<E: de::Error>(self, v: String) -> StdResult<Self::Value, E> {
self.visit_str(&v)
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> StdResult<Self::Value, E> {
self.visit_byte_buf(v.into())
}
fn visit_borrowed_bytes<E: de::Error>(self, v: &'de [u8]) -> StdResult<Self::Value, E> {
self.visit_byte_buf(v.into())
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> StdResult<Self::Value, E> {
Multiaddr::from_bytes(v).map_err(DeserializerError::custom)
}
}
if deserializer.is_human_readable() {
let addr: String = Deserialize::deserialize(deserializer)?;
addr.parse::<Multiaddr>().map_err(|err| DeserializerError::custom(err))
deserializer.deserialize_str(Visitor)
} else {
let addr: Vec<u8> = Deserialize::deserialize(deserializer)?;
Multiaddr::from_bytes(addr).map_err(|err| DeserializerError::custom(err))
deserializer.deserialize_bytes(Visitor)
}
}
}
@ -95,7 +124,7 @@ impl Multiaddr {
/// Return a copy to disallow changing the bytes directly
pub fn to_bytes(&self) -> Vec<u8> {
self.bytes.to_owned()
self.bytes.clone()
}
/// Produces a `Multiaddr` from its bytes representation.
@ -103,11 +132,10 @@ impl Multiaddr {
{
let mut ptr = &bytes[..];
while !ptr.is_empty() {
let (_, new_ptr) = AddrComponent::from_bytes(ptr)?;
let (_, new_ptr) = Protocol::from_bytes(ptr)?;
ptr = new_ptr;
}
}
Ok(Multiaddr { bytes })
}
@ -116,25 +144,6 @@ impl Multiaddr {
&self.bytes
}
/// Return a list of protocols
///
/// # Examples
///
/// A single protocol
///
/// ```
/// use multiaddr::{Multiaddr, Protocol};
///
/// let address: Multiaddr = "/ip4/127.0.0.1".parse().unwrap();
/// assert_eq!(address.protocol(), vec![Protocol::IP4]);
/// ```
///
#[inline]
#[deprecated(note = "Use `self.iter().map(|addr| addr.protocol_id())` instead")]
pub fn protocol(&self) -> Vec<Protocol> {
self.iter().map(|addr| addr.protocol_id()).collect()
}
/// Wrap a given Multiaddr and return the combination.
///
/// # Examples
@ -150,10 +159,8 @@ impl Multiaddr {
pub fn encapsulate<T: ToMultiaddr>(&self, input: T) -> Result<Multiaddr> {
let new = input.to_multiaddr()?;
let mut bytes = self.bytes.clone();
bytes.extend(new.to_bytes());
Ok(Multiaddr { bytes: bytes })
Ok(Multiaddr { bytes })
}
/// Adds an already-parsed address component to the end of this multiaddr.
@ -161,18 +168,18 @@ impl Multiaddr {
/// # Examples
///
/// ```
/// use multiaddr::{Multiaddr, AddrComponent};
/// use multiaddr::{Multiaddr, Protocol};
///
/// let mut address: Multiaddr = "/ip4/127.0.0.1".parse().unwrap();
/// address.append(AddrComponent::TCP(10000));
/// address.append(Protocol::Tcp(10000));
/// assert_eq!(address, "/ip4/127.0.0.1/tcp/10000".parse().unwrap());
/// ```
///
#[inline]
pub fn append(&mut self, component: AddrComponent) {
component.write_bytes(&mut self.bytes).expect(
"writing to a Vec never fails",
)
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.
@ -218,7 +225,7 @@ impl Multiaddr {
continue;
}
if &self.bytes[i..next] == input.as_slice() {
if self.bytes[i..next] == input[..] {
matches = true;
input_pos = i;
break;
@ -232,22 +239,21 @@ impl Multiaddr {
let mut bytes = self.bytes.clone();
bytes.truncate(input_pos);
Ok(Multiaddr { bytes: bytes })
Ok(Multiaddr { bytes })
}
/// Returns the components of this multiaddress.
///
/// ```
/// use std::net::Ipv4Addr;
/// use multiaddr::AddrComponent;
/// use multiaddr::Multiaddr;
/// use 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], AddrComponent::IP4(Ipv4Addr::new(127, 0, 0, 1)));
/// assert_eq!(components[1], AddrComponent::UDT);
/// assert_eq!(components[2], AddrComponent::SCTP(5678));
/// 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]
@ -255,38 +261,35 @@ impl Multiaddr {
Iter(&self.bytes)
}
/// Pops the last `AddrComponent` of this multiaddr, or `None` if the multiaddr is empty.
/// Pops the last `Protocol` of this multiaddr, or `None` if the multiaddr is empty.
/// ```
/// use multiaddr::AddrComponent;
/// use multiaddr::Multiaddr;
/// use multiaddr::{Multiaddr, Protocol};
///
/// let mut address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap();
///
/// assert_eq!(address.pop().unwrap(), AddrComponent::SCTP(5678));
/// assert_eq!(address.pop().unwrap(), AddrComponent::UDT);
/// assert_eq!(address.pop().unwrap(), Protocol::Sctp(5678));
/// assert_eq!(address.pop().unwrap(), Protocol::Udt);
/// ```
///
pub fn pop<'a>(&mut self) -> Option<AddrComponent<'a>> {
pub fn pop<'a>(&mut self) -> Option<Protocol<'a>> {
// Note: could be more optimized
let mut list = self.iter().map(AddrComponent::acquire).collect::<Vec<_>>();
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<AddrComponent<'a>> for Multiaddr {
fn from(addr: AddrComponent) -> Multiaddr {
let mut out = Vec::new();
addr.write_bytes(&mut out).expect(
"writing to a Vec never fails",
);
Multiaddr { bytes: out }
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 }
}
}
impl<'a> IntoIterator for &'a Multiaddr {
type Item = AddrComponent<'a>;
type Item = Protocol<'a>;
type IntoIter = Iter<'a>;
#[inline]
@ -295,18 +298,16 @@ impl<'a> IntoIterator for &'a Multiaddr {
}
}
impl<'a> FromIterator<AddrComponent<'a>> for Multiaddr {
impl<'a> FromIterator<Protocol<'a>> for Multiaddr {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = AddrComponent<'a>>,
T: IntoIterator<Item = Protocol<'a>>,
{
let mut bytes = Vec::new();
let mut writer = Vec::new();
for cmp in iter {
cmp.write_bytes(&mut bytes).expect(
"writing to a Vec never fails",
);
cmp.write_bytes(&mut writer).expect("writing to a Vec never fails");
}
Multiaddr { bytes: bytes }
Multiaddr { bytes: writer }
}
}
@ -315,32 +316,20 @@ impl FromStr for Multiaddr {
#[inline]
fn from_str(input: &str) -> Result<Self> {
let mut bytes = Vec::new();
let mut writer = Vec::new();
let mut parts = input.split('/').peekable();
let mut parts = input.split('/');
// A multiaddr must start with `/`
if !parts.next().ok_or(Error::InvalidMultiaddr)?.is_empty() {
return Err(Error::InvalidMultiaddr);
if Some("") != parts.next() {
// A multiaddr must start with `/`
return Err(Error::InvalidMultiaddr)
}
while let Some(part) = parts.next() {
let protocol: Protocol = part.parse()?;
let addr_component = match protocol.size() {
ProtocolArgSize::Fixed { bytes: 0 } => {
protocol.parse_data("")? // TODO: bad design
}
_ => {
let data = parts.next().ok_or(Error::MissingAddress)?;
protocol.parse_data(data)?
}
};
addr_component.write_bytes(&mut bytes).expect(
"writing to a Vec never fails",
);
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: bytes })
Ok(Multiaddr { bytes: writer })
}
}
@ -348,17 +337,18 @@ impl FromStr for Multiaddr {
pub struct Iter<'a>(&'a [u8]);
impl<'a> Iterator for Iter<'a> {
type Item = AddrComponent<'a>;
type Item = Protocol<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.0.is_empty() {
return None;
}
let (component, next_data) =
AddrComponent::from_bytes(self.0).expect("multiaddr is known to be valid");
let (p, next_data) =
Protocol::from_bytes(self.0).expect("multiaddr is known to be valid");
self.0 = next_data;
Some(component)
Some(p)
}
}
@ -395,14 +385,18 @@ impl ToMultiaddr for SocketAddr {
impl ToMultiaddr for SocketAddrV4 {
fn to_multiaddr(&self) -> Result<Multiaddr> {
format!("/ip4/{}/tcp/{}", self.ip(), self.port()).parse()
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 how should we handle `flowinfo` and `scope_id`?
format!("/ip6/{}/tcp/{}", self.ip(), self.port()).parse()
// TODO: Should we handle `flowinfo` and `scope_id`?
let mut m = self.ip().to_multiaddr()?;
m.append(Protocol::Tcp(self.port()));
Ok(m)
}
}
@ -417,13 +411,13 @@ impl ToMultiaddr for IpAddr {
impl ToMultiaddr for Ipv4Addr {
fn to_multiaddr(&self) -> Result<Multiaddr> {
format!("/ip4/{}", &self).parse()
Ok(Protocol::Ip4(*self).into())
}
}
impl ToMultiaddr for Ipv6Addr {
fn to_multiaddr(&self) -> Result<Multiaddr> {
format!("/ip6/{}", &self).parse()
Ok(Protocol::Ip6(*self).into())
}
}
@ -444,3 +438,4 @@ impl ToMultiaddr for Multiaddr {
Ok(self.clone())
}
}

View File

@ -1,390 +1,179 @@
use bs58;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use multihash::Multihash;
use std::{
borrow::Cow,
convert::From,
fmt,
io::{Cursor, Write, Result as IoResult},
io::{self, Cursor, Write},
net::{Ipv4Addr, Ipv6Addr},
str::{self, FromStr}
};
use multihash::Multihash;
use unsigned_varint::{encode, decode};
use {Result, Error};
///! # Protocol
///!
///! A type to describe the possible protocol used in a
///! Multiaddr.
const DCCP: u32 = 33;
const DNS4: u32 = 54;
const DNS6: u32 = 55;
const HTTP: u32 = 480;
const HTTPS: u32 = 443;
const IP4: u32 = 4;
const IP6: u32 = 41;
const P2P_WEBRTC_DIRECT: u32 = 276;
const P2P_WEBRTC_STAR: u32 = 275;
const P2P_WEBSOCKET_STAR: u32 = 479;
const MEMORY: u32 = 777;
const ONION: u32 = 444;
const P2P: u32 = 421;
const P2P_CIRCUIT: u32 = 290;
const QUIC: u32 = 460;
const SCTP: u32 = 132;
const TCP: u32 = 6;
const UDP: u32 = 17;
const UDT: u32 = 301;
const UNIX: u32 = 400;
const UTP: u32 = 302;
const WS: u32 = 477;
const WSS: u32 = 478;
/// Protocol is the list of all possible protocols.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Protocol {
IP4 = 4,
TCP = 6,
UDP = 17,
DCCP = 33,
IP6 = 41,
DNS4 = 54,
DNS6 = 55,
SCTP = 132,
UDT = 301,
UTP = 302,
UNIX = 400,
P2P = 421,
HTTP = 480,
HTTPS = 443,
ONION = 444,
QUIC = 460,
WS = 477,
WSS = 478,
Libp2pWebsocketStar = 479,
Libp2pWebrtcStar = 275,
Libp2pWebrtcDirect = 276,
P2pCircuit = 290,
Memory = 777, // TODO: not standard: https://github.com/multiformats/multiaddr/pull/71
/// `Protocol` describes all possible multiaddress protocols.
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Protocol<'a> {
Dccp(u16),
Dns4(Cow<'a, str>),
Dns6(Cow<'a, str>),
Http,
Https,
Ip4(Ipv4Addr),
Ip6(Ipv6Addr),
P2pWebRtcDirect,
P2pWebRtcStar,
P2pWebSocketStar,
Memory,
Onion(Cow<'a, [u8]>),
P2p(Multihash),
P2pCircuit,
Quic,
Sctp(u16),
Tcp(u16),
Udp(u16),
Udt,
Unix(Cow<'a, str>),
Utp,
Ws,
Wss
}
impl From<Protocol> for u32 {
fn from(proto: Protocol) -> u32 {
proto as u32
}
}
impl From<Protocol> for u64 {
fn from(proto: Protocol) -> u64 {
proto as u32 as u64
}
}
impl fmt::Display for Protocol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Protocol::IP4 => f.write_str("ip4"),
Protocol::TCP => f.write_str("tcp"),
Protocol::UDP => f.write_str("udp"),
Protocol::DCCP => f.write_str("dccp"),
Protocol::IP6 => f.write_str("ip6"),
Protocol::DNS4 => f.write_str("dns4"),
Protocol::DNS6 => f.write_str("dns6"),
Protocol::SCTP => f.write_str("sctp"),
Protocol::UDT => f.write_str("udt"),
Protocol::UTP => f.write_str("utp"),
Protocol::UNIX => f.write_str("unix"),
Protocol::P2P => f.write_str("p2p"),
Protocol::HTTP => f.write_str("http"),
Protocol::HTTPS => f.write_str("https"),
Protocol::ONION => f.write_str("onion"),
Protocol::QUIC => f.write_str("quic"),
Protocol::WS => f.write_str("ws"),
Protocol::WSS => f.write_str("wss"),
Protocol::Libp2pWebsocketStar => f.write_str("p2p-websocket-star"),
Protocol::Libp2pWebrtcStar => f.write_str("p2p-webrtc-star"),
Protocol::Libp2pWebrtcDirect => f.write_str("p2p-webrtc-direct"),
Protocol::P2pCircuit => f.write_str("p2p-circuit"),
Protocol::Memory => f.write_str("memory"),
}
}
}
impl FromStr for Protocol {
type Err = Error;
fn from_str(raw: &str) -> Result<Self> {
match raw {
"ip4" => Ok(Protocol::IP4),
"tcp" => Ok(Protocol::TCP),
"udp" => Ok(Protocol::UDP),
"dccp" => Ok(Protocol::DCCP),
"ip6" => Ok(Protocol::IP6),
"dns4" => Ok(Protocol::DNS4),
"dns6" => Ok(Protocol::DNS6),
"sctp" => Ok(Protocol::SCTP),
"udt" => Ok(Protocol::UDT),
"utp" => Ok(Protocol::UTP),
"unix" => Ok(Protocol::UNIX),
"p2p" => Ok(Protocol::P2P),
"http" => Ok(Protocol::HTTP),
"https" => Ok(Protocol::HTTPS),
"onion" => Ok(Protocol::ONION),
"quic" => Ok(Protocol::QUIC),
"ws" => Ok(Protocol::WS),
"wss" => Ok(Protocol::WSS),
"p2p-websocket-star" => Ok(Protocol::Libp2pWebsocketStar),
"p2p-webrtc-star" => Ok(Protocol::Libp2pWebrtcStar),
"p2p-webrtc-direct" => Ok(Protocol::Libp2pWebrtcDirect),
impl<'a> Protocol<'a> {
/// Parse a protocol value from the given iterator of string slices.
///
/// The parsing only consumes the minimum amount of string slices necessary to
/// produce a well-formed protocol. The same iterator can thus be used to parse
/// a sequence of protocols in succession. It is up to client code to check
/// that iteration has finished whenever appropriate.
pub fn from_str_parts<I>(mut iter: I) -> Result<Self>
where
I: Iterator<Item=&'a str>
{
match iter.next().ok_or(Error::InvalidProtocolString)? {
"ip4" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Ip4(Ipv4Addr::from_str(s)?))
}
"tcp" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Tcp(s.parse()?))
}
"udp" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Udp(s.parse()?))
}
"dccp" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Dccp(s.parse()?))
}
"ip6" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Ip6(Ipv6Addr::from_str(s)?))
}
"dns4" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Dns4(Cow::Borrowed(s)))
}
"dns6" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Dns6(Cow::Borrowed(s)))
}
"sctp" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Sctp(s.parse()?))
}
"udt" => Ok(Protocol::Udt),
"utp" => Ok(Protocol::Utp),
"unix" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
Ok(Protocol::Unix(Cow::Borrowed(s)))
}
"p2p" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
let decoded = bs58::decode(s).into_vec()?;
Ok(Protocol::P2p(Multihash::from_bytes(decoded)?))
}
"http" => Ok(Protocol::Http),
"https" => Ok(Protocol::Https),
"onion" => unimplemented!(), // FIXME
"quic" => Ok(Protocol::Quic),
"ws" => Ok(Protocol::Ws),
"wss" => Ok(Protocol::Wss),
"p2p-websocket-star" => Ok(Protocol::P2pWebSocketStar),
"p2p-webrtc-star" => Ok(Protocol::P2pWebRtcStar),
"p2p-webrtc-direct" => Ok(Protocol::P2pWebRtcDirect),
"p2p-circuit" => Ok(Protocol::P2pCircuit),
"memory" => Ok(Protocol::Memory),
_ => Err(Error::UnknownProtocolString),
}
}
}
impl Protocol {
/// Convert a `u64` based code to a `Protocol`.
///
/// # Examples
///
/// ```
/// use multiaddr::Protocol;
///
/// assert_eq!(Protocol::from(6).unwrap(), Protocol::TCP);
/// assert!(Protocol::from(455).is_err());
/// ```
pub fn from(raw: u64) -> Result<Protocol> {
match raw {
4 => Ok(Protocol::IP4),
6 => Ok(Protocol::TCP),
17 => Ok(Protocol::UDP),
33 => Ok(Protocol::DCCP),
41 => Ok(Protocol::IP6),
54 => Ok(Protocol::DNS4),
55 => Ok(Protocol::DNS6),
132 => Ok(Protocol::SCTP),
301 => Ok(Protocol::UDT),
302 => Ok(Protocol::UTP),
400 => Ok(Protocol::UNIX),
421 => Ok(Protocol::P2P),
480 => Ok(Protocol::HTTP),
443 => Ok(Protocol::HTTPS),
444 => Ok(Protocol::ONION),
460 => Ok(Protocol::QUIC),
477 => Ok(Protocol::WS),
478 => Ok(Protocol::WSS),
479 => Ok(Protocol::Libp2pWebsocketStar),
275 => Ok(Protocol::Libp2pWebrtcStar),
276 => Ok(Protocol::Libp2pWebrtcDirect),
290 => Ok(Protocol::P2pCircuit),
777 => Ok(Protocol::Memory),
_ => Err(Error::UnknownProtocol),
_ => Err(Error::UnknownProtocolString)
}
}
/// Get the size from a `Protocol`.
///
/// # Examples
///
/// ```
/// use multiaddr::Protocol;
/// use multiaddr::ProtocolArgSize;
///
/// assert_eq!(Protocol::TCP.size(), ProtocolArgSize::Fixed { bytes: 2 });
/// ```
///
pub fn size(&self) -> ProtocolArgSize {
match *self {
Protocol::IP4 => ProtocolArgSize::Fixed { bytes: 4 },
Protocol::TCP => ProtocolArgSize::Fixed { bytes: 2 },
Protocol::UDP => ProtocolArgSize::Fixed { bytes: 2 },
Protocol::DCCP => ProtocolArgSize::Fixed { bytes: 2 },
Protocol::IP6 => ProtocolArgSize::Fixed { bytes: 16 },
Protocol::DNS4 => ProtocolArgSize::Variable,
Protocol::DNS6 => ProtocolArgSize::Variable,
Protocol::SCTP => ProtocolArgSize::Fixed { bytes: 2 },
Protocol::UDT => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::UTP => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::UNIX => ProtocolArgSize::Variable,
Protocol::P2P => ProtocolArgSize::Variable,
Protocol::HTTP => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::HTTPS => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::ONION => ProtocolArgSize::Fixed { bytes: 10 },
Protocol::QUIC => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::WS => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::WSS => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::Libp2pWebsocketStar => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::Libp2pWebrtcStar => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::Libp2pWebrtcDirect => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::P2pCircuit => ProtocolArgSize::Fixed { bytes: 0 },
Protocol::Memory => ProtocolArgSize::Fixed { bytes: 0 },
/// Parse a single `Protocol` value from its byte slice representation,
/// returning the protocol as well as the remaining byte slice.
pub fn from_bytes(input: &'a [u8]) -> Result<(Self, &'a [u8])> {
fn split_at(n: usize, input: &[u8]) -> Result<(&[u8], &[u8])> {
if input.len() < n {
return Err(Error::DataLessThanLen)
}
Ok(input.split_at(n))
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ProtocolArgSize {
/// The size of the argument is of fixed length. The length can be 0, in which case there is no
/// argument.
Fixed { bytes: usize },
/// The size of the argument is of variable length.
Variable,
}
impl Protocol {
/// Convert an array slice to the string representation.
///
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use multiaddr::AddrComponent;
/// use multiaddr::Protocol;
///
/// let proto = Protocol::IP4;
/// assert_eq!(proto.parse_data("127.0.0.1").unwrap(),
/// AddrComponent::IP4(Ipv4Addr::new(127, 0, 0, 1)));
/// ```
///
pub fn parse_data<'a>(&self, a: &'a str) -> Result<AddrComponent<'a>> {
match *self {
Protocol::IP4 => {
let addr = Ipv4Addr::from_str(a)?;
Ok(AddrComponent::IP4(addr))
}
Protocol::IP6 => {
let addr = Ipv6Addr::from_str(a)?;
Ok(AddrComponent::IP6(addr))
}
Protocol::DNS4 => Ok(AddrComponent::DNS4(Cow::Borrowed(a))),
Protocol::DNS6 => Ok(AddrComponent::DNS6(Cow::Borrowed(a))),
Protocol::TCP => {
let parsed: u16 = a.parse()?;
Ok(AddrComponent::TCP(parsed))
}
Protocol::UDP => {
let parsed: u16 = a.parse()?;
Ok(AddrComponent::UDP(parsed))
}
Protocol::DCCP => {
let parsed: u16 = a.parse()?;
Ok(AddrComponent::DCCP(parsed))
}
Protocol::SCTP => {
let parsed: u16 = a.parse()?;
Ok(AddrComponent::SCTP(parsed))
}
Protocol::P2P => {
let decoded = bs58::decode(a).into_vec()?;
Ok(AddrComponent::P2P(Multihash::from_bytes(decoded)?))
}
Protocol::ONION => unimplemented!(), // TODO:
Protocol::QUIC => Ok(AddrComponent::QUIC),
Protocol::UTP => Ok(AddrComponent::UTP),
Protocol::UNIX => Ok(AddrComponent::UNIX(Cow::Borrowed(a))),
Protocol::UDT => Ok(AddrComponent::UDT),
Protocol::HTTP => Ok(AddrComponent::HTTP),
Protocol::HTTPS => Ok(AddrComponent::HTTPS),
Protocol::WS => Ok(AddrComponent::WS),
Protocol::WSS => Ok(AddrComponent::WSS),
Protocol::Libp2pWebsocketStar => Ok(AddrComponent::Libp2pWebsocketStar),
Protocol::Libp2pWebrtcStar => Ok(AddrComponent::Libp2pWebrtcStar),
Protocol::Libp2pWebrtcDirect => Ok(AddrComponent::Libp2pWebrtcDirect),
Protocol::P2pCircuit => Ok(AddrComponent::P2pCircuit),
Protocol::Memory => Ok(AddrComponent::Memory),
}
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum AddrComponent<'a> {
IP4(Ipv4Addr),
TCP(u16),
UDP(u16),
DCCP(u16),
IP6(Ipv6Addr),
DNS4(Cow<'a, str>),
DNS6(Cow<'a, str>),
SCTP(u16),
UDT,
UTP,
UNIX(Cow<'a, str>),
P2P(Multihash),
HTTP,
HTTPS,
ONION(Cow<'a, [u8]>),
QUIC,
WS,
WSS,
Libp2pWebsocketStar,
Libp2pWebrtcStar,
Libp2pWebrtcDirect,
P2pCircuit,
Memory,
}
impl<'a> AddrComponent<'a> {
/// Turn this `AddrComponent` into one that owns its data, thus being valid for any lifetime.
pub fn acquire<'b>(self) -> AddrComponent<'b> {
use AddrComponent::*;
match self {
DNS4(cow) => DNS4(Cow::Owned(cow.into_owned())),
DNS6(cow) => DNS6(Cow::Owned(cow.into_owned())),
UNIX(cow) => UNIX(Cow::Owned(cow.into_owned())),
ONION(cow) => ONION(Cow::Owned(cow.into_owned())),
IP4(a) => IP4(a),
TCP(a) => TCP(a),
UDP(a) => UDP(a),
DCCP(a) => DCCP(a),
IP6(a) => IP6(a),
SCTP(a) => SCTP(a),
UDT => UDT,
UTP => UTP,
P2P(a) => P2P(a),
HTTP => HTTP,
HTTPS => HTTPS,
QUIC => QUIC,
WS => WS,
WSS => WSS,
Libp2pWebsocketStar => Libp2pWebsocketStar,
Libp2pWebrtcStar => Libp2pWebrtcStar,
Libp2pWebrtcDirect => Libp2pWebrtcDirect,
P2pCircuit => P2pCircuit,
Memory => Memory
}
}
/// Returns the `Protocol` corresponding to this `AddrComponent`.
#[inline]
pub fn protocol_id(&self) -> Protocol {
match *self {
AddrComponent::IP4(_) => Protocol::IP4,
AddrComponent::TCP(_) => Protocol::TCP,
AddrComponent::UDP(_) => Protocol::UDP,
AddrComponent::DCCP(_) => Protocol::DCCP,
AddrComponent::IP6(_) => Protocol::IP6,
AddrComponent::DNS4(_) => Protocol::DNS4,
AddrComponent::DNS6(_) => Protocol::DNS6,
AddrComponent::SCTP(_) => Protocol::SCTP,
AddrComponent::UDT => Protocol::UDT,
AddrComponent::UTP => Protocol::UTP,
AddrComponent::UNIX(_) => Protocol::UNIX,
AddrComponent::P2P(_) => Protocol::P2P,
AddrComponent::HTTP => Protocol::HTTP,
AddrComponent::HTTPS => Protocol::HTTPS,
AddrComponent::ONION(_) => Protocol::ONION,
AddrComponent::QUIC => Protocol::QUIC,
AddrComponent::WS => Protocol::WS,
AddrComponent::WSS => Protocol::WSS,
AddrComponent::Libp2pWebsocketStar => Protocol::Libp2pWebsocketStar,
AddrComponent::Libp2pWebrtcStar => Protocol::Libp2pWebrtcStar,
AddrComponent::Libp2pWebrtcDirect => Protocol::Libp2pWebrtcDirect,
AddrComponent::P2pCircuit => Protocol::P2pCircuit,
AddrComponent::Memory => Protocol::Memory,
}
}
/// Builds an `AddrComponent` from an array that starts with a bytes representation. On
/// success, also returns the rest of the slice.
pub fn from_bytes(input: &[u8]) -> Result<(AddrComponent, &[u8])> {
let (proto_num, input) = decode::u64(input)?;
let protocol_id = Protocol::from(proto_num)?;
let (data_size, input) = match protocol_id.size() {
ProtocolArgSize::Fixed { bytes } => (bytes, input),
ProtocolArgSize::Variable => decode::usize(input)?
};
let (data, rest) = input.split_at(data_size);
let addr_component = match protocol_id {
Protocol::IP4 => {
AddrComponent::IP4(Ipv4Addr::new(data[0], data[1], data[2], data[3]))
},
Protocol::IP6 => {
let (id, input) = decode::u32(input)?;
match id {
DCCP => {
let (data, rest) = split_at(2, input)?;
let mut rdr = Cursor::new(data);
let mut seg = [0; 8];
let num = rdr.read_u16::<BigEndian>()?;
Ok((Protocol::Dccp(num), rest))
}
DNS4 => {
let (n, input) = decode::usize(input)?;
let (data, rest) = split_at(n, input)?;
Ok((Protocol::Dns4(Cow::Borrowed(str::from_utf8(data)?)), rest))
}
DNS6 => {
let (n, input) = decode::usize(input)?;
let (data, rest) = split_at(n, input)?;
Ok((Protocol::Dns6(Cow::Borrowed(str::from_utf8(data)?)), rest))
}
HTTP => Ok((Protocol::Http, input)),
HTTPS => Ok((Protocol::Https, input)),
IP4 => {
let (data, rest) = split_at(4, input)?;
Ok((Protocol::Ip4(Ipv4Addr::new(data[0], data[1], data[2], data[3])), rest))
}
IP6 => {
let (data, rest) = split_at(16, input)?;
let mut rdr = Cursor::new(data);
let mut seg = [0_u16; 8];
for i in 0..8 {
seg[i] = rdr.read_u16::<BigEndian>()?;
for x in seg.iter_mut() {
*x = rdr.read_u16::<BigEndian>()?;
}
let addr = Ipv6Addr::new(seg[0],
@ -395,146 +184,197 @@ impl<'a> AddrComponent<'a> {
seg[5],
seg[6],
seg[7]);
AddrComponent::IP6(addr)
}
Protocol::DNS4 => {
AddrComponent::DNS4(Cow::Borrowed(str::from_utf8(data)?))
}
Protocol::DNS6 => {
AddrComponent::DNS6(Cow::Borrowed(str::from_utf8(data)?))
}
Protocol::TCP => {
let mut rdr = Cursor::new(data);
let num = rdr.read_u16::<BigEndian>()?;
AddrComponent::TCP(num)
}
Protocol::UDP => {
let mut rdr = Cursor::new(data);
let num = rdr.read_u16::<BigEndian>()?;
AddrComponent::UDP(num)
}
Protocol::DCCP => {
let mut rdr = Cursor::new(data);
let num = rdr.read_u16::<BigEndian>()?;
AddrComponent::DCCP(num)
}
Protocol::SCTP => {
let mut rdr = Cursor::new(data);
let num = rdr.read_u16::<BigEndian>()?;
AddrComponent::SCTP(num)
}
Protocol::UNIX => {
AddrComponent::UNIX(Cow::Borrowed(str::from_utf8(data)?))
}
Protocol::P2P => {
AddrComponent::P2P(Multihash::from_bytes(data.to_owned())?)
}
Protocol::ONION => unimplemented!(), // TODO:
Protocol::QUIC => AddrComponent::QUIC,
Protocol::UTP => AddrComponent::UTP,
Protocol::UDT => AddrComponent::UDT,
Protocol::HTTP => AddrComponent::HTTP,
Protocol::HTTPS => AddrComponent::HTTPS,
Protocol::WS => AddrComponent::WS,
Protocol::WSS => AddrComponent::WSS,
Protocol::Libp2pWebsocketStar => AddrComponent::Libp2pWebsocketStar,
Protocol::Libp2pWebrtcStar => AddrComponent::Libp2pWebrtcStar,
Protocol::Libp2pWebrtcDirect => AddrComponent::Libp2pWebrtcDirect,
Protocol::P2pCircuit => AddrComponent::P2pCircuit,
Protocol::Memory => AddrComponent::Memory,
};
Ok((addr_component, rest))
Ok((Protocol::Ip6(addr), rest))
}
P2P_WEBRTC_DIRECT => Ok((Protocol::P2pWebRtcDirect, input)),
P2P_WEBRTC_STAR => Ok((Protocol::P2pWebRtcStar, input)),
P2P_WEBSOCKET_STAR => Ok((Protocol::P2pWebSocketStar, input)),
MEMORY => Ok((Protocol::Memory, input)),
ONION => unimplemented!(), // FIXME
P2P => {
let (n, input) = decode::usize(input)?;
let (data, rest) = split_at(n, input)?;
Ok((Protocol::P2p(Multihash::from_bytes(data.to_owned())?), rest))
}
P2P_CIRCUIT => Ok((Protocol::P2pCircuit, input)),
QUIC => Ok((Protocol::Quic, input)),
SCTP => {
let (data, rest) = split_at(2, input)?;
let mut rdr = Cursor::new(data);
let num = rdr.read_u16::<BigEndian>()?;
Ok((Protocol::Sctp(num), rest))
}
TCP => {
let (data, rest) = split_at(2, input)?;
let mut rdr = Cursor::new(data);
let num = rdr.read_u16::<BigEndian>()?;
Ok((Protocol::Tcp(num), rest))
}
UDP => {
let (data, rest) = split_at(2, input)?;
let mut rdr = Cursor::new(data);
let num = rdr.read_u16::<BigEndian>()?;
Ok((Protocol::Udp(num), rest))
}
UDT => Ok((Protocol::Udt, input)),
UNIX => {
let (n, input) = decode::usize(input)?;
let (data, rest) = split_at(n, input)?;
Ok((Protocol::Unix(Cow::Borrowed(str::from_utf8(data)?)), rest))
}
UTP => Ok((Protocol::Utp, input)),
WS => Ok((Protocol::Ws, input)),
WSS => Ok((Protocol::Wss, input)),
_ => Err(Error::UnknownProtocolId(id))
}
}
/// Turns this address component into bytes by writing it to a `Write`.
pub fn write_bytes<W: Write>(self, out: &mut W) -> IoResult<()> {
out.write_all(encode::u64(self.protocol_id().into(), &mut encode::u64_buffer()))?;
/// Encode this protocol by writing its binary representation into
/// the given `Write` impl.
pub fn write_bytes<W: Write>(&self, w: &mut W) -> io::Result<()> {
let mut buf = encode::u32_buffer();
match self {
AddrComponent::IP4(addr) => {
out.write_all(&addr.octets())?;
Protocol::Ip4(addr) => {
w.write_all(encode::u32(IP4, &mut buf))?;
w.write_all(&addr.octets())?
}
AddrComponent::IP6(addr) => {
Protocol::Ip6(addr) => {
w.write_all(encode::u32(IP6, &mut buf))?;
for &segment in &addr.segments() {
out.write_u16::<BigEndian>(segment)?;
w.write_u16::<BigEndian>(segment)?
}
}
AddrComponent::TCP(port) | AddrComponent::UDP(port) | AddrComponent::DCCP(port) |
AddrComponent::SCTP(port) => {
out.write_u16::<BigEndian>(port)?;
Protocol::Tcp(port) => {
w.write_all(encode::u32(TCP, &mut buf))?;
w.write_u16::<BigEndian>(*port)?
}
AddrComponent::DNS4(s) | AddrComponent::DNS6(s) | AddrComponent::UNIX(s) => {
Protocol::Udp(port) => {
w.write_all(encode::u32(UDP, &mut buf))?;
w.write_u16::<BigEndian>(*port)?
}
Protocol::Dccp(port) => {
w.write_all(encode::u32(DCCP, &mut buf))?;
w.write_u16::<BigEndian>(*port)?
}
Protocol::Sctp(port) => {
w.write_all(encode::u32(SCTP, &mut buf))?;
w.write_u16::<BigEndian>(*port)?
}
Protocol::Dns4(s) => {
w.write_all(encode::u32(DNS4, &mut buf))?;
let bytes = s.as_bytes();
out.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
out.write_all(&bytes)?;
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
w.write_all(&bytes)?
}
AddrComponent::P2P(multihash) => {
let bytes = multihash.into_bytes();
out.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
out.write_all(&bytes)?;
Protocol::Dns6(s) => {
w.write_all(encode::u32(DNS6, &mut buf))?;
let bytes = s.as_bytes();
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
w.write_all(&bytes)?
}
AddrComponent::ONION(_) => {
unimplemented!() // TODO:
},
AddrComponent::QUIC |
AddrComponent::UTP |
AddrComponent::UDT |
AddrComponent::HTTP |
AddrComponent::HTTPS |
AddrComponent::WS |
AddrComponent::WSS |
AddrComponent::Libp2pWebsocketStar |
AddrComponent::Libp2pWebrtcStar |
AddrComponent::Libp2pWebrtcDirect |
AddrComponent::P2pCircuit |
AddrComponent::Memory => {}
};
Protocol::Unix(s) => {
w.write_all(encode::u32(UNIX, &mut buf))?;
let bytes = s.as_bytes();
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
w.write_all(&bytes)?
}
Protocol::P2p(multihash) => {
w.write_all(encode::u32(P2P, &mut buf))?;
let bytes = multihash.as_bytes();
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
w.write_all(&bytes)?
}
Protocol::Onion(_) => unimplemented!(), // FIXME
Protocol::Quic => w.write_all(encode::u32(QUIC, &mut buf))?,
Protocol::Utp => w.write_all(encode::u32(UTP, &mut buf))?,
Protocol::Udt => w.write_all(encode::u32(UDT, &mut buf))?,
Protocol::Http => w.write_all(encode::u32(HTTP, &mut buf))?,
Protocol::Https => w.write_all(encode::u32(HTTPS, &mut buf))?,
Protocol::Ws => w.write_all(encode::u32(WS, &mut buf))?,
Protocol::Wss => w.write_all(encode::u32(WSS, &mut buf))?,
Protocol::P2pWebSocketStar => w.write_all(encode::u32(P2P_WEBSOCKET_STAR, &mut buf))?,
Protocol::P2pWebRtcStar => w.write_all(encode::u32(P2P_WEBRTC_STAR, &mut buf))?,
Protocol::P2pWebRtcDirect => w.write_all(encode::u32(P2P_WEBRTC_DIRECT, &mut buf))?,
Protocol::P2pCircuit => w.write_all(encode::u32(P2P_CIRCUIT, &mut buf))?,
Protocol::Memory => w.write_all(encode::u32(MEMORY, &mut buf))?
}
Ok(())
}
}
impl<'a> fmt::Display for AddrComponent<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// Turn this `Protocol` into one that owns its data, thus being valid for any lifetime.
pub fn acquire<'b>(self) -> Protocol<'b> {
use Protocol::*;
match self {
AddrComponent::IP4(addr) => write!(f, "/ip4/{}", addr),
AddrComponent::TCP(port) => write!(f, "/tcp/{}", port),
AddrComponent::UDP(port) => write!(f, "/udp/{}", port),
AddrComponent::DCCP(port) => write!(f, "/dccp/{}", port),
AddrComponent::IP6(addr) => write!(f, "/ip6/{}", addr),
AddrComponent::DNS4(s) => write!(f, "/dns4/{}", s),
AddrComponent::DNS6(s) => write!(f, "/dns6/{}", s),
AddrComponent::SCTP(port) => write!(f, "/sctp/{}", port),
AddrComponent::UDT => f.write_str("/udt"),
AddrComponent::UTP => f.write_str("/utp"),
AddrComponent::UNIX(s) => write!(f, "/unix/{}", s),
AddrComponent::P2P(c) => write!(f, "/p2p/{}", bs58::encode(c.as_bytes()).into_string()),
AddrComponent::HTTP => f.write_str("/http"),
AddrComponent::HTTPS => f.write_str("/https"),
AddrComponent::ONION(_) => unimplemented!(),//write!("/onion"), // TODO:
AddrComponent::QUIC => f.write_str("/quic"),
AddrComponent::WS => f.write_str("/ws"),
AddrComponent::WSS => f.write_str("/wss"),
AddrComponent::Libp2pWebsocketStar => f.write_str("/p2p-websocket-star"),
AddrComponent::Libp2pWebrtcStar => f.write_str("/p2p-webrtc-star"),
AddrComponent::Libp2pWebrtcDirect => f.write_str("/p2p-webrtc-direct"),
AddrComponent::P2pCircuit => f.write_str("/p2p-circuit"),
AddrComponent::Memory => f.write_str("/memory"),
Dccp(a) => Dccp(a),
Dns4(cow) => Dns4(Cow::Owned(cow.into_owned())),
Dns6(cow) => Dns6(Cow::Owned(cow.into_owned())),
Http => Http,
Https => Https,
Ip4(a) => Ip4(a),
Ip6(a) => Ip6(a),
P2pWebRtcDirect => P2pWebRtcDirect,
P2pWebRtcStar => P2pWebRtcStar,
P2pWebSocketStar => P2pWebSocketStar,
Memory => Memory,
Onion(cow) => Onion(Cow::Owned(cow.into_owned())),
P2p(a) => P2p(a),
P2pCircuit => P2pCircuit,
Quic => Quic,
Sctp(a) => Sctp(a),
Tcp(a) => Tcp(a),
Udp(a) => Udp(a),
Udt => Udt,
Unix(cow) => Unix(Cow::Owned(cow.into_owned())),
Utp => Utp,
Ws => Ws,
Wss => Wss
}
}
}
impl<'a> From<Ipv4Addr> for AddrComponent<'a> {
#[inline]
fn from(addr: Ipv4Addr) -> Self {
AddrComponent::IP4(addr)
impl<'a> fmt::Display for Protocol<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Protocol::*;
match self {
Dccp(port) => write!(f, "/dccp/{}", port),
Dns4(s) => write!(f, "/dns4/{}", s),
Dns6(s) => write!(f, "/dns6/{}", s),
Http => f.write_str("/http"),
Https => f.write_str("/https"),
Ip4(addr) => write!(f, "/ip4/{}", addr),
Ip6(addr) => write!(f, "/ip6/{}", addr),
P2pWebRtcDirect => f.write_str("/p2p-webrtc-direct"),
P2pWebRtcStar => f.write_str("/p2p-webrtc-star"),
P2pWebSocketStar => f.write_str("/p2p-websocket-star"),
Memory => f.write_str("/memory"),
Onion(_) => unimplemented!(), // FIXME!
P2p(c) => write!(f, "/p2p/{}", bs58::encode(c.as_bytes()).into_string()),
P2pCircuit => f.write_str("/p2p-circuit"),
Quic => f.write_str("/quic"),
Sctp(port) => write!(f, "/sctp/{}", port),
Tcp(port) => write!(f, "/tcp/{}", port),
Udp(port) => write!(f, "/udp/{}", port),
Udt => f.write_str("/udt"),
Unix(s) => write!(f, "/unix/{}", s),
Utp => f.write_str("/utp"),
Ws => f.write_str("/ws"),
Wss => f.write_str("/wss"),
}
}
}
impl<'a> From<Ipv6Addr> for AddrComponent<'a> {
impl<'a> From<Ipv4Addr> for Protocol<'a> {
#[inline]
fn from(addr: Ipv6Addr) -> Self {
AddrComponent::IP6(addr)
fn from(addr: Ipv4Addr) -> Self {
Protocol::Ip4(addr)
}
}
impl<'a> From<Ipv6Addr> for Protocol<'a> {
#[inline]
fn from(addr: Ipv6Addr) -> Self {
Protocol::Ip6(addr)
}
}