Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No alloc #34

Closed
wants to merge 16 commits into from
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ keywords = ["ipld", "ipfs", "multihash", "cid", "no_std"]

[features]
default = ["std"]
std = ["data-encoding/std"]
std = ["data-encoding/std", "alloc"]
alloc = []

[dependencies]
base-x = { version = "0.2.7", default-features = false }
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ multibase = "0.9"
```

For `no_std`
```
```toml
[dependencies]
multibase = { version ="0.9", default-features = false }
```

**note**: This crate relies on the [currently unstable](https://github.com/rust-lang/cargo/issues/7915) `host_dep` feature to [compile proc macros with the proper dependencies](https://docs.rs/data-encoding-macro/0.1.10/data_encoding_macro/), thus **requiring nightly rustc** to use.

Then run `cargo build`.

**note**: This crate relies on the [currently unstable](https://github.com/rust-lang/cargo/issues/7915) `host_dep` feature to [compile proc macros with the proper dependencies](https://docs.rs/data-encoding-macro/0.1.10/data_encoding_macro/), thus **requiring nightly rustc** to use.

## Usage

```rust
Expand Down
6 changes: 4 additions & 2 deletions src/base.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::{Error, Result};
use crate::impls::*;

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

macro_rules! build_base_enum {
Expand Down Expand Up @@ -30,13 +30,15 @@ macro_rules! build_base_enum {
}
}

#[cfg(feature = "alloc")]
/// Encode the given byte slice to base string.
pub fn encode<I: AsRef<[u8]>>(&self, input: I) -> String {
match self {
$( Self::$base => $base::encode(input), )*
}
}

#[cfg(feature = "alloc")]
/// Decode the base string.
pub fn decode<I: AsRef<str>>(&self, input: I) -> Result<Vec<u8>> {
match self {
Expand All @@ -60,7 +62,7 @@ build_base_enum! {
'f' => Base16Lower,
/// Base16 upper hexadecimal (alphabet: 0123456789ABCDEF).
'F' => Base16Upper,
/// Base32, rfc4648 no padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
/// Base32, rfc4648 no padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
'b' => Base32Lower,
/// Base32, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ234567).
'B' => Base32Upper,
Expand Down
5 changes: 5 additions & 0 deletions src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub const BASE8: Encoding = new_encoding! {
symbols: "01234567",
};

#[cfg(feature = "alloc")]
/// Base10 (alphabet: 0123456789)
pub const BASE10: &str = "0123456789";

Expand Down Expand Up @@ -85,15 +86,19 @@ pub const BASE32Z: Encoding = new_encoding! {
symbols: "ybndrfg8ejkmcpqxot1uwisza345h769",
};

#[cfg(feature = "alloc")]
/// Base36, [0-9a-z] no padding (alphabet: 0123456789abcdefghijklmnopqrstuvwxyz).
pub const BASE36_LOWER: &str = "0123456789abcdefghijklmnopqrstuvwxyz";

#[cfg(feature = "alloc")]
/// Base36, [0-9A-Z] no padding (alphabet: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ).
pub const BASE36_UPPER: &str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

#[cfg(feature = "alloc")]
// Base58 Flickr's alphabet for creating short urls from photo ids.
pub const BASE58_FLICKR: &str = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";

#[cfg(feature = "alloc")]
// Base58 Bitcoin's alphabet as defined in their Base58Check encoding.
pub const BASE58_BITCOIN: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

Expand Down
47 changes: 46 additions & 1 deletion src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::encoding;
use crate::error::Result;
use data_encoding::{DecodeError, DecodePartial};

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

macro_rules! derive_base_encoding {
Expand All @@ -11,6 +12,7 @@ macro_rules! derive_base_encoding {
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub(crate) struct $type;

#[cfg(feature = "alloc")]
impl BaseCodec for $type {
fn encode<I: AsRef<[u8]>>(input: I) -> String {
$encoding.encode(input.as_ref())
Expand All @@ -20,10 +22,29 @@ macro_rules! derive_base_encoding {
Ok($encoding.decode(input.as_ref().as_bytes())?)
}
}

impl BaseCodecMut for $type {
fn encode_mut<I: AsRef<[u8]>>(input: I, output: &mut [u8]){
$encoding.encode_mut(input.as_ref(), output)
}

fn encode_len(len: usize) -> usize {
$encoding.encode_len(len)
}

fn decode_mut<I: AsRef<[u8]>>(input: I, output: &mut [u8]) -> core::result::Result<usize, DecodePartial> {
$encoding.decode_mut(input.as_ref(), output)
}

fn decode_len(len: usize) -> core::result::Result<usize, DecodeError> {
$encoding.decode_len(len)
}
}
)*
};
}

#[cfg(feature = "alloc")]
macro_rules! derive_base_x {
( $(#[$doc:meta] $type:ident, $encoding:expr;)* ) => {
$(
Expand All @@ -44,6 +65,7 @@ macro_rules! derive_base_x {
};
}

#[cfg(feature = "alloc")]
pub(crate) trait BaseCodec {
/// Encode with the given byte slice.
fn encode<I: AsRef<[u8]>>(input: I) -> String;
Expand All @@ -52,10 +74,28 @@ pub(crate) trait BaseCodec {
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>>;
}

pub(crate) trait BaseCodecMut {
/// Encode with the given byte slice to a mutable slice.
fn encode_mut<I: AsRef<[u8]>>(input: I, output: &mut [u8]);

/// Returns the encoded length of an input of length `len`
fn encode_len(len: usize) -> usize;

/// Encode with the given byte slice to a mutable slice.
fn decode_mut<I: AsRef<[u8]>>(
input: I,
output: &mut [u8],
) -> core::result::Result<usize, DecodePartial>;

/// Returns the decoded length of an input of length `len`
fn decode_len(len: usize) -> core::result::Result<usize, DecodeError>;
}

/// Identity, 8-bit binary (encoder and decoder keeps data unmodified).
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub(crate) struct Identity;

#[cfg(feature = "alloc")]
impl BaseCodec for Identity {
fn encode<I: AsRef<[u8]>>(input: I) -> String {
String::from_utf8(input.as_ref().to_vec()).expect("input must be valid UTF-8 bytes")
Expand Down Expand Up @@ -103,6 +143,7 @@ derive_base_encoding! {
Base64UrlPad, encoding::BASE64URL_PAD;
}

#[cfg(feature = "alloc")]
derive_base_x! {
/// Base10 (alphabet: 0123456789).
Base10, encoding::BASE10;
Expand All @@ -112,10 +153,12 @@ derive_base_x! {
Base58Btc, encoding::BASE58_BITCOIN;
}

#[cfg(feature = "alloc")]
/// Base36, [0-9a-z] no padding (alphabet: abcdefghijklmnopqrstuvwxyz0123456789).
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub(crate) struct Base36Lower;

#[cfg(feature = "alloc")]
impl BaseCodec for Base36Lower {
fn encode<I: AsRef<[u8]>>(input: I) -> String {
base_x::encode(encoding::BASE36_LOWER, input.as_ref())
Expand All @@ -128,10 +171,12 @@ impl BaseCodec for Base36Lower {
}
}

#[cfg(feature = "alloc")]
/// Base36, [0-9A-Z] no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789).
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub(crate) struct Base36Upper;

#[cfg(feature = "alloc")]
impl BaseCodec for Base36Upper {
fn encode<I: AsRef<[u8]>>(input: I) -> String {
base_x::encode(encoding::BASE36_UPPER, input.as_ref())
Expand Down
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

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

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

mod base;
Expand All @@ -31,6 +31,7 @@ pub use self::error::{Error, Result};
/// (Base::Base58Btc, b"hello".to_vec())
/// );
/// ```
#[cfg(feature = "alloc")]
pub fn decode<T: AsRef<str>>(input: T) -> Result<(Base, Vec<u8>)> {
let input = input.as_ref();
let code = input.chars().next().ok_or(Error::InvalidBaseString)?;
Expand All @@ -48,6 +49,7 @@ pub fn decode<T: AsRef<str>>(input: T) -> Result<(Base, Vec<u8>)> {
///
/// assert_eq!(encode(Base::Base58Btc, b"hello"), "zCn8eVZg");
/// ```
#[cfg(feature = "alloc")]
pub fn encode<T: AsRef<[u8]>>(base: Base, input: T) -> String {
let input = input.as_ref();
let mut encoded = base.encode(input.as_ref());
Expand Down