Skip to content

Commit 2a96940

Browse files
Make Error opaque
1 parent 2bc4101 commit 2a96940

File tree

4 files changed

+93
-34
lines changed

4 files changed

+93
-34
lines changed

derive/src/multihash.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ pub fn multihash(s: Structure) -> TokenStream {
252252
fn try_from(code: u64) -> Result<Self, Self::Error> {
253253
match code {
254254
#(#code_from_u64,)*
255-
_ => Err(#mh_crate::Error::UnsupportedCode(code))
255+
_ => Err(#mh_crate::Error::unsupported_code(code))
256256
}
257257
}
258258
}

src/error.rs

+71-21
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,56 @@
11
#[cfg(not(feature = "std"))]
2-
use core2::{error::Error as StdError, io::Error as IoError};
2+
use core2::{error::Error as StdError, io};
33
#[cfg(feature = "std")]
4-
use std::{error::Error as StdError, io::Error as IoError};
4+
use std::{error::Error as StdError, io};
55

66
use unsigned_varint::decode::Error as DecodeError;
77

8-
/// Multihash error.
8+
/// Opaque error struct for operations involving a [`Multihash`](crate::Multihash).
99
#[derive(Debug)]
10-
pub enum Error {
10+
pub struct Error {
11+
kind: Kind,
12+
}
13+
14+
impl Error {
15+
/// The specified code is not supported by code table.
16+
/// FIXME: This should not be in our public API because it is only needed by the custom derive which we have no knowledge of in this crate.
17+
pub fn unsupported_code(code: u64) -> Self {
18+
Self {
19+
kind: Kind::UnsupportedCode(code),
20+
}
21+
}
22+
23+
pub(crate) const fn invalid_size(size: u64) -> Self {
24+
Self {
25+
kind: Kind::InvalidSize(size),
26+
}
27+
}
28+
29+
#[cfg(not(feature = "std"))]
30+
pub(crate) const fn insufficient_varint_bytes() -> Self {
31+
Self {
32+
kind: Kind::Varint(unsigned_varint::decode::Error::Insufficient),
33+
}
34+
}
35+
36+
#[cfg(not(feature = "std"))]
37+
pub(crate) const fn varint_overflow() -> Self {
38+
Self {
39+
kind: Kind::Varint(unsigned_varint::decode::Error::Overflow),
40+
}
41+
}
42+
}
43+
44+
impl core::fmt::Display for Error {
45+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
46+
self.kind.fmt(f)
47+
}
48+
}
49+
50+
#[derive(Debug)]
51+
enum Kind {
1152
/// Io error.
12-
Io(IoError),
53+
Io(io::Error),
1354
/// Unsupported multihash code.
1455
UnsupportedCode(u64),
1556
/// Invalid multihash size.
@@ -18,7 +59,24 @@ pub enum Error {
1859
Varint(DecodeError),
1960
}
2061

21-
impl core::fmt::Display for Error {
62+
#[cfg(feature = "std")]
63+
pub(crate) fn unsigned_variant_to_multihash_error(err: unsigned_varint::io::ReadError) -> Error {
64+
match err {
65+
unsigned_varint::io::ReadError::Io(err) => io_to_multihash_error(err),
66+
unsigned_varint::io::ReadError::Decode(err) => Error {
67+
kind: Kind::Varint(err),
68+
},
69+
_ => unreachable!(),
70+
}
71+
}
72+
73+
pub(crate) fn io_to_multihash_error(err: io::Error) -> Error {
74+
Error {
75+
kind: Kind::Io(err),
76+
}
77+
}
78+
79+
impl core::fmt::Display for Kind {
2280
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2381
match self {
2482
Self::Io(err) => write!(f, "{err}"),
@@ -29,21 +87,13 @@ impl core::fmt::Display for Error {
2987
}
3088
}
3189

32-
impl StdError for Error {}
33-
34-
impl From<IoError> for Error {
35-
fn from(err: IoError) -> Self {
36-
Self::Io(err)
37-
}
38-
}
39-
40-
#[cfg(feature = "std")]
41-
impl From<unsigned_varint::io::ReadError> for Error {
42-
fn from(err: unsigned_varint::io::ReadError) -> Self {
43-
match err {
44-
unsigned_varint::io::ReadError::Io(err) => Self::Io(err),
45-
unsigned_varint::io::ReadError::Decode(err) => Self::Varint(err),
46-
_ => unreachable!(),
90+
impl StdError for Error {
91+
fn source(&self) -> Option<&(dyn StdError + 'static)> {
92+
match &self.kind {
93+
Kind::Io(inner) => Some(inner),
94+
Kind::UnsupportedCode(_) => None,
95+
Kind::InvalidSize(_) => None,
96+
Kind::Varint(_) => None, // FIXME: Does not implement `core2::Error`.
4797
}
4898
}
4999
}

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
#[cfg(feature = "alloc")]
5656
extern crate alloc;
57+
extern crate core;
5758

5859
#[cfg(any(test, feature = "arb"))]
5960
mod arb;

src/multihash.rs

+20-12
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl<const S: usize> Multihash<S> {
107107
/// Wraps the digest in a multihash.
108108
pub const fn wrap(code: u64, input_digest: &[u8]) -> Result<Self, Error> {
109109
if input_digest.len() > S {
110-
return Err(Error::InvalidSize(input_digest.len() as _));
110+
return Err(Error::invalid_size(input_digest.len() as _));
111111
}
112112
let size = input_digest.len();
113113
let mut digest = [0; S];
@@ -158,7 +158,7 @@ impl<const S: usize> Multihash<S> {
158158
let result = Self::read(&mut bytes)?;
159159
// There were more bytes supplied than read
160160
if !bytes.is_empty() {
161-
return Err(Error::InvalidSize(bytes.len().try_into().expect(
161+
return Err(Error::invalid_size(bytes.len().try_into().expect(
162162
"Currently the maximum size is 255, therefore always fits into usize",
163163
)));
164164
}
@@ -221,7 +221,7 @@ impl<const S: usize> Multihash<S> {
221221
pub fn resize<const R: usize>(&self) -> Result<Multihash<R>, Error> {
222222
let size = self.size as usize;
223223
if size > R {
224-
return Err(Error::InvalidSize(self.size as u64));
224+
return Err(Error::invalid_size(self.size as u64));
225225
}
226226
let mut mh = Multihash {
227227
code: self.code,
@@ -328,9 +328,12 @@ where
328328

329329
let written = code.len() + size.len() + digest.len();
330330

331-
w.write_all(code)?;
332-
w.write_all(size)?;
333-
w.write_all(digest)?;
331+
w.write_all(code)
332+
.map_err(crate::error::io_to_multihash_error)?;
333+
w.write_all(size)
334+
.map_err(crate::error::io_to_multihash_error)?;
335+
w.write_all(digest)
336+
.map_err(crate::error::io_to_multihash_error)?;
334337

335338
Ok(written)
336339
}
@@ -349,16 +352,19 @@ where
349352
let size = read_u64(&mut r)?;
350353

351354
if size > S as u64 || size > u8::MAX as u64 {
352-
return Err(Error::InvalidSize(size));
355+
return Err(Error::invalid_size(size));
353356
}
354357

355358
let mut digest = [0; S];
356-
r.read_exact(&mut digest[..size as usize])?;
359+
r.read_exact(&mut digest[..size as usize])
360+
.map_err(crate::error::io_to_multihash_error)?;
357361
Ok((code, size as u8, digest))
358362
}
359363

360364
#[cfg(feature = "std")]
361-
pub(crate) use unsigned_varint::io::read_u64;
365+
pub(crate) fn read_u64<R: io::Read>(r: R) -> Result<u64, Error> {
366+
unsigned_varint::io::read_u64(r).map_err(crate::error::unsigned_variant_to_multihash_error)
367+
}
362368

363369
/// Reads 64 bits from a byte array into a u64
364370
/// Adapted from unsigned-varint's generated read_u64 function at
@@ -368,14 +374,16 @@ pub(crate) fn read_u64<R: io::Read>(mut r: R) -> Result<u64, Error> {
368374
use unsigned_varint::decode;
369375
let mut b = varint_encode::u64_buffer();
370376
for i in 0..b.len() {
371-
let n = r.read(&mut (b[i..i + 1]))?;
377+
let n = r
378+
.read(&mut (b[i..i + 1]))
379+
.map_err(crate::error::io_to_multihash_error)?;
372380
if n == 0 {
373-
return Err(Error::Varint(decode::Error::Insufficient));
381+
return Err(Error::insufficient_varint_bytes());
374382
} else if decode::is_last(b[i]) {
375383
return Ok(decode::u64(&b[..=i]).unwrap().0);
376384
}
377385
}
378-
Err(Error::Varint(decode::Error::Overflow))
386+
Err(Error::varint_overflow())
379387
}
380388

381389
#[cfg(test)]

0 commit comments

Comments
 (0)