thegraph_core/allocation_id.rs
1use alloy::primitives::Address;
2
3/// A unique identifier for an allocation: the allocation's Ethereum address.
4///
5/// This is a "new-type" wrapper around [`Address`] to provide type safety.
6///
7/// ## Formatting
8///
9/// The `AllocationId` type implements the following formatting traits:
10///
11/// - Use [`std::fmt::Display`] for formatting the `AllocationId` as an [EIP-55] checksum string.
12/// - Use [`std::fmt::LowerHex`] (or [`std::fmt::UpperHex`]) for formatting the `AllocationId` as
13/// a hexadecimal string.
14///
15/// See the [`Display`], [`LowerHex`], and [`UpperHex`] trait implementations for usage examples.
16///
17/// ## Generating test data
18///
19/// The `AllocationId` type implements the [`fake`] crate's [`fake::Dummy`] trait, allowing you to
20/// generate random `AllocationId` values for testing.
21///
22/// Note that the `fake` feature must be enabled to use this functionality.
23///
24/// See the [`Dummy`] trait impl for usage examples.
25///
26/// [EIP-55]: https://eips.ethereum.org/EIPS/eip-55
27/// [`Display`]: #impl-Display-for-AllocationId
28/// [`LowerHex`]: #impl-LowerHex-for-AllocationId
29/// [`UpperHex`]: #impl-UpperHex-for-AllocationId
30/// [`Dummy`]: #impl-Dummy<Faker>-for-AllocationId
31#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct AllocationId(Address);
33
34impl AllocationId {
35 /// Create a new [`AllocationId`].
36 pub const fn new(address: Address) -> Self {
37 AllocationId(address)
38 }
39
40 /// Return the internal representation.
41 pub fn into_inner(self) -> Address {
42 self.0
43 }
44}
45
46impl std::fmt::Display for AllocationId {
47 /// Formats the `AllocationId` using its [EIP-55](https://eips.ethereum.org/EIPS/eip-55)
48 /// checksum representation.
49 ///
50 /// See [`LowerHex`] (and [`UpperHex`]) for formatting the `AllocationId` as a hexadecimal
51 /// string.
52 ///
53 /// [`LowerHex`]: struct.AllocationId.html#impl-LowerHex-for-AllocationId
54 /// [`UpperHex`]: struct.AllocationId.html#impl-UpperHex-for-AllocationId
55 ///
56 /// ```rust
57 /// # use thegraph_core::{allocation_id, AllocationId};
58 /// const ID: AllocationId = allocation_id!("0002c67268fb8c8917f36f865a0cbdf5292fa68d");
59 ///
60 /// // Note the uppercase and lowercase hex characters in the checksum
61 /// assert_eq!(format!("{}", ID), "0x0002c67268FB8C8917F36F865a0CbdF5292FA68d");
62 /// ```
63 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
64 std::fmt::Display::fmt(&self.0, f)
65 }
66}
67
68impl std::fmt::Debug for AllocationId {
69 /// Formats the `AllocationId` using its raw lower-case hexadecimal representation.
70 ///
71 /// It is advised to use the [`LowerHex`] (and [`UpperHex`]) format trait implementation over
72 /// the [`Debug`](std::fmt::Debug) implementation to format the `AllocationId` as a lower-case
73 /// hexadecimal string.
74 ///
75 /// This implementation matches `alloy_primitives::Address`'s `Debug` implementation.
76 ///
77 /// [`LowerHex`]: struct.AllocationId.html#impl-LowerHex-for-AllocationId
78 /// [`UpperHex`]: struct.AllocationId.html#impl-UpperHex-for-AllocationId
79 ///
80 /// ```rust
81 /// # use thegraph_core::{allocation_id, AllocationId};
82 /// const ID: AllocationId = allocation_id!("0002c67268fb8c8917f36f865a0cbdf5292fa68d");
83 ///
84 /// assert_eq!(format!("{:?}", ID), "0x0002c67268fb8c8917f36f865a0cbdf5292fa68d");
85 /// ```
86 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
87 std::fmt::Debug::fmt(&self.0, f)
88 }
89}
90
91impl std::fmt::LowerHex for AllocationId {
92 /// Lowercase hex representation of the `AllocationId`.
93 ///
94 /// Note that the alternate flag, `#`, adds a `0x` in front of the output.
95 ///
96 /// ```rust
97 /// # use thegraph_core::{allocation_id, AllocationId};
98 /// const ID: AllocationId = allocation_id!("0002c67268fb8c8917f36f865a0cbdf5292fa68d");
99 ///
100 /// // Lower hex
101 /// assert_eq!(format!("{:x}", ID), "0002c67268fb8c8917f36f865a0cbdf5292fa68d");
102 ///
103 /// // Lower hex with alternate flag
104 /// assert_eq!(format!("{:#x}", ID), "0x0002c67268fb8c8917f36f865a0cbdf5292fa68d");
105 /// ```
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 std::fmt::LowerHex::fmt(&self.0, f)
108 }
109}
110
111impl std::fmt::UpperHex for AllocationId {
112 /// Uppercase hex representation of the `AllocationId`.
113 ///
114 /// Note that the alternate flag, `#`, adds a `0x` in front of the output.
115 ///
116 /// ```rust
117 /// # use thegraph_core::{allocation_id, AllocationId};
118 /// const ID: AllocationId = allocation_id!("0002c67268fb8c8917f36f865a0cbdf5292fa68d");
119 ///
120 /// // Upper hex
121 /// assert_eq!(format!("{:X}", ID), "0002C67268FB8C8917F36F865A0CBDF5292FA68D");
122 ///
123 /// // Upper hex with alternate flag
124 /// assert_eq!(format!("{:#X}", ID), "0x0002C67268FB8C8917F36F865A0CBDF5292FA68D");
125 /// ```
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 std::fmt::UpperHex::fmt(&self.0, f)
128 }
129}
130
131impl From<Address> for AllocationId {
132 fn from(address: Address) -> Self {
133 AllocationId(address)
134 }
135}
136
137impl std::str::FromStr for AllocationId {
138 type Err = <Address as std::str::FromStr>::Err;
139
140 fn from_str(s: &str) -> Result<Self, Self::Err> {
141 let address = std::str::FromStr::from_str(s)?;
142 Ok(AllocationId(address))
143 }
144}
145
146impl PartialEq<Address> for AllocationId {
147 fn eq(&self, other: &Address) -> bool {
148 self.0.eq(other)
149 }
150}
151
152impl AsRef<Address> for AllocationId {
153 fn as_ref(&self) -> &Address {
154 &self.0
155 }
156}
157
158impl std::ops::Deref for AllocationId {
159 type Target = Address;
160
161 fn deref(&self) -> &Self::Target {
162 &self.0
163 }
164}
165
166#[cfg(feature = "serde")]
167impl<'de> serde::Deserialize<'de> for AllocationId {
168 fn deserialize<D>(deserializer: D) -> Result<AllocationId, D::Error>
169 where
170 D: serde::Deserializer<'de>,
171 {
172 let address = Address::deserialize(deserializer)?;
173 Ok(AllocationId(address))
174 }
175}
176
177#[cfg(feature = "serde")]
178impl serde::Serialize for AllocationId {
179 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
180 where
181 S: serde::Serializer,
182 {
183 self.0.serialize(serializer)
184 }
185}
186
187#[cfg(feature = "fake")]
188/// To use the [`fake`] crate to generate random [`AllocationId`] values, **the `fake` feature must
189/// be enabled.**
190///
191/// ```rust
192/// # use thegraph_core::AllocationId;
193/// # use fake::Fake;
194/// let allocation_id = fake::Faker.fake::<AllocationId>();
195///
196/// println!("AllocationId: {:#x}", allocation_id);
197/// ```
198impl fake::Dummy<fake::Faker> for AllocationId {
199 fn dummy_with_rng<R: fake::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
200 use crate::fake_impl::alloy::Alloy;
201 Self(Address::dummy_with_rng(&Alloy, rng))
202 }
203}
204
205/// Converts a sequence of string literals containing hex-encoded data into a new [`AllocationId`]
206/// at compile time.
207///
208/// To create an `AllocationId` from a string literal (no `0x` prefix) at compile time:
209///
210/// ```rust
211/// use thegraph_core::{allocation_id, AllocationId};
212///
213/// const ALLOCATION_ID: AllocationId = allocation_id!("0002c67268fb8c8917f36f865a0cbdf5292fa68d");
214/// ```
215///
216/// If no argument is provided, the macro will create an `AllocationId` with the zero address:
217///
218/// ```rust
219/// use thegraph_core::{
220/// alloy::primitives::Address,
221/// allocation_id, AllocationId
222/// };
223///
224/// const ALLOCATION_ID: AllocationId = allocation_id!();
225///
226/// assert_eq!(ALLOCATION_ID, Address::ZERO);
227/// ```
228#[macro_export]
229#[doc(hidden)]
230macro_rules! __allocation_id {
231 () => {
232 $crate::AllocationId::new($crate::alloy::primitives::Address::ZERO)
233 };
234 ($value:tt) => {
235 $crate::AllocationId::new($crate::alloy::primitives::address!($value))
236 };
237}