Revamp API

This commit is contained in:
Nicolas Stalder
2020-11-29 22:00:44 +01:00
parent 40a54b71df
commit 5326aa4b73
26 changed files with 691 additions and 597 deletions
+8
View File
@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.1.0-alpha.1] - 2020-11-29
- Revamp of logs: only local/gated macros are generated now
- Remove optional semihosting dependency, relegate example implementation to QEMU test
- Relegate stdout/stderr flushers to example submodule
- Simplification of `hex` submodule, removing typenum and implementing all block sizes
- Addition of "truncated" hex formats like `hex_fmt`, remove it as dependency instead
## [0.1.0-alpha.1] - 2020-11-28
Test the release process, meditate on the `local_*!` issue.
+3 -10
View File
@@ -1,6 +1,6 @@
[package]
name = "delog"
version = "0.1.0-alpha.1"
version = "0.1.0-alpha.2"
description = "Deferred logging, an implementation and extension of Rust's standard logging facade."
authors = ["Nicolas Stalder <n@stalder.io>"]
license = "Apache-2.0 OR MIT"
@@ -16,18 +16,11 @@ features = ["example"]
targets = []
[dependencies]
cortex-m-semihosting = { version = "0.3.5", optional = true }
hex_fmt = "0.3.0"
log = "0.4.11"
typenum = "1.12.0"
[dev-dependencies]
insta = "1.3.0"
[features]
default = ["fallible", "immediate"]
fallible = []
immediate = []
example = ["std-example-flushers"]
semihosting-example-flushers = ["cortex-m-semihosting"]
std-example-flushers = []
example = ["std"]
std = []
+3 -1
View File
@@ -8,9 +8,11 @@ edition = "2018"
[dependencies.delog]
path = ".."
features = ["std-example-flushers"]
features = ["example"]
[features]
default = ["log-all"]
log-none = []
log-all = []
log-warn = []
+2 -2
View File
@@ -1,9 +1,9 @@
#[macro_use]
extern crate delog;
use delog::upstream::info;
use delog::log::info;
use delog::flushers::StdoutFlusher;
use delog::example::StdoutFlusher;
delog!(Delogger, 25, StdoutFlusher);
+2 -2
View File
@@ -1,10 +1,10 @@
#[macro_use]
extern crate delog;
use delog::flushers::StdoutFlusher;
use delog::example::StdoutFlusher;
delog!(Delogger, 256, StdoutFlusher);
local_macros!();
generate_macros!();
static FLUSHER: StdoutFlusher = StdoutFlusher {};
+17 -13
View File
@@ -1,10 +1,13 @@
#[macro_use]
extern crate delog;
use delog::flushers::StdoutFlusher;
use delog::renderers::RipgrepRenderer;
use delog::{
example::StdoutFlusher,
render::RipgrepRenderer,
};
delog!(Delogger, 196, StdoutFlusher, renderer: RipgrepRenderer);
local_macros!();
generate_macros!();
static STDOUT_FLUSHER: StdoutFlusher = StdoutFlusher {};
static RENDERER: RipgrepRenderer = RipgrepRenderer {};
@@ -12,22 +15,23 @@ static RENDERER: RipgrepRenderer = RipgrepRenderer {};
fn main() {
Delogger::init(delog::LevelFilter::Info, &STDOUT_FLUSHER, &RENDERER).ok();
// do some serious work
global_try_warn!("This is a warning").unwrap();
global_try_info!("This is information").unwrap();
global_try_warn!("This is a warning").unwrap();
global_try_info!("This is information").expect_err("should error out due to incapacity");
// // do some serious work
// global_try_warn!("This is a warning").unwrap();
// global_try_info!("This is information").unwrap();
// global_try_warn!("This is a warning").unwrap();
// global_try_info!("This is information").expect_err("should error out due to incapacity");
// flush the logs
Delogger::flush();
// // flush the logs
// Delogger::flush();
println!("===");
// println!("===");
try_warn!("This is a warning").unwrap();
try_info!(target: "!", "This is information NOW").unwrap();
try_info!("This is information").unwrap();
try_warn!(target: "!", "This is a warning").unwrap();
try_warn_now!("This is a warning").unwrap();
try_warn!("This is a warning").unwrap();
#[cfg(not(feature = "log-none"))]
#[cfg(not(any(feature = "log-none", feature = "log-warn")))]
try_info!("This is information").expect_err("should error out due to incapacity");
#[cfg(feature = "log-none")]
try_info!("This is information").ok();
+17 -1
View File
@@ -1,10 +1,26 @@
use delog::hex_str;
use delog::{hex_str, hexstr};
fn main() {
let buf = [1u8, 2, 3, 0xA1, 0xB7, 0xFF, 0x3];
println!("'{}'", hexstr!(&buf));
println!("'{}'", hex_str!(&buf));
println!("'{:4}'", hex_str!(&buf));
println!("'{:<4}'", hex_str!(&buf));
println!("'{:>4}'", hex_str!(&buf));
println!("'{}'", hex_str!(&buf, 2));
println!("'{:02x}'", hex_str!(&buf, 2));
println!("'{}'", hex_str!(&buf, 4));
println!("'{:4}'", hex_str!(&buf, 2));
println!("'{:<4}'", hex_str!(&buf, 2));
println!("'{:>4}'", hex_str!(&buf, 2));
println!("'{}'", hex_str!(&buf[..], 4));
println!("'{}'", hex_str!(&buf, 3));
println!("'{}'", hex_str!(&buf, 2, sep: "|"));
println!("'{:2}'", hex_str!(&buf, 2, sep: "|"));
println!("'{:3x}'", hex_str!(&buf, 2, sep: "|"));
println!("'{:>3x}'", hex_str!(&buf, 2, sep: "|"));
println!("'{:<3x}'", hex_str!(&buf, 2, sep: "|"));
println!("'{:4}'", hex_str!(&buf, 2, sep: "|"));
println!("'{:5x}'", hex_str!(&buf, 2, sep: "|"));
println!("'{:6}'", hex_str!(&buf, 2, sep: "|"));
}
+4 -1
View File
@@ -12,12 +12,15 @@ cfg-if = "1"
[dependencies.lib-a]
path = "lib-a"
[dependencies.lib-a1]
path = "lib-a/lib-a1"
[dependencies.lib-b]
path = "lib-b"
[dependencies.delog]
path = ".."
features = ["std-example-flushers"]
features = ["example"]
[features]
default = ["verbose-renderer"]
+1 -1
View File
@@ -2,6 +2,6 @@ something:
cargo run
cargo run --no-default-features --features lib-a/log-all,lib-b/log-all
cargo run --features lib-a/log-all,lib-b/log-all
cargo run --features lib-a/log-all
cargo run --features lib-a/log-all,lib-a1/log-all
cargo run --features lib-b/log-all
cargo run --features lib-a/log-trace,lib-b/log-error
+6
View File
@@ -4,6 +4,12 @@ version = "0.1.0"
authors = ["Nicolas Stalder <n@stalder.io>"]
edition = "2018"
[dependencies]
log = "0.4"
[dependencies.lib-a1]
path = "lib-a1"
[dependencies.delog]
path = "../.."
+14 -2
View File
@@ -4,6 +4,18 @@ version = "0.1.0"
authors = ["Nicolas Stalder <n@stalder.io>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4"
[dependencies.delog]
path = "../../.."
[features]
log-error = []
log-warn = ["log-error"]
log-info = ["log-warn"]
log-debug = ["log-info"]
log-trace = ["log-debug"]
log-all = ["log-trace"]
log-none = []
+19 -5
View File
@@ -1,7 +1,21 @@
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
delog::generate_macros!();
pub fn f() {
submodule::sub_f()
}
pub mod submodule {
pub fn sub_f() {
log::info!("global info log from lib_a1");
log::warn!("global info log from lib_a1");
// log!(delog::Level::Info, "log level info from lib_a::f");
// log!(target: "!", delog::Level::Info, "log level info from lib_a::f");
// log!(target: "!", delog::Level::Warn, "log level warn from lib_a::f");
info!("local info from lib_a1::f");
warn!("local warn from lib_a1::f");
info_now!("immediate local info from lib_a1::f");
warn_now!("immediate local warn from lib_a1::f");
}
}
+17 -10
View File
@@ -1,15 +1,22 @@
delog::local_macros!();
delog::generate_macros!();
pub fn f() {
info!("global info log from lib_a");
warn!("global info log from lib_a");
submodule::sub_f();
lib_a1::f();
}
log!(delog::Level::Info, "log level info from lib_a::f");
log!(target: "!", delog::Level::Info, "log level info from lib_a::f");
log!(target: "!", delog::Level::Warn, "log level warn from lib_a::f");
pub mod submodule {
pub fn sub_f() {
log::info!("global info log from lib_a");
log::warn!("global info log from lib_a");
info!("local info from lib_a::f");
warn!("local warn from lib_a::f");
info!(target: "!", "immediate local info from lib_a::f");
warn!(target: "!", "immediate local warn from lib_a::f");
// log!(delog::Level::Info, "log level info from lib_a::f");
// log!(target: "!", delog::Level::Info, "log level info from lib_a::f");
// log!(target: "!", delog::Level::Warn, "log level warn from lib_a::f");
info!("local info from lib_a::f");
warn!("local warn from lib_a::f");
info_now!("immediate local info from lib_a::f");
warn_now!("immediate local warn from lib_a::f");
}
}
+6 -4
View File
@@ -1,12 +1,14 @@
delog::local_macros!();
delog::generate_macros!();
use delog::log;
pub fn g() {
delog::upstream::info!("global info from B");
log::info!("global info from B");
warn!("info from B");
log!(delog::Level::Info, "log level info from B");
log!(target: "!", delog::Level::Info, "info from B");
log!(target: "!", delog::Level::Warn, "warn from B");
log!(target: "!", delog::Level::Info, "log! ! info from B");
log!(target: "!", delog::Level::Warn, "log! ! warn from B");
info!("info from B");
warn!("warn from B");
+6 -6
View File
@@ -1,17 +1,17 @@
#[macro_use]
extern crate delog;
use delog::flushers::StdoutFlusher;
use delog::example::StdoutFlusher;
cfg_if::cfg_if! {
if #[cfg(feature = "verbose-renderer")] {
use delog::renderers::RipgrepRenderer;
use delog::render::RipgrepRenderer;
delog!(Delogger, 4096, StdoutFlusher, renderer: RipgrepRenderer);
static RENDERER: RipgrepRenderer = RipgrepRenderer {};
} else {
use delog::renderers::ArgumentsRenderer;
use delog::render::DefaultRenderer;
delog!(Delogger, 4096, StdoutFlusher);
static RENDERER: ArgumentsRenderer = ArgumentsRenderer {};
static RENDERER: DefaultRenderer = DefaultRenderer {};
}
}
@@ -21,7 +21,7 @@ fn main() {
Delogger::init(delog::LevelFilter::Info, &FLUSHER, &RENDERER).expect("all good");
lib_a::f();
lib_b::g();
println!("{:?}", delog::trylogger().unwrap().statistics());
println!("{:?}", delog::logger().unwrap().statistics());
Delogger::flush();
println!("{:?}", delog::trylogger().unwrap().statistics());
println!("{:?}", delog::logger().unwrap().statistics());
}
-1
View File
@@ -14,7 +14,6 @@ panic-semihosting = { version = "0.5.3", features = ["exit"] }
[dependencies.delog]
path = ".."
features = ["semihosting-example-flushers"]
[features]
default = ["log-all"]
+2 -2
View File
@@ -17,7 +17,7 @@ impl delog::Flusher for SemihostingFlusher {
}
}
delog::local_macros!();
delog::generate_macros!();
delog!(Delogger, 256, SemihostingFlusher);
@@ -43,7 +43,7 @@ fn main() -> ! {
test_runs();
debug_now!("{:?}", delog::trylogger().unwrap().statistics());
debug_now!("{:?}", delog::logger().unwrap().statistics());
info_now!("All tests passed");
debug::exit(debug::EXIT_SUCCESS);
+36 -8
View File
@@ -1,14 +1,21 @@
//! An example deferred logger, generated as
//! `delog!(Delogger, 4096, StdoutFlusher, ArgumentsRenderer)`.
//! `delog!(Delogger, 4096, StderrFlusher, DefaultRenderer)`.
//!
//! It is included here for documentation purposes only.
//!
//! Do ensure that the `example` feature is not active in production!
//!
//! ```
//! use delog::flushers::StdoutFlusher;
//! delog!(Delogger, 256, StdoutFlusher);
//! static STDOUT_FLUSHER: StdoutFlusher = StdoutFlusher {};
//! pub struct StderrFlusher {}
//!
//! impl crate::Flusher for StderrFlusher {
//! fn flush(&self, logs: &str) {
//! print!("{}", logs);
//! }
//! }
//!
//! delog!(Delogger, 256, StderrFlusher);
//! static FLUSHER: StderrFlusher = StderrFlusher {};
//! Delogger::init(log::LevelFilter::Info, &STDOUT_FLUSHER).ok();
//!
//! warn!("This is a warning");
@@ -18,10 +25,31 @@
//! Delogger::flush();
//! ```
use crate::flushers::StdoutFlusher;
use crate::renderers::ArgumentsRenderer;
// use crate::flushers::StderrFlusher;
use crate::render::DefaultRenderer;
crate::delog!(Delogger, 4096, StdoutFlusher, renderer: ArgumentsRenderer);
#[derive(Debug, Default)]
/// Flushes logs to stderr.
pub struct StderrFlusher {}
crate::local_macros!();
impl crate::Flusher for StderrFlusher {
fn flush(&self, logs: &str) {
print!("{}", logs);
}
}
#[derive(Debug, Default)]
/// Flushes logs to stdout.
pub struct StdoutFlusher {}
impl crate::Flusher for StdoutFlusher {
fn flush(&self, logs: &str) {
print!("{}", logs);
}
}
crate::delog!(Delogger, 4096, StderrFlusher, renderer: DefaultRenderer);
// #[macro_export]
// crate::generate_macros!();
+31 -8
View File
@@ -6,12 +6,35 @@
//! selected. Additionally setting `std` gives stdout/stderr flushers,
//! while additionally setting `semihosting` gives flushers to host's stdout/stderr.
#[cfg(any(feature = "std-example-flushers", test))]
mod std;
#[cfg(any(feature = "std-example-flushers", test))]
pub use crate::flushers::std::*;
// #[cfg(any(feature = "std-example-flushers", test))]
// mod std;
// #[cfg(any(feature = "std-example-flushers", test))]
// pub use crate::flushers::std::*;
// // #[cfg(feature = "semihosting-example-flushers")]
// // mod semihosting;
// // #[cfg(feature = "semihosting-example-flushers")]
// // pub use crate::flushers::semihosting::*;
use crate::Flusher;
#[derive(Debug, Default)]
/// Flushes logs to stdout.
pub struct StdoutFlusher {}
impl Flusher for StdoutFlusher {
fn flush(&self, logs: &str) {
print!("{}", logs);
}
}
#[derive(Debug, Default)]
/// Flushes logs to stderr.
pub struct StderrFlusher {}
impl Flusher for StderrFlusher {
fn flush(&self, logs: &str) {
eprint!("{}", logs);
}
}
#[cfg(feature = "semihosting-example-flushers")]
mod semihosting;
#[cfg(feature = "semihosting-example-flushers")]
pub use crate::flushers::semihosting::*;
+138 -167
View File
@@ -39,14 +39,49 @@
use core::marker::PhantomData;
use core::fmt;
/// re-export from `hex_fmt`
///
pub use hex_fmt::HexFmt;
/// re-export from `hex_fmt`
///
pub use hex_fmt::HexList;
///// re-export from `hex_fmt`
/////
//pub use hex_fmt::HexFmt;
///// re-export from `hex_fmt`
/////
//pub use hex_fmt::HexList;
pub use typenum::{consts, Unsigned};
/// A type that specifies an unsigned integer.
///
/// We use this instead of `typenum` as the latter currently lacks
/// a mapping from `usize` to the associated type.
pub trait Unsigned {
/// The actual number.
const N: usize;
}
/// Sorry little replacement for the missing int to Unsigned type map in `typenum`.
#[macro_export]
#[doc(hidden)]
macro_rules! typeint {
($name:ident, $n:expr) => {
/// A type that represents the integer `N`.
pub struct $name {}
impl $crate::hex::Unsigned for $name {
const N: usize = $n;
}
}
}
typeint!(U1, 1);
typeint!(U2, 1);
typeint!(U3, 1);
typeint!(U4, 1);
typeint!(U5, 1);
typeint!(U6, 1);
typeint!(U7, 1);
typeint!(U8, 1);
// /// A type representing the number 1.
// pub struct U1 {}
// impl Unsigned for U1 {
// const N: usize = 1;
// }
/// A type that specifies a separator str.
pub trait Separator {
@@ -65,12 +100,19 @@ impl Separator for SpaceSeparator {
const SEPARATOR: &'static str = " ";
}
// /// New approach.
// pub trait HexStrTrait {
// const BYTES_PER_BLOCK: usize;
// const SEPARATOR: &'static str;
// fn bytes(&self) -> &[u8];
// }
/// Zero-sized wrapper newtype, allowing grouping bytes in blocks of N hexadecimals
/// during formatting.
///
/// Use the method with the same name to construct this from your byte array or slice,
/// or preferrably the `hex_str!` or `hexstr!` macro.
pub struct HexStr<'a, T: ?Sized, S=SpaceSeparator, BytesPerBlock=consts::U1>
pub struct HexStr<'a, T: ?Sized, S=SpaceSeparator, BytesPerBlock=U1>
where
S: Separator,
BytesPerBlock: Unsigned,
@@ -81,34 +123,21 @@ where
_block_size: PhantomData<BytesPerBlock>,
}
/// Sorry little replacement for the missing int to Unsigned type map in `typenum`.
// this doesn't really help with the below, as it doesn't match on passed $n:literal values
// hoping for: https://github.com/paholg/typenum/pull/136
#[macro_export]
#[doc(hidden)]
macro_rules! typeint {
(1) => { $crate::hex::consts::U1 };
(2) => { $crate::hex::consts::U2 };
(3) => { $crate::hex::consts::U3 };
(4) => { $crate::hex::consts::U4 };
(5) => { $crate::hex::consts::U5 };
(6) => { $crate::hex::consts::U6 };
(7) => { $crate::hex::consts::U7 };
(8) => { $crate::hex::consts::U8 };
(9) => { $crate::hex::consts::U9 };
(10) => { $crate::hex::consts::U10 };
(16) => { $crate::hex::consts::U16 };
(20) => { $crate::hex::consts::U20 };
(32) => { $crate::hex::consts::U32 };
(64) => { $crate::hex::consts::U64 };
}
// /// Sorry little replacement for the missing int to Unsigned type map in `typenum`.
// #[macro_export]
// #[doc(hidden)]
// macro_rules! typeint {
// ($n:expr) => {
// struct Number {};
// impl $crate::hex::Unsigned for Number {
// const N: usize = $n;
// }
// }
// }
#[macro_export]
/// Compactly format byte arrays and slices as hexadecimals.
///
/// Exposes the `hex_str` function as macro, for ease of practical use via the
/// latter's "namespace-piercing" capabilities.
///
/// The second parameter refers to the number of bytes in a block (separated by spaces).
///
/// ```
@@ -116,44 +145,26 @@ macro_rules! typeint {
/// let four_bytes = &[7u8, 0xA1, 255, 0xC7];
/// assert_eq!(format!("{:x}", hex_str!(four_bytes)), "07 a1 ff c7");
/// assert_eq!(format!("{}", hex_str!(four_bytes, 2)), "07A1 FFC7");
/// assert_eq!(format!("{}", hex_str!(four_bytes, 2, "|")), "07A1|FFC7");
/// assert_eq!(format!("{}", hex_str!(four_bytes, 2, sep: "|")), "07A1|FFC7");
/// assert_eq!(format!("{}", hex_str!(four_bytes, 3)), "07A1FF C7");
/// ```
macro_rules! hex_str {
($array:expr) => { $crate::hex::hex_str($array) };
($array:expr, 1) => { $crate::hex::hex_str_1($array) };
// ($array:expr, 2) => { $crate::hex::hex_str_2($array) };
($array:expr, 2) => { $crate::hex_str!($array, 2, " ") };
($array:expr, 3) => { $crate::hex::hex_str_3($array) };
($array:expr, 4) => { $crate::hex::hex_str_4($array) };
($array:expr, 5) => { $crate::hex::hex_str_5($array) };
($array:expr, 8) => { $crate::hex::hex_str_8($array) };
($array:expr, 16) => { $crate::hex::hex_str_16($array) };
($array:expr, 20) => { $crate::hex::hex_str_20($array) };
($array:expr, 32) => { $crate::hex::hex_str_32($array) };
($array:expr, 64) => { $crate::hex::hex_str_64($array) };
($array:expr, 2, $separator:expr) => {{
($array:expr) => { $crate::hex_str!($array, 1, sep: " ") };
($array:expr, sep: $separator:expr) => { $crate::hex_str!($array, 1, sep: $separator) };
($array:expr, $n:tt) => { $crate::hex_str!($array, $n, sep: " ") };
($array:expr, $n:tt, sep: $separator:expr) => {{
struct Separator {}
impl $crate::hex::Separator for Separator {
const SEPARATOR: &'static str = $separator;
}
$crate::hex::HexStr::<_, Separator, $crate::typeint!(2)>($array)
$crate::typeint!(Number, $n);
$crate::hex::HexStr::<_, Separator, Number>($array)
}};
// ($array:expr, $n:literal, $separator:expr) => {{
// struct Separator {}
// impl $crate::hex::Separator for Separator {
// const SEPARATOR: &'static str = $separator;
// }
// $crate::hex::HexStr::<_, Separator, $crate::typeint!($n)>($array)
// }};
}
#[macro_export]
/// More compactly format byte arrays and slices as hexadecimals.
///
/// Exposes the `hexstr` function (no spaces) as macro, for ease of practical use via the
/// latter's "namespace-piercing" capabilities.
///
/// ```
/// use delog::hexstr;
/// let four_bytes = &[7u8, 0xA1, 255, 0xC7];
@@ -161,115 +172,38 @@ macro_rules! hex_str {
/// assert_eq!(format!("{:x}", hexstr!(four_bytes)), "07a1ffc7");
/// ```
macro_rules! hexstr {
($array:expr) => { $crate::hex::hexstr($array) };
($array:expr) => {
$crate::hex_str!($array, sep: "")
}
}
#[allow(non_snake_case)]
/// dive into `typenum` and discover your inner traitist
/// dive into types and discover your inner traitist
///
/// The first parameter denotes the separator, the second `typenum` parameter
/// denotes the block size in bytes, e.g. `consts::U7` means blocks of 7 bytes (or 56 bits).
/// The first parameter denotes the separator, the second `Unsigned` parameter
/// denotes the block size in bytes, e.g. `typeint!(U7, 7)` creates a type `U7`
/// which means blocks of 7 bytes (or 56 bits).
///
/// In most cases, using one of the macros will suffice and is preferrable.
///
/// ```
/// use delog::hex::{HexStr, Separator, consts};
/// use delog::hex::{HexStr, Separator, Unsigned};
/// struct Pipe {}
/// impl Separator for Pipe {
/// const SEPARATOR: &'static str = "|";
/// }
/// struct U3 {}
/// impl Unsigned for U3 {
/// const N: usize = 3;
/// }
/// let four_bytes = &[7u8, 0xA1, 255, 0xC7];
/// let hex_str = HexStr::<_, Pipe, consts::U3>(four_bytes);
/// let hex_str = HexStr::<_, Pipe, U3>(four_bytes);
/// assert_eq!(format!("{}", hex_str), "07A1FF|C7");
/// ```
pub fn HexStr<T: ?Sized, S: Separator, B: Unsigned>(value: &T) -> HexStr<T, S, B> {
HexStr { value, _separator: PhantomData, _block_size: PhantomData }
}
/// blocks of 1 byte / 8 bits in hex, no space in between (e.g., `4A121387`)
///
/// For ease of use, prefer the `hexstr!(value)` macro.
pub fn hexstr<T: ?Sized>(value: &T) -> HexStr<T, NullSeparator, consts::U1> {
HexStr(value)
}
/// synonym for `hex_str_1`, like ISO 7816 if enclosed in single quotes (`'8A 4F 12 AA'`).
///
/// For ease of use, prefer the `hex_str!(value)` macro.
pub fn hex_str<T: ?Sized>(value: &T) -> HexStr<T> {
HexStr(value)
}
/// blocks of 1 byte / 8 bits in hex, space in between (e.g., `4A 12 13 87`)
///
/// For ease of use, prefer the `hex_str!(value)` macro.
pub fn hex_str_1<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U1> {
HexStr(value)
}
/// blocks of 2 bytes / 16 bits in hex, space in between (e.g., `4A12 1387`)
///
/// For ease of use, prefer the `hex_str!(value, 2)` macro.
pub fn hex_str_2<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U2> {
HexStr(value)
}
/// blocks of 3 bytes / 24 bits in hex, space in between (e.g., `4A1213 871234 ABCD`)
///
/// For ease of use, prefer the `hex_str!(value, 3)` macro.
pub fn hex_str_3<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U3> {
HexStr(value)
}
/// blocks of 4 bytes / 32 bits in hex, space in between (e.g., `4A121387 1234ABCD`)
///
/// For ease of use, prefer the `hex_str!(value, 4)` macro.
pub fn hex_str_4<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, typeint!(4)> {
HexStr(value)
}
/// blocks of 5 bytes / 40 bits in hex, space in between (e.g., `4A12138712 34ABCD`)
///
/// For ease of use, prefer the `hex_str!(value, 5)` macro.
pub fn hex_str_5<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U5> {
HexStr(value)
}
/// blocks of 8 bytes / 64 bits in hex, space in between
///
/// For ease of use, prefer the `hex_str!(value, 8)` macro.
pub fn hex_str_8<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U8> {
HexStr(value)
}
/// blocks of 16 bytes / 128 bits in hex, space in between
///
/// For ease of use, prefer the `hex_str!(value, 16)` macro.
pub fn hex_str_16<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U16> {
HexStr(value)
}
/// blocks of 20 bytes / 160 bits in hex, space in between
///
/// For ease of use, prefer the `hex_str!(value, 20)` macro.
pub fn hex_str_20<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U20> {
HexStr(value)
}
/// blocks of 32 bytes / 256 bits in hex, space in between
///
/// For ease of use, prefer the `hex_str!(value, 32)` macro.
pub fn hex_str_32<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U32> {
HexStr(value)
}
/// blocks of 64 bytes / 512 bits in hex, space in between
///
/// For ease of use, prefer the `hex_str!(value, 64)` macro.
pub fn hex_str_64<T: ?Sized>(value: &T) -> HexStr<T, SpaceSeparator, consts::U64> {
HexStr(value)
}
impl<T: ?Sized, S, U> fmt::Debug for HexStr<'_, T, S, U>
where
T: AsRef<[u8]>,
@@ -303,19 +237,55 @@ macro_rules! implement {
U: Unsigned,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let mut first = true;
for entry in self.value.as_ref().chunks(U::USIZE) {
if !first {
f.write_str(S::SEPARATOR)?;
} else {
first = false;
}
for byte in entry.iter() {
write!(f, $padded_formatter, byte)?;
// fmt::$Trait::fmt(byte, f)?;
use core::fmt::{self, Alignment::*};
let max_bytes = f.width().unwrap_or(usize::MAX);
let bytes = self.value.as_ref();
#[inline]
fn nontruncated_fmt(
bytes: &[u8], f: &mut fmt::Formatter<'_>,
chunk_size: usize, separator: &str,
) -> Result<(), fmt::Error> {
let mut first = true;
for entry in bytes.chunks(chunk_size) {
if first {
first = false;
} else {
f.write_str(separator)?;
}
for byte in entry.iter() {
write!(f, $padded_formatter, byte)?;
}
}
Ok(())
}
// const ELLIPSIS: &str = "…";
const ELLIPSIS: &str = "..";
let chunk_size = U::N;
let separator = S::SEPARATOR;
if bytes.len() <= max_bytes {
nontruncated_fmt(bytes, f, chunk_size, separator)
} else {
let align = f.align().unwrap_or(Center);
let (left, right) = match align {
Left => (max_bytes, 0),
Center => (max_bytes - max_bytes/2, max_bytes/2),
Right => (0, max_bytes),
};
nontruncated_fmt(&bytes[..left], f, chunk_size, separator)?;
// if left > 0 {
// f.write_str(separator)?;
// }
f.write_str(ELLIPSIS)?;
// if right > 0 {
// f.write_str(separator)?;
// }
nontruncated_fmt(&bytes[bytes.len()-right..], f, chunk_size, separator)?;
Ok(())
}
Ok(())
}
}
}
@@ -331,21 +301,22 @@ mod test {
#[test]
fn test_hex_str() {
let buf = [1u8, 2, 3, 0xA1, 0xB7, 0xFF, 0x3];
insta::assert_debug_snapshot!(format_args!("'{:02X}'", hex_str_1(&buf)));
insta::assert_debug_snapshot!(format_args!("'{:02X}'", hex_str_2(&buf)));
insta::assert_debug_snapshot!(format_args!("'{:02x}'", hex_str_2(&buf)));
insta::assert_debug_snapshot!(format_args!("'{:02X}'", hex_str_4(&buf)));
insta::assert_debug_snapshot!(format_args!("'{:02X}'", hex_str_4(&buf[..])));
insta::assert_debug_snapshot!(format_args!("'{:02X}'", hex_str_4(&buf)));
insta::assert_debug_snapshot!(format_args!("'{:X}'", hex_str_4(&buf)));
insta::assert_debug_snapshot!(format_args!("'{}'", hex_str!(&buf)));
insta::assert_debug_snapshot!(format_args!("'{}'", hex_str!(&buf, 2)));
insta::assert_debug_snapshot!(format_args!("'{:x}'", hex_str!(&buf, 2)));
insta::assert_debug_snapshot!(format_args!("'{}'", hex_str!(&buf, 4)));
insta::assert_debug_snapshot!(format_args!("'{}'", hex_str!(&buf[..], 4)));
insta::assert_debug_snapshot!(format_args!("'{}'", hex_str!(&buf, 4)));
insta::assert_debug_snapshot!(format_args!("'{}'", hex_str!(&buf, 4)));
}
#[test]
fn test_custom_hex_str() {
let buf = [1u8, 2, 3, 0xA1, 0xB7, 0xFF, 0x3];
typeint!(U3, 3);
insta::assert_debug_snapshot!(format_args!(
"'{:02X}'",
HexStr::<_, SpaceSeparator, consts::U3>(&buf),
"'{:X}'",
HexStr::<_, SpaceSeparator, U3>(&buf),
));
}

Some files were not shown because too many files have changed in this diff Show More