Skip to content

Commit a354af2

Browse files
authored
Add alloc feature (#42)
1 parent d8fa31f commit a354af2

File tree

8 files changed

+128
-44
lines changed

8 files changed

+128
-44
lines changed

.gitlab-ci-matrix.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ steps:
2222
script:
2323
- cargo test
2424
- cargo test --no-default-features
25+
- cargo test --no-default-features --features alloc
26+
- cargo test --no-default-features --features std
27+
- cargo test --no-default-features --features serde
2528
dependencies:
2629
- compile
2730

.gitlab-ci.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ test:rust-stable:
115115
- cargo test
116116
- cargo test --features serde
117117
- cargo test --no-default-features
118+
- cargo test --no-default-features --features std
119+
- cargo test --no-default-features --features alloc
120+
- cargo test --no-default-features --features serde
118121
variables:
119122
RUST_KEY: rust-stable
120123

@@ -127,6 +130,9 @@ test:rust-stable-musl:
127130
- cargo test
128131
- cargo test --features serde
129132
- cargo test --no-default-features
133+
- cargo test --no-default-features --features std
134+
- cargo test --no-default-features --features alloc
135+
- cargo test --no-default-features --features serde
130136
variables:
131137
RUST_KEY: rust-stable-musl
132138

@@ -139,6 +145,9 @@ test:rust-beta:
139145
- cargo test
140146
- cargo test --features serde
141147
- cargo test --no-default-features
148+
- cargo test --no-default-features --features std
149+
- cargo test --no-default-features --features alloc
150+
- cargo test --no-default-features --features serde
142151
variables:
143152
RUST_KEY: rust-beta
144153

@@ -151,6 +160,9 @@ test:rust-beta-musl:
151160
- cargo test
152161
- cargo test --features serde
153162
- cargo test --no-default-features
163+
- cargo test --no-default-features --features std
164+
- cargo test --no-default-features --features alloc
165+
- cargo test --no-default-features --features serde
154166
variables:
155167
RUST_KEY: rust-beta-musl
156168

@@ -163,6 +175,9 @@ test:rust-nightly:
163175
- cargo test
164176
- cargo test --features serde
165177
- cargo test --no-default-features
178+
- cargo test --no-default-features --features std
179+
- cargo test --no-default-features --features alloc
180+
- cargo test --no-default-features --features serde
166181
variables:
167182
RUST_KEY: rust-nightly
168183
allow_failure: true
@@ -176,7 +191,9 @@ test:rust-nightly-musl:
176191
- cargo test
177192
- cargo test --features serde
178193
- cargo test --no-default-features
194+
- cargo test --no-default-features --features std
195+
- cargo test --no-default-features --features alloc
196+
- cargo test --no-default-features --features serde
179197
variables:
180198
RUST_KEY: rust-nightly-musl
181199
allow_failure: true
182-

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ install:
2121

2222
script:
2323
- if [[ $TRAVIS_RUST_VERSION == "stable" && $TRAVIS_OS_NAME == "linux" ]]; then cargo fmt -- --check; fi
24-
- if [[ $TRAVIS_RUST_VERSION == "stable" && $TRAVIS_OS_NAME == "linux" ]]; then cargo clippy -- -D clippy::all; fi
24+
- if [[ $TRAVIS_RUST_VERSION == "stable" && $TRAVIS_OS_NAME == "linux" ]]; then cargo clippy -- -W clippy::all; fi
2525
- cargo test
2626
- cargo test --features serde
2727
- cargo test --no-default-features
28+
- cargo test --no-default-features --features std
29+
- cargo test --no-default-features --features alloc
30+
- cargo test --no-default-features --features serde
2831
# Validate benches still work.
2932
- cargo bench --all -- --test

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ travis-ci = { repository = "KokaKiwi/rust-hex", branch = "master" }
1616

1717
[features]
1818
default = ["std"]
19-
std = []
19+
alloc = []
20+
std = ["alloc"]
2021

2122
[[bench]]
2223
name = "hex"
2324
harness = false
2425

2526
[dependencies]
26-
serde = { version = "1.0", optional = true }
27+
serde = { version = "1.0", default-features = false, optional = true }
2728

2829
[dev-dependencies]
2930
criterion = "0.3"

src/error.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ impl fmt::Display for FromHexError {
3333
}
3434

3535
#[cfg(test)]
36+
// this feature flag is here to suppress unused
37+
// warnings of `super::*` and `pretty_assertions::assert_eq`
38+
#[cfg(feature = "alloc")]
3639
mod tests {
3740
use super::*;
38-
#[cfg(not(feature = "std"))]
41+
#[cfg(feature = "alloc")]
3942
use alloc::string::ToString;
4043
use pretty_assertions::assert_eq;
4144

4245
#[test]
46+
#[cfg(feature = "alloc")]
4347
fn test_display() {
4448
assert_eq!(
4549
FromHexError::InvalidHexCharacter { c: '\n', index: 5 }.to_string(),

src/lib.rs

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@
1515
//! # Example
1616
//!
1717
//! ```
18+
//! # #[cfg(not(feature = "alloc"))]
19+
//! # let mut output = [0; 0x18];
20+
//! #
21+
//! # #[cfg(not(feature = "alloc"))]
22+
//! # hex::encode_to_slice(b"Hello world!", &mut output).unwrap();
23+
//! #
24+
//! # #[cfg(not(feature = "alloc"))]
25+
//! # let hex_string = ::core::str::from_utf8(&output).unwrap();
26+
//! #
27+
//! # #[cfg(feature = "alloc")]
1828
//! let hex_string = hex::encode("Hello world!");
1929
//!
2030
//! println!("{}", hex_string); // Prints "48656c6c6f20776f726c6421"
@@ -27,9 +37,9 @@
2737
#![cfg_attr(docsrs, feature(doc_cfg))]
2838
#![allow(clippy::unreadable_literal)]
2939

30-
#[cfg(not(feature = "std"))]
40+
#[cfg(feature = "alloc")]
3141
extern crate alloc;
32-
#[cfg(not(feature = "std"))]
42+
#[cfg(feature = "alloc")]
3343
use alloc::{string::String, vec::Vec};
3444

3545
use core::iter;
@@ -41,7 +51,9 @@ pub use crate::error::FromHexError;
4151
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
4252
pub mod serde;
4353
#[cfg(feature = "serde")]
44-
pub use crate::serde::{deserialize, serialize, serialize_upper};
54+
pub use crate::serde::deserialize;
55+
#[cfg(all(feature = "alloc", feature = "serde"))]
56+
pub use crate::serde::{serialize, serialize_upper};
4557

4658
/// Encoding values as hex string.
4759
///
@@ -95,7 +107,7 @@ impl<'a> Iterator for BytesToHexChars<'a> {
95107
Some(current) => Some(current),
96108
None => self.inner.next().map(|byte| {
97109
let current = self.table[(byte >> 4) as usize] as char;
98-
self.next = Some(self.table[(byte & 0xf) as usize] as char);
110+
self.next = Some(self.table[(byte & 0x0F) as usize] as char);
99111
current
100112
}),
101113
}
@@ -117,6 +129,7 @@ impl<'a> iter::ExactSizeIterator for BytesToHexChars<'a> {
117129
}
118130
}
119131

132+
#[inline]
120133
fn encode_to_iter<T: iter::FromIterator<char>>(table: &'static [u8; 16], source: &[u8]) -> T {
121134
BytesToHexChars::new(source, table).collect()
122135
}
@@ -139,17 +152,14 @@ impl<T: AsRef<[u8]>> ToHex for T {
139152
///
140153
/// ```
141154
/// use hex::FromHex;
155+
/// use core::str;
142156
///
143-
/// match Vec::from_hex("48656c6c6f20776f726c6421") {
144-
/// Ok(vec) => {
145-
/// for b in vec {
146-
/// println!("{}", b as char);
147-
/// }
148-
/// }
149-
/// Err(e) => {
150-
/// // Deal with the error ...
151-
/// }
152-
/// }
157+
/// let buffer = <[u8; 12]>::from_hex("48656c6c6f20776f726c6421")?;
158+
/// let string = str::from_utf8(&buffer).expect("invalid buffer length");
159+
///
160+
/// println!("{}", string); // prints "Hello world!"
161+
/// # assert_eq!("Hello world!", string);
162+
/// # Ok::<(), hex::FromHexError>(())
153163
/// ```
154164
pub trait FromHex: Sized {
155165
type Error;
@@ -174,6 +184,7 @@ fn val(c: u8, idx: usize) -> Result<u8, FromHexError> {
174184
}
175185
}
176186

187+
#[cfg(feature = "alloc")]
177188
impl FromHex for Vec<u8> {
178189
type Error = FromHexError;
179190

@@ -198,7 +209,7 @@ macro_rules! from_hex_array_impl {
198209
type Error = FromHexError;
199210

200211
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
201-
let mut out = [0u8; $len];
212+
let mut out = [0_u8; $len];
202213
decode_to_slice(hex, &mut out as &mut [u8])?;
203214
Ok(out)
204215
}
@@ -243,6 +254,8 @@ from_hex_array_impl! {
243254
/// assert_eq!(hex::encode("Hello world!"), "48656c6c6f20776f726c6421");
244255
/// assert_eq!(hex::encode(vec![1, 2, 3, 15, 16]), "0102030f10");
245256
/// ```
257+
#[must_use]
258+
#[cfg(feature = "alloc")]
246259
pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
247260
data.encode_hex()
248261
}
@@ -257,6 +270,8 @@ pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
257270
/// assert_eq!(hex::encode_upper("Hello world!"), "48656C6C6F20776F726C6421");
258271
/// assert_eq!(hex::encode_upper(vec![1, 2, 3, 15, 16]), "0102030F10");
259272
/// ```
273+
#[must_use]
274+
#[cfg(feature = "alloc")]
260275
pub fn encode_upper<T: AsRef<[u8]>>(data: T) -> String {
261276
data.encode_hex_upper()
262277
}
@@ -277,6 +292,7 @@ pub fn encode_upper<T: AsRef<[u8]>>(data: T) -> String {
277292
/// assert_eq!(hex::decode("123"), Err(hex::FromHexError::OddLength));
278293
/// assert!(hex::decode("foo").is_err());
279294
/// ```
295+
#[cfg(feature = "alloc")]
280296
pub fn decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, FromHexError> {
281297
FromHex::from_hex(data)
282298
}
@@ -316,11 +332,14 @@ pub fn decode_to_slice<T: AsRef<[u8]>>(data: T, out: &mut [u8]) -> Result<(), Fr
316332
// (4, 5)
317333
// (6, 7)
318334
// ...
335+
#[inline]
319336
fn generate_iter(len: usize) -> impl Iterator<Item = (usize, usize)> {
320337
(0..len).step_by(2).zip((0..len).skip(1).step_by(2))
321338
}
322339

323340
// the inverse of `val`.
341+
#[inline]
342+
#[must_use]
324343
fn byte2hex(byte: u8, table: &[u8; 16]) -> (u8, u8) {
325344
let high = table[((byte & 0xf0) >> 4) as usize];
326345
let low = table[(byte & 0x0f) as usize];
@@ -350,7 +369,11 @@ pub fn encode_to_slice<T: AsRef<[u8]>>(input: T, output: &mut [u8]) -> Result<()
350369
return Err(FromHexError::InvalidStringLength);
351370
}
352371

353-
for (byte, (i, j)) in input.as_ref().iter().zip(generate_iter(input.as_ref().len() * 2)) {
372+
for (byte, (i, j)) in input
373+
.as_ref()
374+
.iter()
375+
.zip(generate_iter(input.as_ref().len() * 2))
376+
{
354377
let (high, low) = byte2hex(*byte, HEX_CHARS_LOWER);
355378
output[i] = high;
356379
output[j] = low;
@@ -362,11 +385,12 @@ pub fn encode_to_slice<T: AsRef<[u8]>>(input: T, output: &mut [u8]) -> Result<()
362385
#[cfg(test)]
363386
mod test {
364387
use super::*;
365-
#[cfg(not(feature = "std"))]
388+
#[cfg(feature = "alloc")]
366389
use alloc::string::ToString;
367390
use pretty_assertions::assert_eq;
368391

369392
#[test]
393+
#[cfg(feature = "alloc")]
370394
fn test_gen_iter() {
371395
let mut result = Vec::new();
372396
result.push((0, 1));
@@ -405,38 +429,53 @@ mod test {
405429

406430
let mut output_3 = [0; 4];
407431

408-
assert_eq!(decode_to_slice(b"6", &mut output_3), Err(FromHexError::OddLength));
432+
assert_eq!(
433+
decode_to_slice(b"6", &mut output_3),
434+
Err(FromHexError::OddLength)
435+
);
409436
}
410437

411438
#[test]
439+
#[cfg(feature = "alloc")]
412440
fn test_encode() {
413441
assert_eq!(encode("foobar"), "666f6f626172");
414442
}
415443

416444
#[test]
445+
#[cfg(feature = "alloc")]
417446
fn test_decode() {
418-
assert_eq!(decode("666f6f626172"), Ok(String::from("foobar").into_bytes()));
447+
assert_eq!(
448+
decode("666f6f626172"),
449+
Ok(String::from("foobar").into_bytes())
450+
);
419451
}
420452

421453
#[test]
454+
#[cfg(feature = "alloc")]
422455
pub fn test_from_hex_okay_str() {
423456
assert_eq!(Vec::from_hex("666f6f626172").unwrap(), b"foobar");
424457
assert_eq!(Vec::from_hex("666F6F626172").unwrap(), b"foobar");
425458
}
426459

427460
#[test]
461+
#[cfg(feature = "alloc")]
428462
pub fn test_from_hex_okay_bytes() {
429463
assert_eq!(Vec::from_hex(b"666f6f626172").unwrap(), b"foobar");
430464
assert_eq!(Vec::from_hex(b"666F6F626172").unwrap(), b"foobar");
431465
}
432466

433467
#[test]
468+
#[cfg(feature = "alloc")]
434469
pub fn test_invalid_length() {
435470
assert_eq!(Vec::from_hex("1").unwrap_err(), FromHexError::OddLength);
436-
assert_eq!(Vec::from_hex("666f6f6261721").unwrap_err(), FromHexError::OddLength);
471+
assert_eq!(
472+
Vec::from_hex("666f6f6261721").unwrap_err(),
473+
FromHexError::OddLength
474+
);
437475
}
438476

439477
#[test]
478+
#[cfg(feature = "alloc")]
440479
pub fn test_invalid_char() {
441480
assert_eq!(
442481
Vec::from_hex("66ag").unwrap_err(),
@@ -445,11 +484,13 @@ mod test {
445484
}
446485

447486
#[test]
487+
#[cfg(feature = "alloc")]
448488
pub fn test_empty() {
449489
assert_eq!(Vec::from_hex("").unwrap(), b"");
450490
}
451491

452492
#[test]
493+
#[cfg(feature = "alloc")]
453494
pub fn test_from_hex_whitespace() {
454495
assert_eq!(
455496
Vec::from_hex("666f 6f62617").unwrap_err(),
@@ -471,6 +512,7 @@ mod test {
471512
}
472513

473514
#[test]
515+
#[cfg(feature = "alloc")]
474516
fn test_to_hex() {
475517
assert_eq!(
476518
[0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex::<String>(),

0 commit comments

Comments
 (0)