iota_types/block/
macro.rs

1// Copyright 2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4/// TODO
5#[macro_export]
6macro_rules! impl_id {
7    ($vis:vis $name:ident, $length:literal, $doc:literal) => {
8        #[doc = $doc]
9        #[derive(
10            Clone,
11            Copy,
12            Eq,
13            Hash,
14            PartialEq,
15            Ord,
16            PartialOrd,
17            derive_more::From,
18            derive_more::AsRef,
19            packable::Packable,
20        )]
21        #[as_ref(forward)]
22        $vis struct $name([u8; $name::LENGTH]);
23
24        impl $name {
25            #[doc = concat!("The length of a [`", stringify!($ty),"`].")]
26            $vis const LENGTH: usize = $length;
27
28            #[doc = concat!("Creates a new [`", stringify!($ty),"`].")]
29            $vis fn new(bytes: [u8; $name::LENGTH]) -> Self {
30                Self::from(bytes)
31            }
32
33            #[doc = concat!("Creates a null [`", stringify!($ty),"`].")]
34            pub fn null() -> Self {
35                Self::from([0u8; $name::LENGTH])
36            }
37
38            #[doc = concat!("Checks if the [`", stringify!($ty),"`] is null.")]
39            pub fn is_null(&self) -> bool {
40                self.0.iter().all(|&b| b == 0)
41            }
42        }
43
44        impl core::str::FromStr for $name {
45            type Err = $crate::block::Error;
46
47            fn from_str(s: &str) -> Result<Self, Self::Err> {
48                Ok($name::from(prefix_hex::decode::<[u8; Self::LENGTH]>(s).map_err($crate::block::Error::Hex)?))
49            }
50        }
51
52        impl core::fmt::Display for $name {
53            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54                write!(f, "{}", prefix_hex::encode(self.0))
55            }
56        }
57
58        impl core::fmt::Debug for $name {
59            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60                write!(f, "{}({})", stringify!($name), self)
61            }
62        }
63
64        impl core::ops::Deref for $name {
65            type Target = [u8; $name::LENGTH];
66
67            fn deref(&self) -> &Self::Target {
68                &self.0
69            }
70        }
71    };
72}
73
74/// Helper macro to serialize types to string via serde.
75#[macro_export]
76#[cfg(feature = "serde")]
77macro_rules! string_serde_impl {
78    ($type:ty) => {
79        impl serde::Serialize for $type {
80            fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
81                use alloc::string::ToString;
82
83                s.serialize_str(&self.to_string())
84            }
85        }
86
87        impl<'de> serde::Deserialize<'de> for $type {
88            fn deserialize<D>(deserializer: D) -> Result<$type, D::Error>
89            where
90                D: serde::Deserializer<'de>,
91            {
92                struct StringVisitor;
93
94                impl<'de> serde::de::Visitor<'de> for StringVisitor {
95                    type Value = $type;
96
97                    fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98                        formatter.write_str("a string representing the value")
99                    }
100
101                    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
102                    where
103                        E: serde::de::Error,
104                    {
105                        let value = core::str::FromStr::from_str(v).map_err(serde::de::Error::custom)?;
106                        Ok(value)
107                    }
108                }
109
110                deserializer.deserialize_str(StringVisitor)
111            }
112        }
113    };
114}
115
116/// A convenience macro to work around the fact the `[bitflags]` crate does not yet support iterating over the
117/// individual flags. This macro essentially creates the `[bitflags]` and puts the individual flags into an associated
118/// constant `pub const ALL_FLAGS: &'static []`.
119#[macro_export]
120macro_rules! create_bitflags {
121    ($(#[$meta:meta])* $vis:vis $Name:ident, $TagType:ty, [$(($FlagName:ident, $TypeName:ident),)+]) => {
122        bitflags! {
123            $(#[$meta])*
124            $vis struct $Name: $TagType {
125                $(
126                    #[doc = concat!("Signals the presence of a [`", stringify!($TypeName), "`].")]
127                    const $FlagName = 1 << $TypeName::KIND;
128                )*
129            }
130        }
131
132        impl $Name {
133            #[allow(dead_code)]
134            /// Returns a slice of all possible base flags.
135            $vis const ALL_FLAGS: &'static [$Name] = &[$($Name::$FlagName),*];
136        }
137    };
138}