Skip to content

Commit 2bda23d

Browse files
committed
support io (read/write) without core
This: 1. Uses core2 when std isn't supported. 2. Adds an alloc feature for building with and without the alloc crate. Uses multiformats/rust-multihash#146. Unfortunately, we can't do multibase formatting yet due to multiformats/rust-multibase#33. But we can fix that later.
1 parent 728d16a commit 2bda23d

File tree

4 files changed

+83
-42
lines changed

4 files changed

+83
-42
lines changed

Cargo.toml

+9-3
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,26 @@ no-dev-version = true
1515

1616
[features]
1717
default = ["std", "multihash/default"]
18-
std = ["multibase", "multihash/std", "unsigned-varint/std"]
18+
std = ["multihash/std", "unsigned-varint/std", "alloc", "multibase/std"]
19+
alloc = ["multibase", "multihash/alloc"]
1920
arb = ["quickcheck", "rand", "multihash/arb"]
2021
scale-codec = ["parity-scale-codec", "multihash/scale-codec"]
2122
serde-codec = ["serde", "multihash/serde-codec"]
2223

2324
[dependencies]
24-
multihash = { version = "0.14.0", default-features = false }
25+
multihash = { version = "0.15.0", default-features = false }
2526
unsigned-varint = { version = "0.7.0", default-features = false }
2627

27-
multibase = { version = "0.9.1", optional = true }
28+
multibase = { version = "0.9.1", optional = true, default-features = false }
2829
parity-scale-codec = { version = "2.1.1", default-features = false, features = ["derive"], optional = true }
2930
quickcheck = { version = "0.9.2", optional = true }
3031
rand = { version = "0.7.3", optional = true }
3132
serde = { version = "1.0.116", optional = true }
3233

34+
core2 = { version = "0.3", default-features = false, features = ["alloc"] }
35+
3336
[dev-dependencies]
3437
serde_json = "1.0.59"
38+
39+
[patch.crates-io]
40+
multihash = { git = "https://github.com/yatima-inc/rust-multihash", branch = "sb/core-io" }

src/cid.rs

+63-31
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,50 @@
55
//!
66
//! As a library author that works with CIDs that should support hashes of anysize, you would
77
//! import the `Cid` type from this module.
8-
#[cfg(feature = "std")]
9-
use std::convert::TryFrom;
8+
use core::convert::TryFrom;
109

11-
#[cfg(feature = "std")]
10+
#[cfg(feature = "alloc")]
1211
use multibase::{encode as base_encode, Base};
12+
1313
use multihash::{MultihashGeneric as Multihash, Size};
14+
use unsigned_varint::encode as varint_encode;
15+
16+
#[cfg(feature = "alloc")]
17+
extern crate alloc;
18+
19+
#[cfg(feature = "alloc")]
20+
use alloc::{
21+
borrow,
22+
string::{String, ToString},
23+
vec::Vec,
24+
};
25+
26+
#[cfg(feature = "std")]
27+
pub(crate) use unsigned_varint::io::read_u64 as varint_read_u64;
28+
29+
/// Reads 64 bits from a byte array into a u64
30+
/// Adapted from unsigned-varint's generated read_u64 function at
31+
/// https://github.com/paritytech/unsigned-varint/blob/master/src/io.rs
32+
#[cfg(not(feature = "std"))]
33+
pub(crate) fn varint_read_u64<R: io::Read>(mut r: R) -> Result<u64> {
34+
use unsigned_varint::decode;
35+
let mut b = varint_encode::u64_buffer();
36+
for i in 0..b.len() {
37+
let n = r.read(&mut (b[i..i + 1]))?;
38+
if n == 0 {
39+
return Err(Error::VarIntDecodeError);
40+
} else if decode::is_last(b[i]) {
41+
return Ok(decode::u64(&b[..=i]).unwrap().0);
42+
}
43+
}
44+
Err(Error::VarIntDecodeError)
45+
}
46+
1447
#[cfg(feature = "std")]
15-
use unsigned_varint::{encode as varint_encode, io::read_u64 as varint_read_u64};
48+
use std::io;
49+
50+
#[cfg(not(feature = "std"))]
51+
use core2::io;
1652

1753
use crate::error::{Error, Result};
1854
use crate::version::Version;
@@ -93,8 +129,7 @@ impl<S: Size> Cid<S> {
93129
}
94130

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

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

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

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

137170
/// Returns the encoded bytes of the `Cid`.
138-
#[cfg(feature = "std")]
171+
#[cfg(feature = "alloc")]
139172
pub fn to_bytes(&self) -> Vec<u8> {
140-
let mut bytes = vec![];
173+
let mut bytes = Vec::new();
141174
self.write_bytes(&mut bytes).unwrap();
142175
bytes
143176
}
144177

145-
#[cfg(feature = "std")]
178+
#[cfg(feature = "alloc")]
146179
fn to_string_v0(&self) -> String {
147180
Base::Base58Btc.encode(self.hash.to_bytes())
148181
}
149182

150-
#[cfg(feature = "std")]
183+
#[cfg(feature = "alloc")]
151184
fn to_string_v1(&self) -> String {
152185
multibase::encode(Base::Base32Lower, self.to_bytes().as_slice())
153186
}
@@ -167,7 +200,7 @@ impl<S: Size> Cid<S> {
167200
/// let encoded = cid.to_string_of_base(Base::Base64).unwrap();
168201
/// assert_eq!(encoded, "mAVUSICwmtGto/8aP+ZtFPB0wQTQTQi1wZIO/oPmKXohiZueu");
169202
/// ```
170-
#[cfg(feature = "std")]
203+
#[cfg(feature = "alloc")]
171204
pub fn to_string_of_base(&self, base: Base) -> Result<String> {
172205
match self.version {
173206
Version::V0 => {
@@ -192,9 +225,9 @@ impl<S: Size> Default for Cid<S> {
192225
}
193226
}
194227

195-
#[cfg(feature = "std")]
196-
impl<S: Size> std::fmt::Display for Cid<S> {
197-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
228+
#[cfg(feature = "alloc")]
229+
impl<S: Size> core::fmt::Display for Cid<S> {
230+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
198231
let output = match self.version {
199232
Version::V0 => self.to_string_v0(),
200233
Version::V1 => self.to_string_v1(),
@@ -222,16 +255,16 @@ impl<S: Size> std::fmt::Debug for Cid<S> {
222255
}
223256
}
224257

225-
#[cfg(feature = "std")]
226-
impl<S: Size> std::str::FromStr for Cid<S> {
258+
#[cfg(feature = "alloc")]
259+
impl<S: Size> core::str::FromStr for Cid<S> {
227260
type Err = Error;
228261

229262
fn from_str(cid_str: &str) -> Result<Self> {
230263
Self::try_from(cid_str)
231264
}
232265
}
233266

234-
#[cfg(feature = "std")]
267+
#[cfg(feature = "alloc")]
235268
impl<S: Size> TryFrom<String> for Cid<S> {
236269
type Error = Error;
237270

@@ -240,7 +273,7 @@ impl<S: Size> TryFrom<String> for Cid<S> {
240273
}
241274
}
242275

243-
#[cfg(feature = "std")]
276+
#[cfg(feature = "alloc")]
244277
impl<S: Size> TryFrom<&str> for Cid<S> {
245278
type Error = Error;
246279

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

270-
#[cfg(feature = "std")]
303+
#[cfg(feature = "alloc")]
271304
impl<S: Size> TryFrom<Vec<u8>> for Cid<S> {
272305
type Error = Error;
273306

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

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

@@ -294,31 +326,31 @@ where
294326
}
295327
}
296328

297-
#[cfg(feature = "std")]
329+
#[cfg(feature = "alloc")]
298330
impl<S: Size> From<Cid<S>> for Vec<u8> {
299331
fn from(cid: Cid<S>) -> Self {
300332
cid.to_bytes()
301333
}
302334
}
303335

304-
#[cfg(feature = "std")]
336+
#[cfg(feature = "alloc")]
305337
impl<S: Size> From<Cid<S>> for String {
306338
fn from(cid: Cid<S>) -> Self {
307339
cid.to_string()
308340
}
309341
}
310342

311-
#[cfg(feature = "std")]
312-
impl<'a, S: Size> From<Cid<S>> for std::borrow::Cow<'a, Cid<S>> {
343+
#[cfg(feature = "alloc")]
344+
impl<'a, S: Size> From<Cid<S>> for borrow::Cow<'a, Cid<S>> {
313345
fn from(from: Cid<S>) -> Self {
314-
std::borrow::Cow::Owned(from)
346+
borrow::Cow::Owned(from)
315347
}
316348
}
317349

318350
#[cfg(feature = "std")]
319-
impl<'a, S: Size> From<&'a Cid<S>> for std::borrow::Cow<'a, Cid<S>> {
351+
impl<'a, S: Size> From<&'a Cid<S>> for borrow::Cow<'a, Cid<S>> {
320352
fn from(from: &'a Cid<S>) -> Self {
321-
std::borrow::Cow::Borrowed(from)
353+
borrow::Cow::Borrowed(from)
322354
}
323355
}
324356

src/error.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
use core::fmt;
22

3+
#[cfg(feature = "std")]
4+
use std::io;
5+
6+
#[cfg(not(feature = "std"))]
7+
use core2::io;
8+
39
/// Type alias to use this library's [`Error`] type in a `Result`.
410
pub type Result<T> = core::result::Result<T, Error>;
511

@@ -23,8 +29,7 @@ pub enum Error {
2329
/// Varint decode failure.
2430
VarIntDecodeError,
2531
/// Io error.
26-
#[cfg(feature = "std")]
27-
Io(std::io::Error),
32+
Io(io::Error),
2833
}
2934

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

4953
f.write_str(error)
5054
}
5155
}
5256

53-
#[cfg(feature = "std")]
57+
#[cfg(feature = "alloc")]
5458
impl From<multibase::Error> for Error {
5559
fn from(_: multibase::Error) -> Error {
5660
Error::ParsingError
@@ -80,9 +84,8 @@ impl From<unsigned_varint::io::ReadError> for Error {
8084
}
8185
}
8286

83-
#[cfg(feature = "std")]
84-
impl From<std::io::Error> for Error {
85-
fn from(err: std::io::Error) -> Self {
87+
impl From<io::Error> for Error {
88+
fn from(err: io::Error) -> Self {
8689
Self::Io(err)
8790
}
8891
}

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub use self::cid::Cid as CidGeneric;
1616
pub use self::error::{Error, Result};
1717
pub use self::version::Version;
1818

19-
#[cfg(feature = "std")]
19+
#[cfg(feature = "alloc")]
2020
pub use multibase;
2121
pub use multihash;
2222

0 commit comments

Comments
 (0)