Skip to content

Commit

Permalink
Move re-exports from engine to prelude
Browse files Browse the repository at this point in the history
  • Loading branch information
marshallpierce committed Dec 29, 2022
1 parent 53e1091 commit c3f6e7f
Show file tree
Hide file tree
Showing 17 changed files with 138 additions and 116 deletions.
72 changes: 42 additions & 30 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,22 @@
# 0.21.0-beta.1

## Breaking changes

- `FastPortable` was only meant to be an interim name, and shouldn't have shipped in 0.20. It is now `GeneralPurpose` to
make its intended usage more clear.
- `GeneralPurpose` and its config are now `pub use`'d in the `engine` module for convenience.
- Change a few `from()` functions to be `new()`. `from()` causes confusing compiler errors because of confusion
with `From::from`, and is a little misleading because some of those invocations are not very cheap as one would
usually expect from a `from` call.
- `encode*` and `decode*` top level functions are now methods on `Engine`.
- `DEFAULT_ENGINE` was replaced by `engine::general_purpose::STANDARD`
- Predefined engine consts `engine::general_purpose::{STANDARD, STANDARD_NO_PAD, URL_SAFE, URL_SAFE_NO_PAD}`
- These are `pub use`d into `engine` as well
- The `*_slice` decode/encode functions now return an error instead of panicking when the output slice is too small
- As part of this, there isn't now a public way to decode into a slice _exactly_ the size needed for inputs that
aren't multiples of 4 tokens. If adding up to 2 bytes to always be a multiple of 3 bytes for the decode buffer is
a problem, file an issue.
# 0.21.0

## Other changes
(not yet released)

- `decoded_len_estimate()` is provided to make it easy to size decode buffers correctly.

## Migration

### Functions

| < 0.20 function | 0.21 equivalent |
|-------------------------|-----------------------------|
| `encode()` | `engine::STANDARD.encode()` |
| `encode_config()` | `engine.encode()` |
| `encode_config_buf()` | `engine.encode_string()` |
| `encode_config_slice()` | `engine.encode_slice()` |
| `decode()` | `engine::STANDARD.decode()` |
| `decode_config()` | `engine.decode()` |
| `decode_config_buf()` | `engine.decode_vec()` |
| `decode_config_slice()` | `engine.decode_slice()` |
| < 0.20 function | 0.21 equivalent |
|-------------------------|-------------------------------------------------------------------------------------|
| `encode()` | `engine::general_purpose::STANDARD.encode()` or `prelude::BASE64_STANDARD.encode()` |
| `encode_config()` | `engine.encode()` |
| `encode_config_buf()` | `engine.encode_string()` |
| `encode_config_slice()` | `engine.encode_slice()` |
| `decode()` | `engine::general_purpose::STANDARD.decode()` or `prelude::BASE64_STANDARD.decode()` |
| `decode_config()` | `engine.decode()` |
| `decode_config_buf()` | `engine.decode_vec()` |
| `decode_config_slice()` | `engine.decode_slice()` |

The short-lived 0.20 functions were the 0.13 functions with `config` replaced with `engine`.

Expand All @@ -55,6 +37,36 @@ precisely, see the following table.
| URL_SAFE | URL_SAFE | true | Indifferent |
| URL_SAFE_NO_PAD | URL_SAFE | false | Indifferent |


# 0.21.0-beta.2

## Breaking changes

- Re-exports of preconfigured engines in `engine` are removed in favor of `base64::prelude::...` that are better suited to those who wish to `use` the entire path to a name.

# 0.21.0-beta.1

## Breaking changes

- `FastPortable` was only meant to be an interim name, and shouldn't have shipped in 0.20. It is now `GeneralPurpose` to
make its intended usage more clear.
- `GeneralPurpose` and its config are now `pub use`'d in the `engine` module for convenience.
- Change a few `from()` functions to be `new()`. `from()` causes confusing compiler errors because of confusion
with `From::from`, and is a little misleading because some of those invocations are not very cheap as one would
usually expect from a `from` call.
- `encode*` and `decode*` top level functions are now methods on `Engine`.
- `DEFAULT_ENGINE` was replaced by `engine::general_purpose::STANDARD`
- Predefined engine consts `engine::general_purpose::{STANDARD, STANDARD_NO_PAD, URL_SAFE, URL_SAFE_NO_PAD}`
- These are `pub use`d into `engine` as well
- The `*_slice` decode/encode functions now return an error instead of panicking when the output slice is too small
- As part of this, there isn't now a public way to decode into a slice _exactly_ the size needed for inputs that
aren't multiples of 4 tokens. If adding up to 2 bytes to always be a multiple of 3 bytes for the decode buffer is
a problem, file an issue.

## Other changes

- `decoded_len_estimate()` is provided to make it easy to size decode buffers correctly.

# 0.20.0

## Breaking changes
Expand Down
2 changes: 1 addition & 1 deletion benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate criterion;

use base64::{
display,
engine::{Engine, STANDARD},
engine::{general_purpose::STANDARD, Engine},
write,
};
use criterion::{black_box, Bencher, BenchmarkId, Criterion, Throughput};
Expand Down
2 changes: 1 addition & 1 deletion src/decode.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::engine::{DecodeEstimate, Engine, STANDARD};
use crate::engine::{general_purpose::STANDARD, DecodeEstimate, Engine};
#[cfg(any(feature = "alloc", feature = "std", test))]
use alloc::vec::Vec;
use core::fmt;
Expand Down
5 changes: 2 additions & 3 deletions src/display.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! Enables base64'd output anywhere you might use a `Display` implementation, like a format string.
//!
//! ```
//! use base64::display::Base64Display;
//! use base64::engine::STANDARD;
//! use base64::{display::Base64Display, engine::general_purpose::STANDARD};
//!
//! let data = vec![0x0, 0x1, 0x2, 0x3];
//! let wrapper = Base64Display::new(&data, &STANDARD);
Expand Down Expand Up @@ -59,7 +58,7 @@ mod tests {
chunked_encode_matches_normal_encode_random, SinkTestHelper,
};
use super::*;
use crate::engine::STANDARD;
use crate::engine::general_purpose::STANDARD;

#[test]
fn basic_display() {
Expand Down
7 changes: 2 additions & 5 deletions src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::fmt;
use std::error;

#[cfg(any(feature = "alloc", feature = "std", test))]
use crate::engine::STANDARD;
use crate::engine::general_purpose::STANDARD;
use crate::engine::{Config, Engine};
use crate::PAD_BYTE;

Expand Down Expand Up @@ -161,10 +161,7 @@ mod tests {

use crate::{
alphabet,
engine::{
general_purpose::{GeneralPurpose, NO_PAD},
STANDARD,
},
engine::general_purpose::{GeneralPurpose, NO_PAD, STANDARD},
tests::{assert_encode_sanity, random_config, random_engine},
};
use rand::{
Expand Down
2 changes: 1 addition & 1 deletion src/engine/general_purpose/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ fn write_u64(output: &mut [u8], value: u64) {
mod tests {
use super::*;

use crate::engine::STANDARD;
use crate::engine::general_purpose::STANDARD;

#[test]
fn decode_chunk_precise_writes_only_6_bytes() {
Expand Down
10 changes: 5 additions & 5 deletions src/engine/general_purpose/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ fn read_u64(s: &[u8]) -> u64 {
///
/// The constants [PAD] and [NO_PAD] cover most use cases.
///
/// To specify the characters used, see [crate::alphabet::Alphabet].
/// To specify the characters used, see [Alphabet].
#[derive(Clone, Copy, Debug)]
pub struct GeneralPurposeConfig {
encode_padding: bool,
Expand Down Expand Up @@ -325,16 +325,16 @@ impl Config for GeneralPurposeConfig {
}
}

/// A [GeneralPurpose] engine using the [crate::alphabet::STANDARD] base64 alphabet and [crate::engine::general_purpose::PAD] config.
/// A [GeneralPurpose] engine using the [alphabet::STANDARD] base64 alphabet and [PAD] config.
pub const STANDARD: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, PAD);

/// A [GeneralPurpose] engine using the [crate::alphabet::STANDARD] base64 alphabet and [crate::engine::general_purpose::NO_PAD] config.
/// A [GeneralPurpose] engine using the [alphabet::STANDARD] base64 alphabet and [NO_PAD] config.
pub const STANDARD_NO_PAD: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, NO_PAD);

/// A [GeneralPurpose] engine using the [crate::alphabet::URL_SAFE] base64 alphabet and [crate::engine::general_purpose::PAD] config.
/// A [GeneralPurpose] engine using the [alphabet::URL_SAFE] base64 alphabet and [PAD] config.
pub const URL_SAFE: GeneralPurpose = GeneralPurpose::new(&alphabet::URL_SAFE, PAD);

/// A [GeneralPurpose] engine using the [crate::alphabet::URL_SAFE] base64 alphabet and [crate::engine::general_purpose::NO_PAD] config.
/// A [GeneralPurpose] engine using the [alphabet::URL_SAFE] base64 alphabet and [NO_PAD] config.
pub const URL_SAFE_NO_PAD: GeneralPurpose = GeneralPurpose::new(&alphabet::URL_SAFE, NO_PAD);

/// Include padding bytes when encoding, and require that they be present when decoding.
Expand Down
76 changes: 35 additions & 41 deletions src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,15 @@ mod naive;
#[cfg(test)]
mod tests;

pub use general_purpose::{
GeneralPurpose, GeneralPurposeConfig, STANDARD, STANDARD_NO_PAD, URL_SAFE, URL_SAFE_NO_PAD,
};
pub use general_purpose::{GeneralPurpose, GeneralPurposeConfig};

/// An `Engine` provides low-level encoding and decoding operations that all other higher-level parts of the API use. Users of the library will generally not need to implement this.
///
/// Different implementations offer different characteristics. The library currently ships with
/// [GeneralPurpose] that offers good speed and works on any CPU, with more choices
/// coming later, like a constant-time one when side channel resistance is called for, and vendor-specific vectorized ones for more speed.
///
/// See [STANDARD] if you just want standard base64. Otherwise, when possible, it's
/// See [general_purpose::STANDARD_NO_PAD] if you just want standard base64. Otherwise, when possible, it's
/// recommended to store the engine in a `const` so that references to it won't pose any lifetime
/// issues, and to avoid repeating the cost of engine setup.
///
Expand Down Expand Up @@ -112,16 +110,15 @@ pub trait Engine: Send + Sync {
/// # Example
///
/// ```rust
/// use base64::Engine as _;
/// const URL_SAFE_ENGINE: base64::engine::GeneralPurpose =
/// base64::engine::GeneralPurpose::new(
/// &base64::alphabet::URL_SAFE,
/// base64::engine::general_purpose::NO_PAD);
/// use base64::{Engine as _, engine::{self, general_purpose}, alphabet};
///
/// let b64 = base64::engine::STANDARD.encode(b"hello world~");
/// let b64 = general_purpose::STANDARD.encode(b"hello world~");
/// println!("{}", b64);
///
/// let b64_url = URL_SAFE_ENGINE.encode(b"hello internet~");
/// const CUSTOM_ENGINE: engine::GeneralPurpose =
/// engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::NO_PAD);
///
/// let b64_url = CUSTOM_ENGINE.encode(b"hello internet~");
#[cfg(any(feature = "alloc", feature = "std", test))]
fn encode<T: AsRef<[u8]>>(&self, input: T) -> String {
let encoded_size = encoded_len(input.as_ref().len(), self.config().encode_padding())
Expand All @@ -139,18 +136,17 @@ pub trait Engine: Send + Sync {
/// # Example
///
/// ```rust
/// use base64::Engine as _;
/// const URL_SAFE_ENGINE: base64::engine::GeneralPurpose =
/// base64::engine::GeneralPurpose::new(
/// &base64::alphabet::URL_SAFE,
/// base64::engine::general_purpose::NO_PAD);
/// use base64::{Engine as _, engine::{self, general_purpose}, alphabet};
/// const CUSTOM_ENGINE: engine::GeneralPurpose =
/// engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::NO_PAD);
///
/// fn main() {
/// let mut buf = String::new();
/// base64::engine::STANDARD.encode_string(b"hello world~", &mut buf);
/// general_purpose::STANDARD.encode_string(b"hello world~", &mut buf);
/// println!("{}", buf);
///
/// buf.clear();
/// URL_SAFE_ENGINE.encode_string(b"hello internet~", &mut buf);
/// CUSTOM_ENGINE.encode_string(b"hello internet~", &mut buf);
/// println!("{}", buf);
/// }
/// ```
Expand All @@ -176,18 +172,18 @@ pub trait Engine: Send + Sync {
/// # Example
///
/// ```rust
/// use base64::{engine, Engine as _};
/// use base64::{Engine as _, engine::general_purpose};
/// let s = b"hello internet!";
/// let mut buf = Vec::new();
/// // make sure we'll have a slice big enough for base64 + padding
/// buf.resize(s.len() * 4 / 3 + 4, 0);
///
/// let bytes_written = engine::STANDARD.encode_slice(s, &mut buf).unwrap();
/// let bytes_written = general_purpose::STANDARD.encode_slice(s, &mut buf).unwrap();
///
/// // shorten our vec down to just what was written
/// buf.truncate(bytes_written);
///
/// assert_eq!(s, engine::STANDARD.decode(&buf).unwrap().as_slice());
/// assert_eq!(s, general_purpose::STANDARD.decode(&buf).unwrap().as_slice());
/// ```
fn encode_slice<T: AsRef<[u8]>>(
&self,
Expand Down Expand Up @@ -216,17 +212,18 @@ pub trait Engine: Send + Sync {
/// # Example
///
/// ```rust
/// use base64::{Engine as _, Engine};
///
/// let bytes = base64::engine::STANDARD.decode("aGVsbG8gd29ybGR+Cg==").unwrap();
/// println!("{:?}", bytes);
///
/// // custom engine setup
/// let bytes_url = base64::engine::GeneralPurpose::new(
/// &base64::alphabet::URL_SAFE,
/// base64::engine::general_purpose::NO_PAD)
/// .decode("aGVsbG8gaW50ZXJuZXR-Cg").unwrap();
/// println!("{:?}", bytes_url);
/// use base64::{Engine as _, alphabet, engine::{self, general_purpose}};
///
/// let bytes = general_purpose::STANDARD
/// .decode("aGVsbG8gd29ybGR+Cg==").unwrap();
/// println!("{:?}", bytes);
///
/// // custom engine setup
/// let bytes_url = engine::GeneralPurpose::new(
/// &alphabet::URL_SAFE,
/// general_purpose::NO_PAD)
/// .decode("aGVsbG8gaW50ZXJuZXR-Cg").unwrap();
/// println!("{:?}", bytes_url);
/// ```
///
/// # Panics
Expand All @@ -253,25 +250,22 @@ pub trait Engine: Send + Sync {
/// # Example
///
/// ```rust
/// const URL_SAFE_ENGINE: base64::engine::GeneralPurpose =
/// base64::engine::GeneralPurpose::new(
/// &base64::alphabet::URL_SAFE,
/// base64::engine::general_purpose::PAD);
/// use base64::{Engine as _, alphabet, engine::{self, general_purpose}};
/// const CUSTOM_ENGINE: engine::GeneralPurpose =
/// engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::PAD);
///
/// fn main() {
/// use base64::Engine;
/// let mut buffer = Vec::<u8>::new();
/// // with the default engine
/// base64::engine::STANDARD.decode_vec(
/// "aGVsbG8gd29ybGR+Cg==",
/// &mut buffer,
/// ).unwrap();
/// general_purpose::STANDARD
/// .decode_vec("aGVsbG8gd29ybGR+Cg==", &mut buffer,).unwrap();
/// println!("{:?}", buffer);
///
/// buffer.clear();
///
/// // with a custom engine
/// URL_SAFE_ENGINE.decode_vec(
/// CUSTOM_ENGINE.decode_vec(
/// "aGVsbG8gaW50ZXJuZXR-Cg==",
/// &mut buffer,
/// ).unwrap();
Expand Down
Loading

0 comments on commit c3f6e7f

Please sign in to comment.