derive_hex/lib.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use proc_macro::TokenStream;
8use quote::quote;
9
10#[proc_macro_derive(Hex)]
11pub fn derive_hex(item: TokenStream) -> TokenStream {
12 let input = syn::parse_macro_input!(item as syn::DeriveInput);
13 let ident = &input.ident;
14
15 (quote! {
16 impl core::fmt::LowerHex for #ident {
17 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
18 let bytes = self.to_bytes();
19
20 if f.alternate() {
21 write!(f, "0x")?
22 }
23
24 for byte in &bytes[..] {
25 write!(f, "{:02x}", &byte)?
26 }
27
28 Ok(())
29 }
30 }
31
32 impl core::fmt::UpperHex for #ident {
33 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34 let bytes = self.to_bytes();
35
36 if f.alternate() {
37 write!(f, "0x")?
38 }
39
40 for byte in &bytes[..] {
41 write!(f, "{:02X}", &byte)?
42 }
43
44 Ok(())
45 }
46 }
47 })
48 .into()
49}
50
51#[proc_macro_derive(HexDebug)]
52pub fn derive_hex_debug(item: TokenStream) -> TokenStream {
53 let mut hex: TokenStream = derive_hex(item.clone());
54 let input = syn::parse_macro_input!(item as syn::DeriveInput);
55 let ident = &input.ident;
56
57 let dbg: TokenStream = (quote! {
58 impl core::fmt::Debug for #ident {
59 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60 // Once we format an object using the debug notation (e.g. `{:x?}`)
61 // there is absolutely NO WAY to detect the flag for the lowerhex
62 // or upperhex, and therefore forwarding to the relevant formatter.
63 // Two methods for this purpose exists, but they're not exposed
64 // because they didn't agree on a name yet, see:
65 // <https://github.com/rust-lang/rust/blob/90442458ac46b1d5eed752c316da25450f67285b/library/core/src/fmt/mod.rs#L1817-L1825>
66 //
67 // Therefore the only way is using the deprecated method `flags`,
68 // implementing the same logic of the forementioned methods.
69
70 // We also do not have access to the `FlagV1` enum since it's
71 // private.
72 let FlagV1_DebugUpperHex = 5_u32;
73
74 #[allow(deprecated)]
75 if f.flags() & (1 << FlagV1_DebugUpperHex) !=0 {
76 core::fmt::UpperHex::fmt(self, f)
77 } else { // LowerHex is always the default for debug
78 core::fmt::LowerHex::fmt(self, f)
79 }
80 }
81 }})
82 .into();
83
84 hex.extend(dbg);
85 hex
86}