Skip to content

Commit

Permalink
Merge pull request #98 from multiformats/feat/core-io
Browse files Browse the repository at this point in the history
support io (read/write) without core
  • Loading branch information
Stebalien authored Oct 29, 2021
2 parents 728d16a + 2bda23d commit 57c7d15
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 42 deletions.
12 changes: 9 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,26 @@ no-dev-version = true

[features]
default = ["std", "multihash/default"]
std = ["multibase", "multihash/std", "unsigned-varint/std"]
std = ["multihash/std", "unsigned-varint/std", "alloc", "multibase/std"]
alloc = ["multibase", "multihash/alloc"]
arb = ["quickcheck", "rand", "multihash/arb"]
scale-codec = ["parity-scale-codec", "multihash/scale-codec"]
serde-codec = ["serde", "multihash/serde-codec"]

[dependencies]
multihash = { version = "0.14.0", default-features = false }
multihash = { version = "0.15.0", default-features = false }
unsigned-varint = { version = "0.7.0", default-features = false }

multibase = { version = "0.9.1", optional = true }
multibase = { version = "0.9.1", optional = true, default-features = false }
parity-scale-codec = { version = "2.1.1", default-features = false, features = ["derive"], optional = true }
quickcheck = { version = "0.9.2", optional = true }
rand = { version = "0.7.3", optional = true }
serde = { version = "1.0.116", optional = true }

core2 = { version = "0.3", default-features = false, features = ["alloc"] }

[dev-dependencies]
serde_json = "1.0.59"

[patch.crates-io]
multihash = { git = "https://github.com/yatima-inc/rust-multihash", branch = "sb/core-io" }
94 changes: 63 additions & 31 deletions src/cid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,50 @@
//!
//! As a library author that works with CIDs that should support hashes of anysize, you would
//! import the `Cid` type from this module.
#[cfg(feature = "std")]
use std::convert::TryFrom;
use core::convert::TryFrom;

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
use multibase::{encode as base_encode, Base};

use multihash::{MultihashGeneric as Multihash, Size};
use unsigned_varint::encode as varint_encode;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "alloc")]
use alloc::{
borrow,
string::{String, ToString},
vec::Vec,
};

#[cfg(feature = "std")]
pub(crate) use unsigned_varint::io::read_u64 as varint_read_u64;

/// Reads 64 bits from a byte array into a u64
/// Adapted from unsigned-varint's generated read_u64 function at
/// https://github.com/paritytech/unsigned-varint/blob/master/src/io.rs
#[cfg(not(feature = "std"))]
pub(crate) fn varint_read_u64<R: io::Read>(mut r: R) -> Result<u64> {
use unsigned_varint::decode;
let mut b = varint_encode::u64_buffer();
for i in 0..b.len() {
let n = r.read(&mut (b[i..i + 1]))?;
if n == 0 {
return Err(Error::VarIntDecodeError);
} else if decode::is_last(b[i]) {
return Ok(decode::u64(&b[..=i]).unwrap().0);
}
}
Err(Error::VarIntDecodeError)
}

#[cfg(feature = "std")]
use unsigned_varint::{encode as varint_encode, io::read_u64 as varint_read_u64};
use std::io;

#[cfg(not(feature = "std"))]
use core2::io;

use crate::error::{Error, Result};
use crate::version::Version;
Expand Down Expand Up @@ -93,8 +129,7 @@ impl<S: Size> Cid<S> {
}

/// Reads the bytes from a byte stream.
#[cfg(feature = "std")]
pub fn read_bytes<R: std::io::Read>(mut r: R) -> Result<Self> {
pub fn read_bytes<R: io::Read>(mut r: R) -> Result<Self> {
let version = varint_read_u64(&mut r)?;
let codec = varint_read_u64(&mut r)?;
// CIDv0 has the fixed `0x12 0x20` prefix
Expand All @@ -110,8 +145,7 @@ impl<S: Size> Cid<S> {
}
}

#[cfg(feature = "std")]
fn write_bytes_v1<W: std::io::Write>(&self, mut w: W) -> Result<()> {
fn write_bytes_v1<W: io::Write>(&self, mut w: W) -> Result<()> {
let mut version_buf = varint_encode::u64_buffer();
let version = varint_encode::u64(self.version.into(), &mut version_buf);

Expand All @@ -125,8 +159,7 @@ impl<S: Size> Cid<S> {
}

/// Writes the bytes to a byte stream.
#[cfg(feature = "std")]
pub fn write_bytes<W: std::io::Write>(&self, w: W) -> Result<()> {
pub fn write_bytes<W: io::Write>(&self, w: W) -> Result<()> {
match self.version {
Version::V0 => self.hash.write(w)?,
Version::V1 => self.write_bytes_v1(w)?,
Expand All @@ -135,19 +168,19 @@ impl<S: Size> Cid<S> {
}

/// Returns the encoded bytes of the `Cid`.
#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = vec![];
let mut bytes = Vec::new();
self.write_bytes(&mut bytes).unwrap();
bytes
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
fn to_string_v0(&self) -> String {
Base::Base58Btc.encode(self.hash.to_bytes())
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
fn to_string_v1(&self) -> String {
multibase::encode(Base::Base32Lower, self.to_bytes().as_slice())
}
Expand All @@ -167,7 +200,7 @@ impl<S: Size> Cid<S> {
/// let encoded = cid.to_string_of_base(Base::Base64).unwrap();
/// assert_eq!(encoded, "mAVUSICwmtGto/8aP+ZtFPB0wQTQTQi1wZIO/oPmKXohiZueu");
/// ```
#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
pub fn to_string_of_base(&self, base: Base) -> Result<String> {
match self.version {
Version::V0 => {
Expand All @@ -192,9 +225,9 @@ impl<S: Size> Default for Cid<S> {
}
}

#[cfg(feature = "std")]
impl<S: Size> std::fmt::Display for Cid<S> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
#[cfg(feature = "alloc")]
impl<S: Size> core::fmt::Display for Cid<S> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let output = match self.version {
Version::V0 => self.to_string_v0(),
Version::V1 => self.to_string_v1(),
Expand Down Expand Up @@ -222,16 +255,16 @@ impl<S: Size> std::fmt::Debug for Cid<S> {
}
}

#[cfg(feature = "std")]
impl<S: Size> std::str::FromStr for Cid<S> {
#[cfg(feature = "alloc")]
impl<S: Size> core::str::FromStr for Cid<S> {
type Err = Error;

fn from_str(cid_str: &str) -> Result<Self> {
Self::try_from(cid_str)
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl<S: Size> TryFrom<String> for Cid<S> {
type Error = Error;

Expand All @@ -240,7 +273,7 @@ impl<S: Size> TryFrom<String> for Cid<S> {
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl<S: Size> TryFrom<&str> for Cid<S> {
type Error = Error;

Expand All @@ -267,7 +300,7 @@ impl<S: Size> TryFrom<&str> for Cid<S> {
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl<S: Size> TryFrom<Vec<u8>> for Cid<S> {
type Error = Error;

Expand All @@ -276,7 +309,6 @@ impl<S: Size> TryFrom<Vec<u8>> for Cid<S> {
}
}

#[cfg(feature = "std")]
impl<S: Size> TryFrom<&[u8]> for Cid<S> {
type Error = Error;

Expand All @@ -294,31 +326,31 @@ where
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl<S: Size> From<Cid<S>> for Vec<u8> {
fn from(cid: Cid<S>) -> Self {
cid.to_bytes()
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl<S: Size> From<Cid<S>> for String {
fn from(cid: Cid<S>) -> Self {
cid.to_string()
}
}

#[cfg(feature = "std")]
impl<'a, S: Size> From<Cid<S>> for std::borrow::Cow<'a, Cid<S>> {
#[cfg(feature = "alloc")]
impl<'a, S: Size> From<Cid<S>> for borrow::Cow<'a, Cid<S>> {
fn from(from: Cid<S>) -> Self {
std::borrow::Cow::Owned(from)
borrow::Cow::Owned(from)
}
}

#[cfg(feature = "std")]
impl<'a, S: Size> From<&'a Cid<S>> for std::borrow::Cow<'a, Cid<S>> {
impl<'a, S: Size> From<&'a Cid<S>> for borrow::Cow<'a, Cid<S>> {
fn from(from: &'a Cid<S>) -> Self {
std::borrow::Cow::Borrowed(from)
borrow::Cow::Borrowed(from)
}
}

Expand Down
17 changes: 10 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use core::fmt;

#[cfg(feature = "std")]
use std::io;

#[cfg(not(feature = "std"))]
use core2::io;

/// Type alias to use this library's [`Error`] type in a `Result`.
pub type Result<T> = core::result::Result<T, Error>;

Expand All @@ -23,8 +29,7 @@ pub enum Error {
/// Varint decode failure.
VarIntDecodeError,
/// Io error.
#[cfg(feature = "std")]
Io(std::io::Error),
Io(io::Error),
}

#[cfg(feature = "std")]
Expand All @@ -42,15 +47,14 @@ impl fmt::Display for Error {
InvalidCidV0Multihash => "CIDv0 requires a Sha-256 multihash",
InvalidCidV0Base => "CIDv0 requires a Base58 base",
VarIntDecodeError => "Failed to decode unsigned varint format",
#[cfg(feature = "std")]
Io(err) => return write!(f, "{}", err),
};

f.write_str(error)
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl From<multibase::Error> for Error {
fn from(_: multibase::Error) -> Error {
Error::ParsingError
Expand Down Expand Up @@ -80,9 +84,8 @@ impl From<unsigned_varint::io::ReadError> for Error {
}
}

#[cfg(feature = "std")]
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::Io(err)
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use self::cid::Cid as CidGeneric;
pub use self::error::{Error, Result};
pub use self::version::Version;

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
pub use multibase;
pub use multihash;

Expand Down

0 comments on commit 57c7d15

Please sign in to comment.