Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ia0 committed Nov 1, 2020
1 parent 76e21dd commit 72bc81b
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 630 deletions.
160 changes: 10 additions & 150 deletions README.md
Expand Up @@ -8,159 +8,18 @@
[![Coverage Status][coveralls_badge]][coveralls]
[![Dependency Status][dependency_badge]][dependency]

This repository provides a Rust [library] and a [binary] providing efficient
common and custom data-encodings.

## Common use-cases

The [library] provides the following common encodings:

- `HEXLOWER`: lowercase hexadecimal
- `HEXLOWER_PERMISSIVE`: lowercase hexadecimal with case-insensitive decoding
- `HEXUPPER`: uppercase hexadecimal
- `HEXUPPER_PERMISSIVE`: uppercase hexadecimal with case-insensitive decoding
- `BASE32`: RFC4648 base32
- `BASE32_NOPAD`: RFC4648 base32 without padding
- `BASE32_DNSSEC`: RFC5155 base32
- `BASE32_DNSCURVE`: DNSCurve base32
- `BASE32HEX`: RFC4648 base32hex
- `BASE32HEX_NOPAD`: RFC4648 base32hex without padding
- `BASE64`: RFC4648 base64
- `BASE64_NOPAD`: RFC4648 base64 without padding
- `BASE64_MIME`: RFC2045-like base64
- `BASE64URL`: RFC4648 base64url
- `BASE64URL_NOPAD`: RFC4648 base64url without padding

Typical usage looks like:

```rust
// allocating functions
BASE64.encode(&input_to_encode)
HEXLOWER.decode(&input_to_decode)
// in-place functions
BASE32.encode_mut(&input_to_encode, &mut encoded_output)
BASE64_URL.decode_mut(&input_to_decode, &mut decoded_output)
```

See the [documentation] or the [changelog] for more details.

## Custom use-cases

The [library] also provides the possibility to define custom little-endian ASCII
base-conversion encodings for bases of size 2, 4, 8, 16, 32, and 64 (for which
all above use-cases are particular instances). It supports:

- padded and unpadded encodings
- canonical encodings (e.g. trailing bits are checked)
- in-place encoding and decoding functions
- partial decoding functions (e.g. for error recovery)
- character translation (e.g. for case-insensitivity)
- most and least significant bit-order
- ignoring characters when decoding (e.g. for skipping newlines)
- wrapping the output when encoding

The typical definition of a custom encoding looks like:

```rust
lazy_static! {
static ref HEX: Encoding = {
let mut spec = Specification::new();
spec.symbols.push_str("0123456789abcdef");
spec.translate.from.push_str("ABCDEF");
spec.translate.to.push_str("abcdef");
spec.encoding().unwrap()
};
static ref BASE64: Encoding = {
let mut spec = Specification::new();
spec.symbols.push_str(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
spec.padding = Some('=');
spec.encoding().unwrap()
};
}
```

You may also use the [macro] library to define a compile-time custom encoding:

```rust
const HEX: Encoding = new_encoding!{
symbols: "0123456789abcdef",
translate_from: "ABCDEF",
translate_to: "abcdef",
};
const BASE64: Encoding = new_encoding!{
symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
padding: '=',
};
```

See the [documentation] or the [changelog] for more details.

## Performance

The performance of the encoding and decoding functions (for both common and
custom encodings) are similar to existing implementations in C, Rust, and other
high-performance languages. You may run the benchmarks with `make bench`.

## Swiss-knife binary

The [binary] is mostly a wrapper around the library. You can run `make install`
to install it from the repository. By default, it will be installed as
`~/.cargo/bin/data-encoding`. You can also run `cargo install data-encoding-bin`
to install the latest version published on `crates.io`. This second alternative
does not require to clone the repository.

Once installed, you can run `data-encoding --help` (assuming `~/.cargo/bin` is
in your `PATH` environment variable) to see the usage:

```
Usage: data-encoding --mode=<mode> --base=<base> [<options>]
Usage: data-encoding --mode=<mode> --symbols=<symbols> [<options>]
Options:
-m, --mode <mode> {encode|decode|describe}
-b, --base <base> {16|hex|32|32hex|64|64url}
-i, --input <file> read from <file> instead of standard input
-o, --output <file> write to <file> instead of standard output
--block <size> read blocks of about <size> bytes
-p, --padding <padding>
pad with <padding>
-g, --ignore <ignore>
when decoding, ignore characters in <ignore>
-w, --width <cols> when encoding, wrap every <cols> characters
-s, --separator <separator>
when encoding, wrap with <separator>
--symbols <symbols>
define a custom base using <symbols>
--translate <new><old>
when decoding, translate <new> as <old>
--ignore_trailing_bits
when decoding, ignore non-zero trailing bits
--least_significant_bit_first
use least significant bit first bit-order
Examples:
# Encode using the RFC4648 base64 encoding
data-encoding -mencode -b64 # without padding
data-encoding -mencode -b64 -p= # with padding
# Encode using the MIME base64 encoding
data-encoding -mencode -b64 -p= -w76 -s$'\r\n'
# Show base information for the permissive hexadecimal encoding
data-encoding --mode=describe --base=hex
# Decode using the DNSCurve base32 encoding
data-encoding -mdecode \
--symbols=0123456789bcdfghjklmnpqrstuvwxyz \
--translate=BCDFGHJKLMNPQRSTUVWXYZbcdfghjklmnpqrstuvwxyz \
--least_significant_bit_first
```
This repository provides the following Rust crates for data-encoding:
- The `data-encoding` library provides common and custom encodings, like
hexadecimal, base32, and base64. See the [documentation] for more information.
- The `data-encoding-macro` library provides compile-time facilities. See the
[documentation][macro] for more information.
- The `data-encoding-bin` binary is a command-line tool to define and use
encodings. See the [binary] for more information.
- The [website] provides a playground to define and use encodings.

[appveyor]: https://ci.appveyor.com/project/ia0/data-encoding
[appveyor_badge]:https://ci.appveyor.com/api/projects/status/wm4ga69xnlriukhl/branch/master?svg=true
[binary]: https://crates.io/crates/data-encoding-bin
[changelog]: https://github.com/ia0/data-encoding/blob/master/lib/CHANGELOG.md
[coveralls]: https://coveralls.io/github/ia0/data-encoding?branch=master
[coveralls_badge]: https://coveralls.io/repos/github/ia0/data-encoding/badge.svg?branch=master
[dependency]: https://deps.rs/crate/data-encoding/2.3.0
Expand All @@ -170,7 +29,8 @@ Examples:
[library]: https://crates.io/crates/data-encoding
[license]: https://github.com/ia0/data-encoding/blob/master/LICENSE
[license_badge]: https://img.shields.io/crates/l/data-encoding.svg
[macro]: https://crates.io/crates/data-encoding-macro
[macro]: https://docs.rs/data-encoding-macro
[travis]: https://travis-ci.org/ia0/data-encoding
[travis_badge]: https://travis-ci.org/ia0/data-encoding.svg?branch=master
[version_badge]: https://img.shields.io/crates/v/data-encoding.svg
[website]: https://data-encoding.rs
4 changes: 0 additions & 4 deletions bin/Cargo.toml
Expand Up @@ -18,7 +18,3 @@ path = "src/main.rs"
[dependencies]
data-encoding = { version = "2", path = "../lib" }
getopts = "0.2"

[badges]
appveyor = { repository = "ia0/data-encoding" }
travis-ci = { repository = "ia0/data-encoding" }
68 changes: 12 additions & 56 deletions bin/README.md
@@ -1,65 +1,21 @@
This binary is a wrapper around the `data-encoding` [library].

## Installation

You can run `make install` to install the binary from the [github] repository.
By default, it will be installed as `~/.cargo/bin/data-encoding`. You can also
run `cargo install data-encoding-bin` to install the latest version published on
`crates.io`. This second alternative does not require to clone the repository.

## Usage

You can run `data-encoding --help` (assuming `~/.cargo/bin` is in your `PATH`
environment variable) to see the usage:
To install the binary from the [github] repository:

```
Usage: data-encoding --mode=<mode> --base=<base> [<options>]
Usage: data-encoding --mode=<mode> --symbols=<symbols> [<options>]
Options:
-m, --mode <mode> {encode|decode|describe}
-b, --base <base> {16|hex|32|32hex|64|64url}
-i, --input <file> read from <file> instead of standard input
-o, --output <file> write to <file> instead of standard output
--block <size> read blocks of about <size> bytes
-p, --padding <padding>
pad with <padding>
-g, --ignore <ignore>
when decoding, ignore characters in <ignore>
-w, --width <cols> when encoding, wrap every <cols> characters
-s, --separator <separator>
when encoding, wrap with <separator>
--symbols <symbols>
define a custom base using <symbols>
--translate <new><old>
when decoding, translate <new> as <old>
--ignore_trailing_bits
when decoding, ignore non-zero trailing bits
--least_significant_bit_first
use least significant bit first bit-order
Examples:
# Encode using the RFC4648 base64 encoding
data-encoding -mencode -b64 # without padding
data-encoding -mencode -b64 -p= # with padding
# Encode using the MIME base64 encoding
data-encoding -mencode -b64 -p= -w76 -s$'\r\n'
make install
```

# Show base information for the permissive hexadecimal encoding
data-encoding --mode=describe --base=hex
To install the latest version published on `crates.io` (does not require to clone the repository):

# Decode using the DNSCurve base32 encoding
data-encoding -mdecode \
--symbols=0123456789bcdfghjklmnpqrstuvwxyz \
--translate=BCDFGHJKLMNPQRSTUVWXYZbcdfghjklmnpqrstuvwxyz \
--least_significant_bit_first
```
cargo install data-encoding-bin
```

## Performance
By default, the binary will be installed as `~/.cargo/bin/data-encoding`.
Assuming `~/.cargo/bin` is in your `PATH` environment variable, you can see the
usage by running:

The performance of this binary is similar or faster than the GNU `base64`
program (see how to run the benchmarks on [github]).
```
data-encoding --help
```

[library]: https://crates.io/crates/data-encoding
[github]: https://github.com/ia0/data-encoding
2 changes: 2 additions & 0 deletions cmp/.gitignore
@@ -0,0 +1,2 @@
/Cargo.lock
/target/
2 changes: 0 additions & 2 deletions cmp/Cargo.toml
Expand Up @@ -11,8 +11,6 @@ publish = false
base64 = { git = "https://github.com/alicemaz/rust-base64" }
data-encoding = { path = "../lib" }
libc = "0.2"
rustc-serialize = "0.3"
lazy_static = "1"

[build-dependencies]
cc = "1"
50 changes: 8 additions & 42 deletions cmp/tests/lib.rs
@@ -1,13 +1,6 @@
extern crate base64;
extern crate cmp;
extern crate data_encoding;
#[macro_use]
extern crate lazy_static;
extern crate rustc_serialize;

use base64::DecodeError::*;
use data_encoding::DecodeKind::*;
use data_encoding::{DecodeError, Encoding, Specification, BASE64};
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};
use data_encoding::{DecodeError, BASE64};

#[test]
fn encode_exact() {
Expand All @@ -31,56 +24,29 @@ fn encode_exact() {
BASE64.encode_mut(i, &mut r);
assert_eq!(&r, o);
}
for &(ref i, ref o) in tests {
assert_eq!(&i.to_base64(STANDARD).as_bytes(), o);
}
}

#[test]
fn difference() {
let x = b"AAB=";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 2, kind: Trailing });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert!(base64::decode(x).is_err());
assert_eq!(base64::decode(x).err().unwrap(), InvalidLastSymbol(2, b'B'));
let x = b"AA\nB=";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 4, kind: Length });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert_eq!(base64::decode(x).err().unwrap(), base64::DecodeError::InvalidLength);
assert_eq!(base64::decode(x).err().unwrap(), InvalidLength);
let x = b"AAB";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 0, kind: Length });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert!(base64::decode(x).is_err());
assert_eq!(base64::decode(x).err().unwrap(), InvalidLastSymbol(2, b'B'));
let x = b"AAA";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 0, kind: Length });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert_eq!(base64::decode(x).unwrap(), vec![0, 0]);
let x = b"A\rA\nB=";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 4, kind: Length });
assert_eq!(x.from_base64().unwrap(), vec![0, 0]);
assert_eq!(base64::decode(x).err().unwrap(), base64::DecodeError::InvalidByte(1, b'\r'));
assert_eq!(base64::decode(x).err().unwrap(), InvalidByte(1, b'\r'));
let x = b"-_\r\n";
assert_eq!(BASE64.decode(x).err().unwrap(), DecodeError { position: 0, kind: Symbol });
assert_eq!(x.from_base64().unwrap(), vec![251]);
assert_eq!(base64::decode(x).err().unwrap(), base64::DecodeError::InvalidByte(0, b'-'));
assert_eq!(base64::decode(x).err().unwrap(), InvalidByte(0, b'-'));
let x = b"AA==AA==";
assert_eq!(BASE64.decode(x).unwrap(), vec![0, 0]);
assert!(x.from_base64().is_err());
assert_eq!(base64::decode(x).err().unwrap(), base64::DecodeError::InvalidByte(2, b'='));
}

lazy_static! {
static ref HEX: Encoding = {
let mut spec = Specification::new();
spec.symbols.push_str("0123456789abcdef");
spec.translate.from.push_str("ABCDEF");
spec.translate.to.push_str("abcdef");
spec.encoding().unwrap()
};
}

#[test]
fn lazy_static_hex() {
assert_eq!(HEX.encode(b"Hello"), "48656c6c6f");
assert_eq!(HEX.decode(b"48656c6c6f").unwrap(), b"Hello");
assert_eq!(*HEX, data_encoding::HEXLOWER_PERMISSIVE);
assert_eq!(base64::decode(x).err().unwrap(), InvalidByte(2, b'='));
}

0 comments on commit 72bc81b

Please sign in to comment.