refactor: simplify conversions to cid and unify error type
This commit is contained in:
parent
301011db80
commit
74ac58072b
@ -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),
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user