qubit_common/util/tuple/pair.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Pair
10//!
11//! A generic pair structure that holds two values of potentially different types.
12//!
13//! ## Examples
14//!
15//! ```
16//! use qubit_common::Pair;
17//!
18//! // Compare readability
19//! let tuple = ("Alice", 30);
20//! println!("Name: {}, Age: {}", tuple.0, tuple.1); // Less clear
21//!
22//! let pair = Pair::new("Alice", 30);
23//! println!("Name: {}, Age: {}", pair.first, pair.second); // More clear
24//!
25//! // Method chaining with Pair
26//! let result = Pair::new(5, "hello")
27//! .map_first(|x| x * 2)
28//! .map_second(|s| s.len());
29//! assert_eq!(result, Pair::new(10, 5));
30//!
31//! // Easy conversion between Pair and tuple
32//! let tuple = (1, 2);
33//! let pair: Pair<i32, i32> = tuple.into();
34//! let back_to_tuple: (i32, i32) = pair.into();
35//! ```
36//!
37//! # Author
38//!
39//! Haixing Hu
40
41use std::fmt;
42
43/// A generic pair structure that holds two values.
44///
45/// # Type Parameters
46///
47/// * `F` - The type of the first element
48/// * `S` - The type of the second element
49///
50/// # Pair vs. Tuple
51///
52/// While Rust's native tuples `(F, S)` can also hold two values, `Pair<F, S>`
53/// provides several advantages:
54///
55/// ## Similarities
56///
57/// - Both can hold two values of different types
58/// - Both support pattern matching and destructuring
59/// - Both can be converted to each other via `From`/`Into` traits
60///
61/// ## Differences
62///
63/// | Feature | `Pair<F, S>` | `(F, S)` |
64/// |---------|-------------|----------|
65/// | **Named fields** | ✓ Uses `.first` and `.second` | ✗ Uses `.0` and `.1` |
66/// | **Semantic clarity** | ✓ More readable and self-documenting | ✗ Less clear what each element represents |
67/// | **Method chaining** | ✓ Provides `map_first()`, `map_second()`, `swap()` | ✗ No built-in transformation methods |
68/// | **Mutable access** | ✓ Provides `first_mut()` and `second_mut()` | ✓ Direct field mutation |
69/// | **Type aliases** | ✓ Can create meaningful type aliases | ✓ Can create type aliases |
70/// | **Pattern matching** | ✓ `Pair { first, second }` | ✓ `(first, second)` |
71///
72/// ## When to Use `Pair`
73///
74/// Use `Pair<F, S>` when:
75/// - You want more readable code with named fields (`.first`, `.second` vs `.0`, `.1`)
76/// - You need transformation methods like `map_first()` or `swap()`
77/// - You're building a public API where clarity is important
78/// - You want to create semantic type aliases (e.g., `type Coordinate = Pair<f64, f64>`)
79///
80/// ## When to Use Tuples
81///
82/// Use native tuples `(F, S)` when:
83/// - You need a quick, lightweight data structure for internal use
84/// - You're returning multiple values from a function temporarily
85/// - You need to match Rust's standard library APIs that use tuples
86/// - Performance is critical (though the difference is negligible in practice)
87///
88/// # Examples
89///
90/// ```
91/// use qubit_common::Pair;
92///
93/// let pair = Pair::new("name", 42);
94/// assert_eq!(pair.first, "name");
95/// assert_eq!(pair.second, 42);
96///
97/// let pair = Pair { first: 1, second: 2.5 };
98/// assert_eq!(pair.first, 1);
99/// assert_eq!(pair.second, 2.5);
100/// ```
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
102pub struct Pair<F, S> {
103 /// The first element of the pair
104 pub first: F,
105 /// The second element of the pair
106 pub second: S,
107}
108
109impl<F, S> Pair<F, S> {
110 /// Creates a new `Pair` with the given values.
111 ///
112 /// # Arguments
113 ///
114 /// * `first` - The first element
115 /// * `second` - The second element
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// use qubit_common::Pair;
121 ///
122 /// let pair = Pair::new(1, "hello");
123 /// assert_eq!(pair.first, 1);
124 /// assert_eq!(pair.second, "hello");
125 /// ```
126 #[inline]
127 pub fn new(first: F, second: S) -> Self {
128 Pair { first, second }
129 }
130
131 /// Consumes the pair and returns a tuple of its elements.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// use qubit_common::Pair;
137 ///
138 /// let pair = Pair::new(1, "hello");
139 /// let (first, second) = pair.into_tuple();
140 /// assert_eq!(first, 1);
141 /// assert_eq!(second, "hello");
142 /// ```
143 #[inline]
144 pub fn into_tuple(self) -> (F, S) {
145 (self.first, self.second)
146 }
147
148 /// Returns a reference to the first element.
149 ///
150 /// # Examples
151 ///
152 /// ```
153 /// use qubit_common::Pair;
154 ///
155 /// let pair = Pair::new(1, 2);
156 /// assert_eq!(pair.first(), &1);
157 /// ```
158 #[inline]
159 pub fn first(&self) -> &F {
160 &self.first
161 }
162
163 /// Returns a reference to the second element.
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// use qubit_common::Pair;
169 ///
170 /// let pair = Pair::new(1, 2);
171 /// assert_eq!(pair.second(), &2);
172 /// ```
173 #[inline]
174 pub fn second(&self) -> &S {
175 &self.second
176 }
177
178 /// Returns a mutable reference to the first element.
179 ///
180 /// # Examples
181 ///
182 /// ```
183 /// use qubit_common::Pair;
184 ///
185 /// let mut pair = Pair::new(1, 2);
186 /// *pair.first_mut() = 10;
187 /// assert_eq!(pair.first, 10);
188 /// ```
189 #[inline]
190 pub fn first_mut(&mut self) -> &mut F {
191 &mut self.first
192 }
193
194 /// Returns a mutable reference to the second element.
195 ///
196 /// # Examples
197 ///
198 /// ```
199 /// use qubit_common::Pair;
200 ///
201 /// let mut pair = Pair::new(1, 2);
202 /// *pair.second_mut() = 20;
203 /// assert_eq!(pair.second, 20);
204 /// ```
205 #[inline]
206 pub fn second_mut(&mut self) -> &mut S {
207 &mut self.second
208 }
209
210 /// Maps the first element to a new value using the provided function.
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// use qubit_common::Pair;
216 ///
217 /// let pair = Pair::new(1, "hello");
218 /// let mapped = pair.map_first(|x| x * 2);
219 /// assert_eq!(mapped.first, 2);
220 /// assert_eq!(mapped.second, "hello");
221 /// ```
222 #[inline]
223 pub fn map_first<F2, Fn>(self, f: Fn) -> Pair<F2, S>
224 where
225 Fn: FnOnce(F) -> F2,
226 {
227 Pair {
228 first: f(self.first),
229 second: self.second,
230 }
231 }
232
233 /// Maps the second element to a new value using the provided function.
234 ///
235 /// # Examples
236 ///
237 /// ```
238 /// use qubit_common::Pair;
239 ///
240 /// let pair = Pair::new(1, "hello");
241 /// let mapped = pair.map_second(|s| s.len());
242 /// assert_eq!(mapped.first, 1);
243 /// assert_eq!(mapped.second, 5);
244 /// ```
245 #[inline]
246 pub fn map_second<S2, Fn>(self, f: Fn) -> Pair<F, S2>
247 where
248 Fn: FnOnce(S) -> S2,
249 {
250 Pair {
251 first: self.first,
252 second: f(self.second),
253 }
254 }
255
256 /// Swaps the elements of the pair.
257 ///
258 /// # Examples
259 ///
260 /// ```
261 /// use qubit_common::Pair;
262 ///
263 /// let pair = Pair::new(1, "hello");
264 /// let swapped = pair.swap();
265 /// assert_eq!(swapped.first, "hello");
266 /// assert_eq!(swapped.second, 1);
267 /// ```
268 #[inline]
269 pub fn swap(self) -> Pair<S, F> {
270 Pair {
271 first: self.second,
272 second: self.first,
273 }
274 }
275}
276
277impl<F, S> From<(F, S)> for Pair<F, S> {
278 /// Creates a `Pair` from a tuple.
279 ///
280 /// # Examples
281 ///
282 /// ```
283 /// use qubit_common::Pair;
284 ///
285 /// let pair: Pair<i32, &str> = (1, "hello").into();
286 /// assert_eq!(pair.first, 1);
287 /// assert_eq!(pair.second, "hello");
288 /// ```
289 #[inline]
290 fn from(tuple: (F, S)) -> Self {
291 Pair {
292 first: tuple.0,
293 second: tuple.1,
294 }
295 }
296}
297
298impl<F, S> From<Pair<F, S>> for (F, S) {
299 /// Converts a `Pair` into a tuple.
300 ///
301 /// # Examples
302 ///
303 /// ```
304 /// use qubit_common::Pair;
305 ///
306 /// let pair = Pair::new(1, "hello");
307 /// let tuple: (i32, &str) = pair.into();
308 /// assert_eq!(tuple, (1, "hello"));
309 /// ```
310 #[inline]
311 fn from(pair: Pair<F, S>) -> Self {
312 (pair.first, pair.second)
313 }
314}
315
316impl<F: fmt::Display, S: fmt::Display> fmt::Display for Pair<F, S> {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 write!(f, "({}, {})", self.first, self.second)
319 }
320}