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}