mirror of
https://github.com/trussed-dev/delog.git
synced 2026-06-20 04:16:34 -07:00
Revamp API
This commit is contained in:
@@ -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
@@ -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 = []
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
|
||||
@@ -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
@@ -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: "|"));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 = "../.."
|
||||
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ panic-semihosting = { version = "0.5.3", features = ["exit"] }
|
||||
|
||||
[dependencies.delog]
|
||||
path = ".."
|
||||
features = ["semihosting-example-flushers"]
|
||||
|
||||
[features]
|
||||
default = ["log-all"]
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user