diff --git a/.github/workflows/dusk_ci.yml b/.github/workflows/dusk_ci.yml index d489fd0..2ecd982 100644 --- a/.github/workflows/dusk_ci.yml +++ b/.github/workflows/dusk_ci.yml @@ -7,26 +7,8 @@ on: name: Continuous integration jobs: - code-quality: - name: Code quality + ci: + name: CI uses: dusk-network/.github/.github/workflows/run-make.yml@main with: - make_target: cq - - documentation: - name: Build documentation - uses: dusk-network/.github/.github/workflows/run-make.yml@main - with: - make_target: doc - - test: - name: Run tests - uses: dusk-network/.github/.github/workflows/run-make.yml@main - with: - make_target: test - - no-std: - name: Run no-std tests - uses: dusk-network/.github/.github/workflows/run-make.yml@main - with: - make_target: no-std + make_target: ci diff --git a/Makefile b/Makefile index b5941f4..e8ca9bd 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,8 @@ cq: ## Run code quality checks (formatting + clippy) @$(MAKE) fmt CHECK=1 @$(MAKE) clippy +ci: cq test no-std doc ## Run continuous integration checks + check: ## Type-check @cargo check --all-features @@ -31,4 +33,4 @@ doc: ## Generate docs clean: ## Clean build artifacts @cargo clean -.PHONY: help fmt clippy cq check test no-std doc clean +.PHONY: help fmt clippy cq ci check test no-std doc clean diff --git a/derive-hex/CHANGELOG.md b/derive-hex/CHANGELOG.md index 7579eaa..bc27691 100644 --- a/derive-hex/CHANGELOG.md +++ b/derive-hex/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Simplify generated formatting and remove the unused `proc-macro2` dependency + [#55] - Update Syn to 3 [#53] - Raise the MSRV to Rust 1.96.1 [#51] @@ -44,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#45]: https://github.com/dusk-network/dusk-bytes/issues/45 [#51]: https://github.com/dusk-network/dusk-bytes/issues/51 [#53]: https://github.com/dusk-network/dusk-bytes/issues/53 +[#55]: https://github.com/dusk-network/dusk-bytes/issues/55 [unreleased]: https://github.com/dusk-network/dusk-bytes/compare/derive-hex-0.1.2...HEAD [0.1.2]: https://github.com/dusk-network/dusk-bytes/releases/tag/derive-hex-0.1.2 [0.1.1]: https://github.com/dusk-network/dusk-bytes/releases/tag/derive-hex-0.1.1 diff --git a/derive-hex/Cargo.toml b/derive-hex/Cargo.toml index d54dde0..8aff4f3 100644 --- a/derive-hex/Cargo.toml +++ b/derive-hex/Cargo.toml @@ -17,6 +17,5 @@ license = "MPL-2.0" proc-macro = true [dependencies] -proc-macro2 = "1.0" quote = "1.0" syn = "3.0" diff --git a/derive-hex/src/lib.rs b/derive-hex/src/lib.rs index 485ee51..8ec99e0 100644 --- a/derive-hex/src/lib.rs +++ b/derive-hex/src/lib.rs @@ -17,14 +17,12 @@ pub fn derive_hex(item: TokenStream) -> TokenStream { (quote! { impl core::fmt::LowerHex for #ident { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let bytes = self.to_bytes(); - if f.alternate() { write!(f, "0x")? } - for byte in &bytes[..] { - write!(f, "{:02x}", &byte)? + for byte in self.to_bytes() { + write!(f, "{byte:02x}")? } Ok(()) @@ -33,14 +31,12 @@ pub fn derive_hex(item: TokenStream) -> TokenStream { impl core::fmt::UpperHex for #ident { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let bytes = self.to_bytes(); - if f.alternate() { write!(f, "0x")? } - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? + for byte in self.to_bytes() { + write!(f, "{byte:02X}")? } Ok(()) @@ -59,22 +55,13 @@ pub fn derive_hex_debug(item: TokenStream) -> TokenStream { let dbg: TokenStream = (quote! { impl core::fmt::Debug for #ident { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - // Once we format an object using the debug notation (e.g. `{:x?}`) - // there is absolutely NO WAY to detect the flag for the lowerhex - // or upperhex, and therefore forwarding to the relevant formatter. - // Two methods for this purpose exists, but they're not exposed - // because they didn't agree on a name yet, see: + // `Formatter` does not publicly expose the debug-hex case. Bit 5 is + // `FlagV1::DebugUpperHex` in `core`: // - // - // Therefore the only way is using the deprecated method `flags`, - // implementing the same logic of the forementioned methods. - - // We also do not have access to the `FlagV1` enum since it's - // private. - let FlagV1_DebugUpperHex = 5_u32; + const DEBUG_UPPER_HEX: u32 = 1 << 5; #[allow(deprecated)] - if f.flags() & (1 << FlagV1_DebugUpperHex) !=0 { + if f.flags() & DEBUG_UPPER_HEX != 0 { core::fmt::UpperHex::fmt(self, f) } else { // LowerHex is always the default for debug core::fmt::LowerHex::fmt(self, f) diff --git a/derive-hex/tests/hex_test.rs b/derive-hex/tests/hex_test.rs index fab0408..414424e 100644 --- a/derive-hex/tests/hex_test.rs +++ b/derive-hex/tests/hex_test.rs @@ -20,66 +20,16 @@ impl Beef { } } -mod display { - use super::*; - - #[test] - fn lower_hex() { - let beef = Beef {}; - - assert_eq!(format!("{:x}", beef), "beef"); - } - - #[test] - fn lower_hex_alt() { - let beef = Beef {}; - - assert_eq!(format!("{:#x}", beef), "0xbeef"); - } - - #[test] - fn upper_hex() { - let beef = Beef {}; - - assert_eq!(format!("{:X}", beef), "BEEF"); - } - - #[test] - fn upper_hex_alt() { - let beef = Beef {}; - - assert_eq!(format!("{:#X}", beef), "0xBEEF"); - } -} - -mod debug { - use super::*; - - #[test] - fn lower_hex() { - let beef = Beef {}; - - assert_eq!(format!("{:x?}", beef), "beef"); - } - - #[test] - fn lower_hex_alt() { - let beef = Beef {}; - - assert_eq!(format!("{:#x?}", beef), "0xbeef"); - } - - #[test] - fn upper_hex() { - let beef = Beef {}; - - assert_eq!(format!("{:X?}", beef), "BEEF"); - } - - #[test] - fn upper_hex_alt() { - let beef = Beef {}; - - assert_eq!(format!("{:#X?}", beef), "0xBEEF"); - } +#[test] +fn formatting() { + let beef = Beef {}; + + assert_eq!(format!("{:x}", beef), "beef"); + assert_eq!(format!("{:#x}", beef), "0xbeef"); + assert_eq!(format!("{:X}", beef), "BEEF"); + assert_eq!(format!("{:#X}", beef), "0xBEEF"); + assert_eq!(format!("{:x?}", beef), "beef"); + assert_eq!(format!("{:#x?}", beef), "0xbeef"); + assert_eq!(format!("{:X?}", beef), "BEEF"); + assert_eq!(format!("{:#X?}", beef), "0xBEEF"); } diff --git a/dusk-bytes/tests/parse_test.rs b/dusk-bytes/tests/parse_test.rs index 6612586..6be8d06 100644 --- a/dusk-bytes/tests/parse_test.rs +++ b/dusk-bytes/tests/parse_test.rs @@ -6,7 +6,7 @@ mod common; use common::{Beef, BeefError}; -use dusk_bytes::{ParseHexStr, Serializable}; +use dusk_bytes::{Error, ParseHexStr, Serializable}; #[test] fn parse_correct_chars() -> Result<(), BeefError> { @@ -39,6 +39,26 @@ fn parse_wrong_chars() { ) } +#[test] +fn parse_reports_length_and_low_nibble_errors() { + assert_eq!( + u16::from_hex_str("bee"), + Err(Error::BadLength { + found: 3, + expected: 4, + }) + ); + assert_eq!( + u8::from_hex_str("0g"), + Err(Error::InvalidChar { ch: 'g', index: 1 }) + ); +} + +#[test] +fn parse_accepts_uppercase_hex() { + assert_eq!(u16::from_hex_str("BEEF"), Ok(0xefbe)); +} + mod constant { use dusk_bytes::hex; @@ -61,6 +81,18 @@ mod constant { assert_eq!(EMPTY_BIG, [0x0, 0x0]); } + #[test] + fn runtime_matches_const_fixtures() { + let input = std::hint::black_box(*b"beef"); + let exact: [u8; 2] = hex(&input); + let truncated: [u8; 1] = hex(&input); + let padded: [u8; 3] = hex(&input); + + assert_eq!(exact, BEEF); + assert_eq!(truncated, BEEF_SMALL); + assert_eq!(padded, BEEF_BIG); + } + #[test] #[should_panic(expected = "hex(): input length must be even")] fn reject_odd_length() { diff --git a/dusk-bytes/tests/serialize_test.rs b/dusk-bytes/tests/serialize_test.rs index d3053bb..d51e445 100644 --- a/dusk-bytes/tests/serialize_test.rs +++ b/dusk-bytes/tests/serialize_test.rs @@ -5,8 +5,6 @@ // Copyright (c) DUSK NETWORK. All rights reserved. mod common; -use std::fmt::Debug; - use common::{Beef, BeefError}; use dusk_bytes::{DeserializableSlice, Error, Read, Serializable}; @@ -154,26 +152,6 @@ mod from_bytes { assert_eq!(bytes, [0x10], "Buffer is not consumed"); } - #[test] - fn primitive_types() -> Result<(), Error> { - assert_eq!(0x01_u8, u8::from_bytes(&[0x01])?); - assert_eq!(0x0102_u16, u16::from_bytes(&[0x02, 0x01])?); - assert_eq!(0x01020304_u32, u32::from_bytes(&[0x04, 0x03, 0x02, 0x01])?); - assert_eq!( - 0x0102030405060708_u64, - u64::from_bytes(&[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01])? - ); - assert_eq!( - 0x0102030405060708090a0b0c0d0e0f10_u128, - u128::from_bytes(&[ - 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, - 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 - ])? - ); - - Ok(()) - } - #[test] fn from_reader_fills_buffer_across_short_reads() -> Result<(), Error> { let mut reader = ChunkedReader::new(&[0x04, 0x03, 0x02, 0x01, 0xff], 1); @@ -269,153 +247,65 @@ mod from_bytes { #[test] fn primitive_types_buffer_too_small() { - assert!( - matches!( - u8::from_slice(&[]), - Err(Error::BadLength { - found: 0, - expected: 1 - }) - ), - "Not enough bytes to parse" - ); - - assert!( - matches!( - u16::from_slice(&[0x01]), - Err(Error::BadLength { - found: 1, - expected: 2 - }) - ), - "Not enough bytes to parse" - ); - - assert!( - matches!( - u32::from_slice(&[0x01, 0x02]), - Err(Error::BadLength { - found: 2, - expected: 4 - }) - ), - "Not enough bytes to parse" - ); - - assert!( - matches!( - u64::from_slice(&[]), - Err(Error::BadLength { - found: 0, - expected: 8 - }) - ), - "Not enough bytes to parse" - ); - - assert!( - matches!( - u128::from_slice(&[0x01, 0x02, 0x03]), - Err(Error::BadLength { - found: 3, - expected: 16 - }) - ), - "Not enough bytes to parse" - ); - - assert!( - matches!( - i8::from_slice(&[]), - Err(Error::BadLength { - found: 0, - expected: 1 - }) - ), - "Not enough bytes to parse i8" - ); - - assert!( - matches!( - i16::from_slice(&[0xff]), - Err(Error::BadLength { - found: 1, - expected: 2 - }) - ), - "Not enough bytes to parse i16" - ); - - assert!( - matches!( - i32::from_slice(&[0xff, 0xe4]), - Err(Error::BadLength { - found: 2, - expected: 4 - }) - ), - "Not enough bytes to parse i32" - ); - - assert!( - matches!( - i64::from_slice(&[0xff, 0xf4]), - Err(Error::BadLength { - found: 2, - expected: 8 - }) - ), - "Not enough bytes to parse i64" + assert_eq!( + u8::from_slice(&[]), + Err(Error::BadLength { + found: 0, + expected: 1, + }) ); - - assert!( - matches!( - i128::from_slice(&[0xff, 0xe4, 0xef]), - Err(Error::BadLength { - found: 3, - expected: 16 - }) - ), - "Not enough bytes to parse i128" + assert_eq!( + i128::from_slice(&[0xff, 0xe4, 0xef]), + Err(Error::BadLength { + found: 3, + expected: 16, + }) ); } } -mod to_bytes { +mod primitive_types { use super::*; - #[test] - fn it_works() { - let beef = Beef {}; + macro_rules! assert_serialization { + ($ty:ty, $value:expr, $bytes:expr) => {{ + let value: $ty = $value; + let bytes = $bytes; - assert_eq!(beef.to_bytes(), [0xbe, 0xef]); + assert_eq!(value.to_bytes(), bytes); + assert_eq!(<$ty>::from_bytes(&bytes), Ok(value)); + }}; } #[test] - fn primitive_types() { - assert_eq!(0x01_u8.to_bytes(), [0x01]); - assert_eq!(0x0102_u16.to_bytes(), [0x02, 0x01]); - assert_eq!(0x01020304_u32.to_bytes(), [0x04, 0x03, 0x02, 0x01]); - assert_eq!( - 0x0102030405060708_u64.to_bytes(), + fn golden_serialization() { + assert_serialization!(u8, 0x01, [0x01]); + assert_serialization!(u16, 0x0102, [0x02, 0x01]); + assert_serialization!(u32, 0x01020304, [0x04, 0x03, 0x02, 0x01]); + assert_serialization!( + u64, + 0x0102030405060708, [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01] ); - assert_eq!( - 0x0102030405060708090a0b0c0d0e0f10_u128.to_bytes(), + assert_serialization!( + u128, + 0x0102030405060708090a0b0c0d0e0f10, [ 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, - 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, ] ); - assert_eq!((-1_i8).to_bytes(), [0xff]); - assert_eq!(0x0102_i16.to_bytes(), [0x02, 0x01]); - assert_eq!((-12345678_i32).to_bytes(), [0xb2, 0x9e, 0x43, 0xff]); - assert_eq!( - 0x0102030405060708_i64.to_bytes(), + assert_serialization!(i8, -1, [0xff]); + assert_serialization!(i16, 0x0102, [0x02, 0x01]); + assert_serialization!(i32, -12345678, [0xb2, 0x9e, 0x43, 0xff]); + assert_serialization!( + i64, + 0x0102030405060708, [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01] ); - assert_eq!( - (-1234567890123456789012345678901234_i128).to_bytes(), + assert_serialization!( + i128, + -1234567890123456789012345678901234, [ 0x0e, 0x50, 0x69, 0x81, 0x2f, 0xa3, 0x7d, 0x21, 0xcd, 0x68, 0x00, 0x90, 0x21, 0xc3, 0xff, 0xff, @@ -424,6 +314,17 @@ mod to_bytes { } } +mod to_bytes { + use super::*; + + #[test] + fn it_works() { + let beef = Beef {}; + + assert_eq!(beef.to_bytes(), [0xbe, 0xef]); + } +} + mod functions { use super::*; @@ -450,31 +351,6 @@ mod functions { assert_eq!(info, "Size: 2, Bytes: [190, 239]"); } - - fn test_primitive(original: T) - where - T: Serializable + Eq + Debug, - >::Error: Debug, - { - let serialized = >::to_bytes(&original); - let deserialized = - >::from_bytes(&serialized).unwrap(); - assert_eq!(original, deserialized); - } - - #[test] - fn test_serializable_deserialize_primitives() { - test_primitive::(0x01); - test_primitive::(0x0102); - test_primitive::(0x01020304); - test_primitive::(0x0102030405060708); - test_primitive::(0x0102030405060708090a0b0c0d0e0f10); - test_primitive::(-1); - test_primitive::(-1234); - test_primitive::(-12345678); - test_primitive::(-1234567890123456); - test_primitive::(-1234567890123456789012345678901234); - } } mod buffers {