thegraph_core/
indexer_id.rs

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