Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat!: make Error opaque #81

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

- Add `WebTransport` instance for `Multiaddr`. See [PR 70].
- Disable all features of `multihash`. See [PR 77].
- Make `Error` an opaque struct. See [PR 81].

[PR 70]: https://github.com/multiformats/rust-multiaddr/pull/70
[PR 77]: https://github.com/multiformats/rust-multiaddr/pull/77
[PR 81]: https://github.com/multiformats/rust-multiaddr/pull/81

# 0.17.0

Expand Down
110 changes: 89 additions & 21 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,60 @@
use std::{error, fmt, io, net, num, str, string};
use unsigned_varint::decode;

#[deprecated(note = "Use `Result<T, multiaddr::Error>` instead.")]
pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
kind: Kind,
}

impl Error {
pub fn is_unknown_protocol(&self) -> bool {
matches!(self.kind, Kind::UnknownProtocolString(_))
}

pub(crate) fn data_less_than_len() -> Self {
Self {
kind: Kind::DataLessThanLen,
}
}

pub(crate) fn invalid_multiaddr() -> Self {
Self {
kind: Kind::InvalidMultiaddr,
}
}

pub(crate) fn invalid_protocol_string() -> Self {
Self {
kind: Kind::InvalidProtocolString,
}
}

pub(crate) fn unknown_protocol_id(id: u32) -> Self {
Self {
kind: Kind::UnknownProtocolId(id),
}
}

pub(crate) fn unknown_protocol_string(id: String) -> Self {
Self {
kind: Kind::UnknownProtocolString(id),
}
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.kind.fmt(f)
}
}

/// Error types
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
enum Kind {
DataLessThanLen,
InvalidMultiaddr,
InvalidProtocolString,
Expand All @@ -16,16 +64,16 @@ pub enum Error {
UnknownProtocolString(String),
}

impl fmt::Display for Error {
impl fmt::Display for Kind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::DataLessThanLen => f.write_str("we have less data than indicated by length"),
Error::InvalidMultiaddr => f.write_str("invalid multiaddr"),
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::UnknownProtocolId(id) => write!(f, "unknown protocol id: {id}"),
Error::UnknownProtocolString(string) => {
Kind::DataLessThanLen => f.write_str("we have less data than indicated by length"),
Kind::InvalidMultiaddr => f.write_str("invalid multiaddr"),
Kind::InvalidProtocolString => f.write_str("invalid protocol string"),
Kind::InvalidUvar(e) => write!(f, "failed to decode unsigned varint: {e}"),
Kind::ParsingError(e) => write!(f, "failed to parse: {e}"),
Kind::UnknownProtocolId(id) => write!(f, "unknown protocol id: {id}"),
Kind::UnknownProtocolString(string) => {
write!(f, "unknown protocol string: {string}")
}
}
Expand All @@ -35,58 +83,78 @@ impl fmt::Display for Error {
impl error::Error for Error {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
if let Error::ParsingError(e) = self {
Some(&**e)
} else {
None
match &self.kind {
Kind::DataLessThanLen => None,
Kind::InvalidMultiaddr => None,
Kind::InvalidProtocolString => None,
Kind::InvalidUvar(inner) => Some(inner),
Kind::ParsingError(inner) => Some(inner.as_ref()),
Kind::UnknownProtocolId(_) => None,
Kind::UnknownProtocolString(_) => None,
}
}
}

impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::ParsingError(err.into())
Error {
kind: Kind::ParsingError(err.into()),
}
}
}

impl From<multihash::Error> for Error {
fn from(err: multihash::Error) -> Error {
Error::ParsingError(err.into())
Error {
kind: Kind::ParsingError(err.into()),
}
}
}

impl From<multibase::Error> for Error {
fn from(err: multibase::Error) -> Error {
Error::ParsingError(err.into())
Error {
kind: Kind::ParsingError(err.into()),
}
}
}

impl From<net::AddrParseError> for Error {
fn from(err: net::AddrParseError) -> Error {
Error::ParsingError(err.into())
Error {
kind: Kind::ParsingError(err.into()),
}
}
}

impl From<num::ParseIntError> for Error {
fn from(err: num::ParseIntError) -> Error {
Error::ParsingError(err.into())
Error {
kind: Kind::ParsingError(err.into()),
}
}
}

impl From<string::FromUtf8Error> for Error {
fn from(err: string::FromUtf8Error) -> Error {
Error::ParsingError(err.into())
Error {
kind: Kind::ParsingError(err.into()),
}
}
}

impl From<str::Utf8Error> for Error {
fn from(err: str::Utf8Error) -> Error {
Error::ParsingError(err.into())
Error {
kind: Kind::ParsingError(err.into()),
}
}
}

impl From<decode::Error> for Error {
fn from(e: decode::Error) -> Error {
Error::InvalidUvar(e)
Error {
kind: Kind::InvalidUvar(e),
}
}
}
11 changes: 6 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod protocol;
#[cfg(feature = "url")]
mod from_url;

#[allow(deprecated)]
pub use self::errors::{Error, Result};
pub use self::onion_addr::Onion3Addr;
pub use self::protocol::Protocol;
Expand Down Expand Up @@ -260,13 +261,13 @@ impl<'a> FromIterator<Protocol<'a>> for Multiaddr {
impl FromStr for Multiaddr {
type Err = Error;

fn from_str(input: &str) -> Result<Self> {
fn from_str(input: &str) -> std::result::Result<Self, Error> {
let mut writer = Vec::new();
let mut parts = input.split('/').peekable();

if Some("") != parts.next() {
// A multiaddr must start with `/`
return Err(Error::InvalidMultiaddr);
return Err(Error::invalid_multiaddr());
}

while parts.peek().is_some() {
Expand Down Expand Up @@ -345,7 +346,7 @@ impl From<Ipv6Addr> for Multiaddr {
impl TryFrom<Vec<u8>> for Multiaddr {
type Error = Error;

fn try_from(v: Vec<u8>) -> Result<Self> {
fn try_from(v: Vec<u8>) -> std::result::Result<Self, Error> {
// Check if the argument is a valid `Multiaddr` by reading its protocols.
let mut slice = &v[..];
while !slice.is_empty() {
Expand All @@ -359,15 +360,15 @@ impl TryFrom<Vec<u8>> for Multiaddr {
impl TryFrom<String> for Multiaddr {
type Error = Error;

fn try_from(s: String) -> Result<Multiaddr> {
fn try_from(s: String) -> std::result::Result<Multiaddr, Error> {
s.parse()
}
}

impl<'a> TryFrom<&'a str> for Multiaddr {
type Error = Error;

fn try_from(s: &'a str) -> Result<Multiaddr> {
fn try_from(s: &'a str) -> std::result::Result<Multiaddr, Error> {
s.parse()
}
}
Expand Down
Loading