refactor: simplify conversions to cid and unify error type

This commit is contained in:
Joonas Koivunen 2020-06-10 16:37:35 +03:00
parent 301011db80
commit 74ac58072b
4 changed files with 89 additions and 77 deletions

View File

@ -1,5 +1,5 @@
use crate::file::UnwrapBorrowedExt;
use crate::pb::{FlatUnixFs, PBLink, PBNode, UnixFsReadFailed, UnixFsType};
use crate::InvalidCidInLink;
use cid::Cid;
use std::borrow::Cow;
use std::collections::VecDeque;
@ -74,22 +74,18 @@ pub fn resolve<'needle>(
}
};
let mut matching = links.into_iter().enumerate().filter_map(|(i, link)| {
match link.Name.as_deref().unwrap_or_default() {
x if x == needle => Some((i, Cow::Borrowed(link.Hash.unwrap_borrowed_or_empty()))),
let mut matching = links.into_iter().enumerate()
.filter_map(|(i, link)| match link.Name.as_deref().unwrap_or_default() {
x if x == needle => Some((i, link)),
_ => None,
}
});
});
let first = matching.next();
if let Some((i, first)) = first {
let first = try_convert_cid(i, first.as_ref())?;
let first = try_convert_cid(i, first)?;
match matching.next() {
Some((j, Cow::Borrowed(second))) => {
Err(MultipleMatchingLinks::from(((i, first), (j, second))).into())
}
Some((_, Cow::Owned(_))) => unreachable!("never taken ownership of"),
Some((j, second)) => Err(MultipleMatchingLinks::from(((i, first), (j, second))).into()),
None => Ok(MaybeResolved::Found(first)),
}
} else {
@ -97,13 +93,9 @@ pub fn resolve<'needle>(
}
}
fn try_convert_cid(nth: usize, hash: &[u8]) -> Result<Cid, InvalidCidInLink> {
Cid::try_from(hash).map_err(|e| InvalidCidInLink {
nth,
raw: hash.to_vec(),
source: e,
hidden: (),
})
fn try_convert_cid(nth: usize, link: PBLink<'_>) -> Result<Cid, InvalidCidInLink> {
let hash = link.Hash.as_deref().unwrap_or_default();
Cid::try_from(hash).map_err(|e| InvalidCidInLink::from((nth, link, e)))
}
pub enum MaybeResolved<'needle> {
@ -238,24 +230,21 @@ impl<'needle> ShardedLookup<'needle> {
pub(crate) fn partition<'a>(
iter: impl Iterator<Item = PBLink<'a>>,
needle: &str,
work: &mut VecDeque<Cid>,
) -> Result<Option<Cid>, PartitioningError> {
work: &mut VecDeque<Cid>) -> Result<Option<Cid>, PartitioningError> {
let mut found = None;
for (i, link) in iter.enumerate() {
let name = link.Name.as_deref().unwrap_or_default();
if name.len() > 2 && &name[2..] == needle {
let hash = link.Hash.as_deref().unwrap_or_default();
if let Some(first) = found.take() {
return Err(MultipleMatchingLinks::from((first, (i, hash))).into());
return Err(MultipleMatchingLinks::from((first, (i, link))).into());
} else {
found = Some((i, try_convert_cid(i, hash)?));
found = Some((i, try_convert_cid(i, link)?));
}
} else if name.len() == 2 {
// the magic number of two comes from the fanout (256) probably
let cid = try_convert_cid(i, link.Hash.unwrap_borrowed_or_empty())?;
let cid = try_convert_cid(i, link)?;
work.push_back(cid);
} else {
// no match, not interesting for us
@ -381,16 +370,6 @@ impl fmt::Display for ShardError {
impl std::error::Error for ShardError {}
/// A link could not be transformed into a Cid.
#[derive(Debug)]
pub struct InvalidCidInLink {
pub nth: usize,
pub raw: Vec<u8>,
pub source: cid::Error,
/// This is to deny creating these outside of the crate
hidden: (),
}
/// Multiple matching links were found: **at least two**.
#[derive(Debug)]
pub enum MultipleMatchingLinks {
@ -406,8 +385,8 @@ pub enum MultipleMatchingLinks {
},
}
impl<'a> From<((usize, Cid), (usize, &'a [u8]))> for MultipleMatchingLinks {
fn from(((i, first), (j, second)): ((usize, Cid), (usize, &'a [u8]))) -> MultipleMatchingLinks {
impl<'a> From<((usize, Cid), (usize, PBLink<'a>))> for MultipleMatchingLinks {
fn from(((i, first), (j, second)): ((usize, Cid), (usize, PBLink<'a>))) -> MultipleMatchingLinks {
match try_convert_cid(j, second) {
Ok(second) => MultipleMatchingLinks::Two {
first: (i, first),

View File

@ -3,6 +3,7 @@
///! Most usable for walking UnixFS file trees provided by the `visit::IdleFileVisit` and
///! `visit::FileVisit` types.
use crate::pb::{UnixFs, UnixFsReadFailed, UnixFsType};
use crate::InvalidCidInLink;
use std::borrow::Cow;
use std::fmt;
@ -66,20 +67,9 @@ pub enum FileReadFailed {
// This is the raw value instead of the enum by design not to expose the quick-protobuf types
UnexpectedType(i32),
/// Parsing failed
Read(quick_protobuf::Error),
/// Outer dag-pb node was parsed successfully but there was no data bytes for inner message.
EmptyPBNode,
Read(Option<quick_protobuf::Error>),
/// Link could not be turned into Cid.
LinkInvalidCid {
/// The index of this link, from zero
nth: usize,
/// Hash which could not be turned into a Cid
hash: Vec<u8>,
/// Name of the link, most likely empty
name: Cow<'static, str>,
/// Error from the attempted conversion
cause: cid::Error,
},
InvalidCid(InvalidCidInLink),
}
impl fmt::Display for FileReadFailed {
@ -94,15 +84,9 @@ impl fmt::Display for FileReadFailed {
t,
UnixFsType::from(*t)
),
Read(e) => write!(fmt, "reading failed: {}", e),
EmptyPBNode => write!(fmt, "reading failed: missing UnixFS message"),
LinkInvalidCid {
nth, name, cause, ..
} => write!(
fmt,
"failed to convert link #{} ({:?}) to Cid: {}",
nth, name, cause
),
Read(Some(e)) => write!(fmt, "reading failed: {}", e),
Read(None) => write!(fmt, "reading failed: missing UnixFS message"),
InvalidCid(e) => write!(fmt, "{}", e),
}
}
}
@ -111,7 +95,8 @@ impl std::error::Error for FileReadFailed {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use FileReadFailed::*;
match self {
LinkInvalidCid { cause, .. } => Some(cause),
InvalidCid(e) => Some(e),
Read(Some(e)) => Some(e),
_ => None,
}
}
@ -121,9 +106,9 @@ impl From<UnixFsReadFailed> for FileReadFailed {
fn from(e: UnixFsReadFailed) -> Self {
use UnixFsReadFailed::*;
match e {
InvalidDagPb(e) => FileReadFailed::Read(e),
InvalidUnixFs(e) => FileReadFailed::Read(e),
NoData => FileReadFailed::EmptyPBNode,
InvalidDagPb(e) => FileReadFailed::Read(Some(e)),
InvalidUnixFs(e) => FileReadFailed::Read(Some(e)),
NoData => FileReadFailed::Read(None),
}
}
}

View File

@ -1,11 +1,11 @@
use cid::Cid;
use std::borrow::Cow;
use std::convert::TryFrom;
use std::ops::Range;
use crate::file::reader::{FileContent, FileReader, Traversal};
use crate::file::{FileMetadata, FileReadFailed, UnwrapBorrowedExt};
use crate::file::{FileMetadata, FileReadFailed};
use crate::pb::merkledag::PBLink;
use crate::InvalidCidInLink;
/// IdleFileVisit represents a prepared file visit over a tree. The user has to know the CID and be
/// able to get the block for the visit.
@ -162,20 +162,11 @@ fn to_pending(
link: PBLink<'_>,
range: Range<u64>,
) -> Result<(Cid, Range<u64>), FileReadFailed> {
let hash = link.Hash.unwrap_borrowed();
let hash = link.Hash.as_deref().unwrap_or_default();
match Cid::try_from(hash) {
Ok(cid) => Ok((cid, range)),
Err(e) => Err(FileReadFailed::LinkInvalidCid {
nth,
hash: hash.to_vec(),
name: match link.Name {
Some(Cow::Borrowed(x)) => Cow::Owned(String::from(x)),
Some(Cow::Owned(x)) => Cow::Owned(x),
None => Cow::Borrowed(""),
},
cause: e,
}),
Err(e) => Err(FileReadFailed::InvalidCid(InvalidCidInLink::from((nth, link, e)))),
}
}

View File

@ -1,7 +1,64 @@
#[warn(rust_2018_idioms, missing_docs)]
#![warn(rust_2018_idioms, missing_docs)]
//! ipfs-unixfs
use std::borrow::Cow;
use std::fmt;
/// UnixFS file support.
pub mod file;
/// UnixFS directory support.
pub mod dir;
mod pb;
/// A link could not be transformed into a Cid.
#[derive(Debug)]
pub struct InvalidCidInLink {
/// The index of this link, from zero
pub nth: usize,
/// Hash which could not be turned into a Cid
pub hash: Cow<'static, [u8]>,
/// Name of the link, most likely empty when this originates from a file, most likely non-empty
/// for other kinds.
pub name: Cow<'static, str>,
/// Error from the attempted conversion
pub source: cid::Error,
/// This is to deny creating these outside of the crate
hidden: (),
}
impl<'a> From<(usize, pb::PBLink<'a>, cid::Error)> for InvalidCidInLink {
fn from((nth, link, source): (usize, pb::PBLink<'a>, cid::Error)) -> Self {
let hash = match link.Hash {
Some(Cow::Borrowed(x)) if !x.is_empty() => Cow::Owned(x.to_vec()),
Some(Cow::Borrowed(_)) | None => Cow::Borrowed(&[][..]),
Some(Cow::Owned(x)) => Cow::Owned(x),
};
let name = match link.Name {
Some(Cow::Borrowed(x)) if !x.is_empty() => Cow::Owned(x.to_string()),
Some(Cow::Borrowed(_)) | None => Cow::Borrowed(""),
Some(Cow::Owned(x)) => Cow::Owned(x),
};
InvalidCidInLink {
nth,
hash,
name,
source,
hidden: (),
}
}
}
impl fmt::Display for InvalidCidInLink {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "failed to convert link #{} ({:?}) to Cid: {}", self.nth, self.name, self.source)
}
}
impl std::error::Error for InvalidCidInLink {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}