Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo-minimal.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ name = "hex-conservative"
version = "0.3.0"
dependencies = [
"arrayvec",
"if_rust_version",
"serde",
"serde_json",
]
Expand All @@ -42,6 +43,12 @@ dependencies = [
"rustc_version",
]

[[package]]
name = "if_rust_version"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec"

[[package]]
name = "itoa"
version = "0.3.0"
Expand Down
7 changes: 7 additions & 0 deletions Cargo-recent.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ name = "hex-conservative"
version = "0.3.0"
dependencies = [
"arrayvec",
"if_rust_version",
"serde",
"serde_json",
]
Expand All @@ -36,6 +37,12 @@ dependencies = [
"rustc_version",
]

[[package]]
name = "if_rust_version"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec"

[[package]]
name = "itoa"
version = "1.0.11"
Expand Down
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@ members = ["fuzz"]
default = ["std"]
std = ["alloc"]
alloc = []
# Enables detection of newer rust versions to provide additional features
# Turning it on may pull in dependencies that run build scripts and prolong compile time.
# This feature will do nothing once our MSRV supports version detection natively and will
# be removed using semver trick
newer-rust-version = ["dep:if_rust_version"]

[dependencies]
arrayvec = { version = "0.7.2", default-features = false }
if_rust_version = { version = "1.0.0", optional = true }
serde = { version = "1.0", default-features = false, optional = true }


Expand Down
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
# Bitcoin Hexadecimal Library
# A Rust hexadecimal decoding library

General purpose hex encoding/decoding library with a conservative MSRV and dependency policy.

## Stabilization strategy

Because downstream crates may need to return hex errors in their APIs and they need to be
stabilized soon, this crate only exposes the errors and two basic decoding functions. This
should already help with the vast majority of the cases and we're sufficiently confident that
these errors won't have a breaking change any time soon (possibly never).

If you're writing a binary you don't need to worry about any of this and just use the unstable
version for now. If you're writing a library you should use these stable errors in the API but
you may internally depend on the unstable crate version to get the advanced features that won't
affect your API. This way your API can stabilize before all features in this crate are fully
stable and you still can use all of them.

## Crate feature flags

* `std` - enables the standard library, on by default.
* `alloc` - enables features that require allocation such as decoding into `Vec<u8>`, implied
by `std`.
* `newer-rust-version` - enables Rust version detection and thus newer features, may add
dependency on a feature detection crate to reduce compile times. This
feature is expected to do nothing once the native detection is in Rust
and our MSRV is at least that version. We may also remove the feature
gate in 2.0 with semver trick once that happens.

## Minimum Supported Rust Version (MSRV)

This library should compile with almost any combination of features on **Rust 1.63.0**, however we
reserve the right to use features to guard compiler specific code so `--all-features` may not work
using the MSRV toolchain.

### Githooks
### Policy

We don't intend to bump MSRV until the newer Rust version is at least two years old and also
included in Debian stable (1.63 is in Debian 12 at the moment).

Note though that the dependencies may have looser policy. This is not considered
breaking/wrong - you would just need to pin them in `Cargo.lock` (not `.toml`).


## Githooks

To assist devs in catching errors _before_ running CI we provide some githooks. If you do not
already have locally configured githooks you can use the ones in this repository by running, in the
Expand Down
4 changes: 2 additions & 2 deletions contrib/test_vars.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
# shellcheck disable=SC2034

# Test all these features with "std" enabled.
FEATURES_WITH_STD="serde"
FEATURES_WITH_STD="serde newer-rust-version"

# Test all these features without "std" or "alloc" enabled.
FEATURES_WITHOUT_STD="alloc serde"
FEATURES_WITHOUT_STD="alloc serde newer-rust-version"

# Run these examples.
EXAMPLES="hexy:std wrap_array:std serde:std,serde"
6 changes: 4 additions & 2 deletions examples/hexy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
use std::fmt;
use std::str::FromStr;

use hex_conservative::{fmt_hex_exact, Case, DisplayHex as _, FromHex as _, HexToArrayError};
use hex_conservative::{
fmt_hex_exact, Case, DecodeFixedSizedBytesError, DisplayHex as _, FromHex as _,
};

fn main() {
let s = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
Expand Down Expand Up @@ -46,7 +48,7 @@ impl fmt::Display for Hexy {
}

impl FromStr for Hexy {
type Err = HexToArrayError;
type Err = DecodeFixedSizedBytesError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
// Errors if the input is invalid
Expand Down
4 changes: 2 additions & 2 deletions examples/wrap_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use core::fmt;
use core::str::FromStr;

use hex_conservative::{DisplayHex as _, FromHex as _, HexToArrayError};
use hex_conservative::{DecodeFixedSizedBytesError, DisplayHex as _, FromHex as _};

fn main() {
let hex = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
Expand Down Expand Up @@ -72,6 +72,6 @@ impl fmt::UpperHex for Wrap {
}

impl FromStr for Wrap {
type Err = HexToArrayError;
type Err = DecodeFixedSizedBytesError;
fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Self(<[u8; 32]>::from_hex(s)?)) }
}
16 changes: 8 additions & 8 deletions src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
//! assert_eq!(format!("{:0>8}", v.as_hex()), "0000abab");
//!```

#[cfg(all(feature = "alloc", not(feature = "std")))]
#[cfg(feature = "alloc")]
use alloc::string::String;
use core::borrow::Borrow;
use core::fmt;

use super::Case;
#[cfg(any(test, feature = "std"))]
#[cfg(feature = "std")]
use super::Table;
use crate::buf_encoder::BufEncoder;

Expand Down Expand Up @@ -607,16 +607,14 @@ where

/// Given a `T:` [`fmt::Write`], `HexWriter` implements [`std::io::Write`]
/// and writes the source bytes to its inner `T` as hex characters.
#[cfg(any(test, feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(test, feature = "std"))))]
#[cfg(feature = "std")]
#[derive(Debug)]
pub struct HexWriter<T> {
writer: T,
table: &'static Table,
}

#[cfg(any(test, feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(test, feature = "std"))))]
#[cfg(feature = "std")]
impl<T> HexWriter<T> {
/// Creates a `HexWriter` that writes the source bytes to `dest` as hex characters
/// in the given `case`.
Expand All @@ -627,8 +625,7 @@ impl<T> HexWriter<T> {
pub fn into_inner(self) -> T { self.writer }
}

#[cfg(any(test, feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(test, feature = "std"))))]
#[cfg(feature = "std")]
impl<T> std::io::Write for HexWriter<T>
where
T: core::fmt::Write,
Expand Down Expand Up @@ -674,6 +671,7 @@ mod tests {
use core::marker::PhantomData;

use super::*;
use crate::alloc::vec::Vec;

fn check_encoding(bytes: &[u8]) {
use core::fmt::Write;
Expand Down Expand Up @@ -1002,6 +1000,8 @@ mod tests {

#[cfg(feature = "std")]
mod std {
use alloc::string::String;
use alloc::vec::Vec;
use std::io::Write as _;

use arrayvec::ArrayString;
Expand Down
Loading