prism3_core/util/tuple/
triple.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Triple
10//!
11//! A generic triple structure that holds three values of potentially different types.
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17use std::fmt;
18
19/// A generic triple structure that holds three values.
20///
21/// # Type Parameters
22///
23/// * `F` - The type of the first element
24/// * `S` - The type of the second element
25/// * `T` - The type of the third element
26///
27/// # Comparison with Native Tuples
28///
29/// While Rust's native tuples `(F, S, T)` and `Triple<F, S, T>` both store three values,
30/// they differ in several key aspects:
31///
32/// ## Similarities
33///
34/// - Both can hold three values of different types
35/// - Both support pattern matching and destructuring
36/// - Both can be converted to each other via `From`/`Into` traits
37/// - Both have similar memory layout and zero runtime overhead
38///
39/// ## Differences
40///
41/// | Feature | Native Tuple `(F, S, T)` | `Triple<F, S, T>` |
42/// |---------|-------------------------|-------------------|
43/// | Field Access | `.0`, `.1`, `.2` (positional) | `.first`, `.second`, `.third` (named) |
44/// | Semantics | Anonymous, positional | Self-documenting, semantic |
45/// | Methods | Limited built-in methods | Rich API (map, getters, setters) |
46/// | Readability | Less clear in complex code | More expressive and maintainable |
47/// | Type Alias | Hard to create meaningful aliases | Easy to create domain-specific types |
48///
49/// ## When to Use `Triple` vs Native Tuples
50///
51/// **Use `Triple` when:**
52/// - Field names improve code readability (e.g., `triple.first` vs `tuple.0`)
53/// - You need additional methods like `map_first()`, `map_second()`, etc.
54/// - Creating domain-specific types (e.g., `type Coordinate = Triple<f64, f64, f64>`)
55/// - The triple represents a logical entity with semantic meaning
56/// - You want to implement custom traits or behaviors
57///
58/// **Use native tuples when:**
59/// - You need quick, temporary grouping of values
60/// - Working with existing APIs that expect tuples
61/// - Pattern matching is the primary use case
62/// - Minimal overhead and simplicity are paramount
63///
64/// # Examples
65///
66/// ```
67/// use prism3_core::Triple;
68///
69/// let triple = Triple::new("name", 42, true);
70/// assert_eq!(triple.first, "name");
71/// assert_eq!(triple.second, 42);
72/// assert_eq!(triple.third, true);
73///
74/// let triple = Triple { first: 1, second: 2.5, third: "hello" };
75/// assert_eq!(triple.first, 1);
76/// assert_eq!(triple.second, 2.5);
77/// assert_eq!(triple.third, "hello");
78/// ```
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
80pub struct Triple<F, S, T> {
81    /// The first element of the triple
82    pub first: F,
83    /// The second element of the triple
84    pub second: S,
85    /// The third element of the triple
86    pub third: T,
87}
88
89impl<F, S, T> Triple<F, S, T> {
90    /// Creates a new `Triple` with the given values.
91    ///
92    /// # Arguments
93    ///
94    /// * `first` - The first element
95    /// * `second` - The second element
96    /// * `third` - The third element
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use prism3_core::Triple;
102    ///
103    /// let triple = Triple::new(1, "hello", true);
104    /// assert_eq!(triple.first, 1);
105    /// assert_eq!(triple.second, "hello");
106    /// assert_eq!(triple.third, true);
107    /// ```
108    #[inline]
109    pub fn new(first: F, second: S, third: T) -> Self {
110        Triple {
111            first,
112            second,
113            third,
114        }
115    }
116
117    /// Consumes the triple and returns a tuple of its elements.
118    ///
119    /// # Examples
120    ///
121    /// ```
122    /// use prism3_core::Triple;
123    ///
124    /// let triple = Triple::new(1, "hello", true);
125    /// let (first, second, third) = triple.into_tuple();
126    /// assert_eq!(first, 1);
127    /// assert_eq!(second, "hello");
128    /// assert_eq!(third, true);
129    /// ```
130    #[inline]
131    pub fn into_tuple(self) -> (F, S, T) {
132        (self.first, self.second, self.third)
133    }
134
135    /// Returns a reference to the first element.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use prism3_core::Triple;
141    ///
142    /// let triple = Triple::new(1, 2, 3);
143    /// assert_eq!(triple.first(), &1);
144    /// ```
145    #[inline]
146    pub fn first(&self) -> &F {
147        &self.first
148    }
149
150    /// Returns a reference to the second element.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// use prism3_core::Triple;
156    ///
157    /// let triple = Triple::new(1, 2, 3);
158    /// assert_eq!(triple.second(), &2);
159    /// ```
160    #[inline]
161    pub fn second(&self) -> &S {
162        &self.second
163    }
164
165    /// Returns a reference to the third element.
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// use prism3_core::Triple;
171    ///
172    /// let triple = Triple::new(1, 2, 3);
173    /// assert_eq!(triple.third(), &3);
174    /// ```
175    #[inline]
176    pub fn third(&self) -> &T {
177        &self.third
178    }
179
180    /// Returns a mutable reference to the first element.
181    ///
182    /// # Examples
183    ///
184    /// ```
185    /// use prism3_core::Triple;
186    ///
187    /// let mut triple = Triple::new(1, 2, 3);
188    /// *triple.first_mut() = 10;
189    /// assert_eq!(triple.first, 10);
190    /// ```
191    #[inline]
192    pub fn first_mut(&mut self) -> &mut F {
193        &mut self.first
194    }
195
196    /// Returns a mutable reference to the second element.
197    ///
198    /// # Examples
199    ///
200    /// ```
201    /// use prism3_core::Triple;
202    ///
203    /// let mut triple = Triple::new(1, 2, 3);
204    /// *triple.second_mut() = 20;
205    /// assert_eq!(triple.second, 20);
206    /// ```
207    #[inline]
208    pub fn second_mut(&mut self) -> &mut S {
209        &mut self.second
210    }
211
212    /// Returns a mutable reference to the third element.
213    ///
214    /// # Examples
215    ///
216    /// ```
217    /// use prism3_core::Triple;
218    ///
219    /// let mut triple = Triple::new(1, 2, 3);
220    /// *triple.third_mut() = 30;
221    /// assert_eq!(triple.third, 30);
222    /// ```
223    #[inline]
224    pub fn third_mut(&mut self) -> &mut T {
225        &mut self.third
226    }
227
228    /// Maps the first element to a new value using the provided function.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use prism3_core::Triple;
234    ///
235    /// let triple = Triple::new(1, "hello", true);
236    /// let mapped = triple.map_first(|x| x * 2);
237    /// assert_eq!(mapped.first, 2);
238    /// assert_eq!(mapped.second, "hello");
239    /// assert_eq!(mapped.third, true);
240    /// ```
241    #[inline]
242    pub fn map_first<F2, Fn>(self, f: Fn) -> Triple<F2, S, T>
243    where
244        Fn: FnOnce(F) -> F2,
245    {
246        Triple {
247            first: f(self.first),
248            second: self.second,
249            third: self.third,
250        }
251    }
252
253    /// Maps the second element to a new value using the provided function.
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// use prism3_core::Triple;
259    ///
260    /// let triple = Triple::new(1, "hello", true);
261    /// let mapped = triple.map_second(|s| s.len());
262    /// assert_eq!(mapped.first, 1);
263    /// assert_eq!(mapped.second, 5);
264    /// assert_eq!(mapped.third, true);
265    /// ```
266    #[inline]
267    pub fn map_second<S2, Fn>(self, f: Fn) -> Triple<F, S2, T>
268    where
269        Fn: FnOnce(S) -> S2,
270    {
271        Triple {
272            first: self.first,
273            second: f(self.second),
274            third: self.third,
275        }
276    }
277
278    /// Maps the third element to a new value using the provided function.
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use prism3_core::Triple;
284    ///
285    /// let triple = Triple::new(1, "hello", true);
286    /// let mapped = triple.map_third(|b| if b { "yes" } else { "no" });
287    /// assert_eq!(mapped.first, 1);
288    /// assert_eq!(mapped.second, "hello");
289    /// assert_eq!(mapped.third, "yes");
290    /// ```
291    #[inline]
292    pub fn map_third<T2, Fn>(self, f: Fn) -> Triple<F, S, T2>
293    where
294        Fn: FnOnce(T) -> T2,
295    {
296        Triple {
297            first: self.first,
298            second: self.second,
299            third: f(self.third),
300        }
301    }
302}
303
304impl<F, S, T> From<(F, S, T)> for Triple<F, S, T> {
305    /// Creates a `Triple` from a tuple.
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use prism3_core::Triple;
311    ///
312    /// let triple: Triple<i32, &str, bool> = (1, "hello", true).into();
313    /// assert_eq!(triple.first, 1);
314    /// assert_eq!(triple.second, "hello");
315    /// assert_eq!(triple.third, true);
316    /// ```
317    #[inline]
318    fn from(tuple: (F, S, T)) -> Self {
319        Triple {
320            first: tuple.0,
321            second: tuple.1,
322            third: tuple.2,
323        }
324    }
325}
326
327impl<F, S, T> From<Triple<F, S, T>> for (F, S, T) {
328    /// Converts a `Triple` into a tuple.
329    ///
330    /// # Examples
331    ///
332    /// ```
333    /// use prism3_core::Triple;
334    ///
335    /// let triple = Triple::new(1, "hello", true);
336    /// let tuple: (i32, &str, bool) = triple.into();
337    /// assert_eq!(tuple, (1, "hello", true));
338    /// ```
339    #[inline]
340    fn from(triple: Triple<F, S, T>) -> Self {
341        (triple.first, triple.second, triple.third)
342    }
343}
344
345impl<F: fmt::Display, S: fmt::Display, T: fmt::Display> fmt::Display for Triple<F, S, T> {
346    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347        write!(f, "({}, {}, {})", self.first, self.second, self.third)
348    }
349}