Skip to main content

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}