cached_pair/pair.rs
1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! A pair of values where one can be converted to the other.
16//!
17//! This data structure caches the converted value to avoid redundant conversion.
18//! See the document of [`Pair`] for more details.
19
20#[cfg(test)]
21mod tests;
22
23use ::std::cell::OnceCell;
24use ::std::convert::Infallible;
25use ::std::fmt::Debug;
26use ::std::hash::Hash;
27use ::std::ptr;
28
29/// Re-exporting from [`itertools`] crate.
30///
31/// [`itertools`]: https://docs.rs/itertools/latest/itertools/
32#[cfg(feature = "itertools")]
33pub use ::itertools::EitherOrBoth;
34
35/// A simple enum that represents either a left or right value.
36#[cfg(not(feature = "itertools"))]
37#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub enum EitherOrBoth<L, R> {
39 Both(L, R),
40 Left(L),
41 Right(R),
42}
43
44/// A pair of values where one can be converted to the other.
45///
46/// This data structure stores a pair or either a left or right value.
47/// The left and right values can be converted to each other using the [`Converter`] trait.
48/// By default, the [`StdConverter`], which converts using `From` and `TryFrom` traits is used,
49/// but you can use custom closures by using [`fn_converter()`],
50/// or you can implement [`Converter`] for your own type.
51///
52/// The getter methods like [`left()`](Pair::left) and [`right()`](Pair::right) use this converter when that side's value is not present.
53/// Once a value is accessed, it is cached and will not be converted again.
54/// This caching can happen even in non-mutable methods.
55///
56/// On the other hand, the optional getter methods like [`left_opt()`](Pair::left_opt) and [`right_opt()`](Pair::right_opt)
57/// do not use the converter and always return the original value, thus they can return `None`.
58///
59/// # Mutable accessors
60///
61/// Note that mutable accessors like [`left_mut()`](Pair::left_mut) and [`right_mut()`](Pair::right_mut) will erase the other value.
62/// This is because this pair is designed so that one side of the pair is a cache of the other side,
63/// so once either side is mutated, the other side becomes dirty and should be cleared.
64///
65/// # Example
66///
67/// ```rust
68/// use cached_pair::{Pair, fn_converter};
69/// use std::convert::Infallible;
70/// use std::num::ParseIntError;
71///
72/// // Define a converter between i32 and String using fn_converter
73/// let converter = fn_converter(
74/// |s: &String| s.parse::<i32>(), // String -> i32 (may fail)
75/// |i: &i32| Ok::<String, Infallible>(i.to_string()), // i32 -> String (never fails)
76/// );
77///
78/// // Construct a pair from a left value.
79/// let pair: Pair<i32, String, _> = Pair::from_left_conv(42i32, converter);
80///
81/// // Left value is present, but right value is not.
82/// assert_eq!(pair.left_opt(), Some(&42));
83/// assert_eq!(pair.right_opt(), None);
84///
85/// // Get a right value by converting the left value.
86/// assert_eq!(pair.right(), &"42".to_string());
87///
88/// // Once we get the right value, it is cached.
89/// assert_eq!(pair.right_opt(), Some(&"42".to_string()));
90///
91/// // mutable access
92/// let mut pair = pair;
93///
94/// // Get a mutable reference to the left value.
95/// *pair.left_opt_mut().unwrap() = 123;
96///
97/// // ...then the right value is cleared.
98/// assert_eq!(pair.right_opt(), None);
99/// ```
100#[derive(Clone)]
101pub struct Pair<L, R, C = StdConverter> {
102 inner: PairInner<L, R>,
103 converter: C,
104}
105
106impl<L, R, C> Pair<L, R, C> {
107 /// Creates a new pair from a left value.
108 pub fn from_left(left: L) -> Self
109 where
110 C: Default,
111 {
112 Self {
113 inner: PairInner::from_left(left),
114 converter: C::default(),
115 }
116 }
117
118 /// Creates a new pair from a right value.
119 pub fn from_right(right: R) -> Self
120 where
121 C: Default,
122 {
123 Self {
124 inner: PairInner::from_right(right),
125 converter: C::default(),
126 }
127 }
128
129 /// Creates a new pair from a left value with a custom converter.
130 pub fn from_left_conv(left: L, converter: C) -> Self {
131 Self {
132 inner: PairInner::from_left(left),
133 converter,
134 }
135 }
136
137 /// Creates a new pair from a right value with a custom converter.
138 pub fn from_right_conv(right: R, converter: C) -> Self {
139 Self {
140 inner: PairInner::from_right(right),
141 converter,
142 }
143 }
144
145 /// Returns a reference to the left value if available.
146 ///
147 /// Returns `None` if the left value is not present.
148 pub fn left_opt(&self) -> Option<&L> {
149 self.inner.left_opt()
150 }
151
152 /// Returns a reference to the right value if available.
153 ///
154 /// Returns `None` if the right value is not present.
155 pub fn right_opt(&self) -> Option<&R> {
156 self.inner.right_opt()
157 }
158
159 /// Returns a mutable reference to the left value if available.
160 ///
161 /// Returns `None` if the left value is not present.
162 /// Note: Obtaining a mutable reference will erase the right value.
163 pub fn left_opt_mut(&mut self) -> Option<&mut L> {
164 self.inner.left_opt_mut()
165 }
166
167 /// Returns a mutable reference to the right value if available.
168 ///
169 /// Returns `None` if the right value is not present.
170 /// Note: Obtaining a mutable reference will erase the left value.
171 pub fn right_opt_mut(&mut self) -> Option<&mut R> {
172 self.inner.right_opt_mut()
173 }
174
175 /// Returns a left value if it is available.
176 /// If the left value is not available, converts the right value using the given closure.
177 /// The closure must not fail.
178 ///
179 /// # Safety
180 /// The conversion function must be consistent with the converter's behavior.
181 /// Inconsistent conversions may lead to invalid state.
182 pub unsafe fn left_with<F: FnOnce(&R) -> L>(&self, f: F) -> &L {
183 self.try_left_with(|r| Ok::<L, Infallible>(f(r))).into_ok2()
184 }
185
186 /// Returns a right value if it is available.
187 /// If the right value is not available, converts the left value using the given closure.
188 /// The closure must not fail.
189 ///
190 /// # Safety
191 /// The conversion function must be consistent with the converter's behavior.
192 /// Inconsistent conversions may lead to invalid state.
193 pub unsafe fn right_with<F: FnOnce(&L) -> R>(&self, f: F) -> &R {
194 self.try_right_with(|l| Ok::<R, Infallible>(f(l)))
195 .into_ok2()
196 }
197
198 /// Returns a left value if it is available.
199 /// If the left value is not available, attempts to convert the right value using the given closure.
200 ///
201 /// # Safety
202 /// The conversion function must be consistent with the converter's behavior.
203 /// Inconsistent conversions may lead to invalid state.
204 pub unsafe fn try_left_with<F: FnOnce(&R) -> Result<L, E>, E>(&self, f: F) -> Result<&L, E> {
205 self.inner.try_left_with(f)
206 }
207
208 /// Returns a right value if it is available.
209 /// If the right value is not available, attempts to convert the left value using the given closure.
210 ///
211 /// # Safety
212 /// The conversion function must be consistent with the converter's behavior.
213 /// Inconsistent conversions may lead to invalid state.
214 pub unsafe fn try_right_with<F: FnOnce(&L) -> Result<R, E>, E>(&self, f: F) -> Result<&R, E> {
215 self.inner.try_right_with(f)
216 }
217
218 /// Returns a mutable reference to the left value if it is available.
219 /// Note: Obtaining a mutable reference will erase the right value.
220 /// If the left value is not available, converts the right value using the given closure.
221 /// The closure must not fail.
222 ///
223 /// # Safety
224 /// The conversion function must be consistent with the converter's behavior.
225 /// Inconsistent conversions may lead to invalid state.
226 pub unsafe fn left_mut_with<F: FnOnce(&R) -> L>(&mut self, f: F) -> &mut L {
227 self.try_left_mut_with(|r| Ok::<L, Infallible>(f(r)))
228 .into_ok2()
229 }
230
231 /// Returns a mutable reference to the right value if it is available.
232 /// Note: Obtaining a mutable reference will erase the left value.
233 /// If the right value is not available, converts the left value using the given closure.
234 /// The closure must not fail.
235 ///
236 /// # Safety
237 /// The conversion function must be consistent with the converter's behavior.
238 /// Inconsistent conversions may lead to invalid state.
239 pub unsafe fn right_mut_with<F: FnOnce(&L) -> R>(&mut self, f: F) -> &mut R {
240 self.try_right_mut_with(|l| Ok::<R, Infallible>(f(l)))
241 .into_ok2()
242 }
243
244 /// Returns a mutable reference to the left value if it is available.
245 /// Note: Obtaining a mutable reference will erase the right value.
246 /// If the left value is not available, attempts to convert the right value using the given closure.
247 ///
248 /// # Safety
249 /// The conversion function must be consistent with the converter's behavior.
250 /// Inconsistent conversions may lead to invalid state.
251 pub unsafe fn try_left_mut_with<F: FnOnce(&R) -> Result<L, E>, E>(
252 &mut self,
253 f: F,
254 ) -> Result<&mut L, E> {
255 self.inner.try_left_mut_with(f)
256 }
257
258 /// Returns a mutable reference to the right value if it is available.
259 /// Note: Obtaining a mutable reference will erase the left value.
260 /// If the right value is not available, attempts to convert the left value using the given closure.
261 ///
262 /// # Safety
263 /// The conversion function must be consistent with the converter's behavior.
264 /// Inconsistent conversions may lead to invalid state.
265 pub unsafe fn try_right_mut_with<F: FnOnce(&L) -> Result<R, E>, E>(
266 &mut self,
267 f: F,
268 ) -> Result<&mut R, E> {
269 self.inner.try_right_mut_with(f)
270 }
271
272 /// Consumes the pair and returns the left value.
273 /// If the left value is not available, converts the right value using the given closure.
274 /// The closure must not fail.
275 ///
276 /// # Safety
277 /// The conversion function must be consistent with the converter's behavior.
278 /// Inconsistent conversions may lead to invalid state.
279 pub unsafe fn into_left_with<F: FnOnce(R) -> L>(self, f: F) -> L {
280 self.try_into_left_with(|r| Ok::<L, Infallible>(f(r)))
281 .into_ok2()
282 }
283
284 /// Consumes the pair and returns the right value.
285 /// If the right value is not available, converts the left value using the given closure.
286 /// The closure must not fail.
287 ///
288 /// # Safety
289 /// The conversion function must be consistent with the converter's behavior.
290 /// Inconsistent conversions may lead to invalid state.
291 pub unsafe fn into_right_with<F: FnOnce(L) -> R>(self, f: F) -> R {
292 self.try_into_right_with(|l| Ok::<R, Infallible>(f(l)))
293 .into_ok2()
294 }
295
296 /// Consumes the pair and attempts to return the left value.
297 /// If the left value is not available, attempts to convert the right value using the given closure.
298 ///
299 /// # Safety
300 /// The conversion function must be consistent with the converter's behavior.
301 /// Inconsistent conversions may lead to invalid state.
302 pub unsafe fn try_into_left_with<F: FnOnce(R) -> Result<L, E>, E>(self, f: F) -> Result<L, E> {
303 self.inner.try_into_left_with(f)
304 }
305
306 /// Consumes the pair and attempts to return the right value.
307 /// If the right value is not available, attempts to convert the left value using the given closure.
308 ///
309 /// # Safety
310 /// The conversion function must be consistent with the converter's behavior.
311 /// Inconsistent conversions may lead to invalid state.
312 pub unsafe fn try_into_right_with<F: FnOnce(L) -> Result<R, E>, E>(self, f: F) -> Result<R, E> {
313 self.inner.try_into_right_with(f)
314 }
315
316 /// Returns a reference to the pair as [`EitherOrBoth`] enum.
317 ///
318 /// Provides a view of the pair's current state using the [`EitherOrBoth`] type.
319 /// If you specify the `itertools` feature, it uses the [`itertools::EitherOrBoth`] type.
320 /// Otherwise, it uses the [`EitherOrBoth`] enum defined in this crate.
321 ///
322 /// [`itertools::EitherOrBoth`]: https://docs.rs/itertools/latest/itertools/enum.EitherOrBoth.html
323 pub fn as_ref(&self) -> EitherOrBoth<&L, &R> {
324 match &self.inner {
325 PairInner::GivenLeft { left, right_cell } => match right_cell.get() {
326 Some(right) => EitherOrBoth::Both(left, right),
327 None => EitherOrBoth::Left(left),
328 },
329 PairInner::GivenRight { right, left_cell } => match left_cell.get() {
330 Some(left) => EitherOrBoth::Both(left, right),
331 None => EitherOrBoth::Right(right),
332 },
333 }
334 }
335
336 /// Clears the left value if it exists and returns it.
337 /// If the left value is the only value in the pair, converts it to a right value using the given closure before clearing.
338 /// Returns None if the left value doesn't exist.
339 /// The closure must not fail.
340 ///
341 /// # Safety
342 /// The conversion function must be consistent with the converter's behavior.
343 /// Inconsistent conversions may lead to invalid state.
344 pub unsafe fn extract_left_with<F: FnOnce(&L) -> R>(&mut self, f: F) -> Option<L> {
345 self.try_extract_left_with(|l| Ok::<R, Infallible>(f(l)))
346 .into_ok2()
347 }
348
349 /// Clears the right value if it exists and returns it.
350 /// If the right value is the only value in the pair, converts it to a left value using the given closure before clearing.
351 /// Returns None if the right value doesn't exist.
352 /// The closure must not fail.
353 ///
354 /// # Safety
355 /// The conversion function must be consistent with the converter's behavior.
356 /// Inconsistent conversions may lead to invalid state.
357 pub unsafe fn extract_right_with<F: FnOnce(&R) -> L>(&mut self, f: F) -> Option<R> {
358 self.try_extract_right_with(|r| Ok::<L, Infallible>(f(r)))
359 .into_ok2()
360 }
361
362 /// Clears the left value if it exists and returns it.
363 /// If the left value is the only value in the pair, attempts to convert it to a right value using the given closure before clearing.
364 /// Returns None if the left value doesn't exist.
365 /// Returns Err if conversion fails when needed.
366 ///
367 /// # Safety
368 /// The conversion function must be consistent with the converter's behavior.
369 /// Inconsistent conversions may lead to invalid state.
370 pub unsafe fn try_extract_left_with<F: FnOnce(&L) -> Result<R, E>, E>(
371 &mut self,
372 f: F,
373 ) -> Result<Option<L>, E> {
374 self.inner.try_extract_left_with(f)
375 }
376
377 /// Clears the right value if it exists and returns it.
378 /// If the right value is the only value in the pair, attempts to convert it to a left value using the given closure before clearing.
379 /// Returns None if the right value doesn't exist.
380 /// Returns Err if conversion fails when needed.
381 ///
382 /// # Safety
383 /// The conversion function must be consistent with the converter's behavior.
384 /// Inconsistent conversions may lead to invalid state.
385 pub unsafe fn try_extract_right_with<F: FnOnce(&R) -> Result<L, E>, E>(
386 &mut self,
387 f: F,
388 ) -> Result<Option<R>, E> {
389 self.inner.try_extract_right_with(f)
390 }
391
392 /// Returns a reference to the converter used by this pair.
393 pub fn converter(&self) -> &C {
394 &self.converter
395 }
396
397 /// Returns a mutable reference to the converter used by this pair.
398 pub fn converter_mut(&mut self) -> &mut C {
399 &mut self.converter
400 }
401}
402
403impl<L, R, C> Pair<L, R, C>
404where
405 C: Converter<L, R>,
406{
407 /// Attempts to get a reference to the left value, converting if necessary.
408 ///
409 /// If the left value is not available, attempts to convert the right value using the converter.
410 pub fn try_left(&self) -> Result<&L, C::ToLeftError> {
411 self.inner
412 .try_left_with(|r| self.converter.convert_to_left(r))
413 }
414
415 /// Attempts to get a reference to the right value, converting if necessary.
416 ///
417 /// If the right value is not available, attempts to convert the left value using the converter.
418 pub fn try_right(&self) -> Result<&R, C::ToRightError> {
419 self.inner
420 .try_right_with(|l| self.converter.convert_to_right(l))
421 }
422
423 /// Attempts to get a mutable reference to the left value, converting if necessary.
424 ///
425 /// If the left value is not available, attempts to convert the right value using the converter.
426 /// Note: Obtaining a mutable reference will erase the right value.
427 pub fn try_left_mut(&mut self) -> Result<&mut L, C::ToLeftError> {
428 self.inner
429 .try_left_mut_with(|r| Ok(self.converter.convert_to_left(r)?))
430 }
431
432 /// Attempts to get a mutable reference to the right value, converting if necessary.
433 ///
434 /// If the right value is not available, attempts to convert the left value using the converter.
435 /// Note: Obtaining a mutable reference will erase the left value.
436 pub fn try_right_mut(&mut self) -> Result<&mut R, C::ToRightError> {
437 self.inner
438 .try_right_mut_with(|l| Ok(self.converter.convert_to_right(l)?))
439 }
440
441 /// Attempts to consume the pair and return the left value, converting if necessary.
442 ///
443 /// If the left value is not available, attempts to convert the right value using the converter.
444 pub fn try_into_left(self) -> Result<L, C::ToLeftError> {
445 let converter = &self.converter;
446 self.inner
447 .try_into_left_with(|r| Ok(converter.convert_to_left(&r)?))
448 }
449
450 /// Attempts to consume the pair and return the right value, converting if necessary.
451 ///
452 /// If the right value is not available, attempts to convert the left value using the converter.
453 pub fn try_into_right(self) -> Result<R, C::ToRightError> {
454 let converter = &self.converter;
455 self.inner
456 .try_into_right_with(|l| Ok(converter.convert_to_right(&l)?))
457 }
458
459 /// Attempts to extract the left value, converting if necessary.
460 ///
461 /// If the left value is the only value in the pair, attempts to convert it to a right value before clearing.
462 /// Returns None if the left value doesn't exist.
463 /// Returns Err if conversion fails when needed.
464 pub fn try_extract_left(&mut self) -> Result<Option<L>, C::ToRightError> {
465 self.inner
466 .try_extract_left_with(|l| Ok(self.converter.convert_to_right(l)?))
467 }
468
469 /// Attempts to extract the right value, converting if necessary.
470 ///
471 /// If the right value is the only value in the pair, attempts to convert it to a left value before clearing.
472 /// Returns None if the right value doesn't exist.
473 /// Returns Err if conversion fails when needed.
474 pub fn try_extract_right(&mut self) -> Result<Option<R>, C::ToLeftError> {
475 self.inner
476 .try_extract_right_with(|r| Ok(self.converter.convert_to_left(r)?))
477 }
478}
479
480impl<L, R, C> Pair<L, R, C>
481where
482 C: Converter<L, R, ToLeftError = Infallible>,
483{
484 /// Returns a reference to the left value, converting from right if necessary.
485 ///
486 /// If the left value is not available, converts the right value using the converter.
487 /// This method is only available when the conversion is infallible.
488 pub fn left(&self) -> &L {
489 self.try_left().into_ok2()
490 }
491
492 /// Returns a mutable reference to the left value, converting from right if necessary.
493 ///
494 /// If the left value is not available, converts the right value using the converter.
495 /// This method is only available when the conversion is infallible.
496 /// Note: Obtaining a mutable reference will erase the right value.
497 pub fn left_mut(&mut self) -> &mut L {
498 self.try_left_mut().into_ok2()
499 }
500
501 /// Consumes the pair and returns the left value, converting from right if necessary.
502 ///
503 /// If the left value is not available, converts the right value using the converter.
504 /// This method is only available when the conversion is infallible.
505 pub fn into_left(self) -> L {
506 self.try_into_left().into_ok2()
507 }
508
509 /// Extracts and returns the right value if it exists.
510 ///
511 /// If the right value is the only value in the pair, attempts to convert it to a left value before clearing.
512 /// Returns None if the right value doesn't exist.
513 /// This method is only available when the conversion is infallible.
514 pub fn extract_right(&mut self) -> Option<R> {
515 self.try_extract_right().into_ok2()
516 }
517}
518
519impl<L, R, C> Pair<L, R, C>
520where
521 C: Converter<L, R, ToRightError = Infallible>,
522{
523 /// Returns a reference to the right value, converting from left if necessary.
524 ///
525 /// If the right value is not available, converts the left value using the converter.
526 /// This method is only available when the conversion is infallible.
527 pub fn right(&self) -> &R {
528 self.try_right().into_ok2()
529 }
530
531 /// Returns a mutable reference to the right value, converting from left if necessary.
532 ///
533 /// If the right value is not available, converts the left value using the converter.
534 /// This method is only available when the conversion is infallible.
535 /// Note: Obtaining a mutable reference will erase the left value.
536 pub fn right_mut(&mut self) -> &mut R {
537 self.try_right_mut().into_ok2()
538 }
539
540 /// Consumes the pair and returns the right value, converting from left if necessary.
541 ///
542 /// If the right value is not available, converts the left value using the converter.
543 /// This method is only available when the conversion is infallible.
544 pub fn into_right(self) -> R {
545 self.try_into_right().into_ok2()
546 }
547
548 /// Extracts and returns the left value if it exists.
549 ///
550 /// If the left value is the only value in the pair, attempts to convert it to a right value before clearing.
551 /// Returns None if the left value doesn't exist.
552 /// This method is only available when the conversion is infallible.
553 pub fn extract_left(&mut self) -> Option<L> {
554 self.try_extract_left().into_ok2()
555 }
556}
557
558#[derive(Clone)]
559enum PairInner<L, R> {
560 #[doc(hidden)]
561 GivenLeft { left: L, right_cell: OnceCell<R> },
562 #[doc(hidden)]
563 GivenRight { left_cell: OnceCell<L>, right: R },
564}
565
566impl<L, R> PairInner<L, R> {
567 fn from_left(left: L) -> Self {
568 Self::GivenLeft {
569 left,
570 right_cell: OnceCell::new(),
571 }
572 }
573
574 fn from_right(right: R) -> Self {
575 Self::GivenRight {
576 left_cell: OnceCell::new(),
577 right,
578 }
579 }
580
581 fn left_opt(&self) -> Option<&L> {
582 match self {
583 PairInner::GivenLeft { left, .. } => Some(left),
584 PairInner::GivenRight { left_cell, .. } => left_cell.get(),
585 }
586 }
587
588 fn right_opt(&self) -> Option<&R> {
589 match self {
590 PairInner::GivenLeft { right_cell, .. } => right_cell.get(),
591 PairInner::GivenRight { right, .. } => Some(right),
592 }
593 }
594
595 fn left_opt_mut(&mut self) -> Option<&mut L> {
596 match self {
597 PairInner::GivenLeft { left, right_cell } => {
598 let _ = right_cell.take();
599 Some(left)
600 }
601 PairInner::GivenRight { left_cell, .. } => {
602 let left = left_cell.take()?;
603 *self = Self::from_left(left);
604 if let PairInner::GivenLeft { left, .. } = self {
605 Some(left)
606 } else {
607 unreachable!()
608 }
609 }
610 }
611 }
612
613 fn right_opt_mut(&mut self) -> Option<&mut R> {
614 match self {
615 PairInner::GivenLeft { right_cell, .. } => {
616 let right = right_cell.take()?;
617 *self = Self::from_right(right);
618 if let PairInner::GivenRight { right, .. } = self {
619 Some(right)
620 } else {
621 unreachable!()
622 }
623 }
624 PairInner::GivenRight { right, left_cell } => {
625 let _ = left_cell.take();
626 Some(right)
627 }
628 }
629 }
630
631 fn try_left_with<F: FnOnce(&R) -> Result<L, E>, E>(&self, f: F) -> Result<&L, E> {
632 match self {
633 PairInner::GivenLeft { left, .. } => Ok(left),
634 PairInner::GivenRight { left_cell, right } => left_cell.get_or_try_init2(|| f(right)),
635 }
636 }
637
638 fn try_right_with<F: FnOnce(&L) -> Result<R, E>, E>(&self, f: F) -> Result<&R, E> {
639 match self {
640 PairInner::GivenLeft { left, right_cell } => right_cell.get_or_try_init2(|| f(left)),
641 PairInner::GivenRight { right, .. } => Ok(right),
642 }
643 }
644
645 fn try_left_mut_with<F: FnOnce(&R) -> Result<L, E>, E>(&mut self, f: F) -> Result<&mut L, E> {
646 match self {
647 PairInner::GivenLeft { left, right_cell } => {
648 let _ = right_cell.take();
649 Ok(left)
650 }
651 PairInner::GivenRight { left_cell, right } => {
652 let left = left_cell.take().map(Ok).unwrap_or_else(|| f(right))?;
653 *self = Self::from_left(left);
654
655 if let PairInner::GivenLeft { left, .. } = self {
656 Ok(left)
657 } else {
658 unreachable!()
659 }
660 }
661 }
662 }
663
664 fn try_right_mut_with<F: FnOnce(&L) -> Result<R, E>, E>(&mut self, f: F) -> Result<&mut R, E> {
665 match self {
666 PairInner::GivenLeft { left, right_cell } => {
667 let right = right_cell.take().map(Ok).unwrap_or_else(|| f(left))?;
668 *self = Self::from_right(right);
669
670 if let PairInner::GivenRight { right, .. } = self {
671 Ok(right)
672 } else {
673 unreachable!()
674 }
675 }
676 PairInner::GivenRight { right, left_cell } => {
677 let _ = left_cell.take();
678 Ok(right)
679 }
680 }
681 }
682
683 fn try_extract_left_with<F: FnOnce(&L) -> Result<R, E>, E>(
684 &mut self,
685 f: F,
686 ) -> Result<Option<L>, E> {
687 match self {
688 PairInner::GivenLeft { left, right_cell } => {
689 let right = right_cell.take().map(Ok).unwrap_or_else(|| f(left))?;
690 let _ = unsafe { ptr::read(right_cell) };
691 let old_left = unsafe { ptr::read(left) };
692 unsafe {
693 ptr::write(self, Self::from_right(right));
694 }
695 Ok(Some(old_left))
696 }
697 PairInner::GivenRight { left_cell, .. } => Ok(left_cell.take()),
698 }
699 }
700
701 fn try_extract_right_with<F: FnOnce(&R) -> Result<L, E>, E>(
702 &mut self,
703 f: F,
704 ) -> Result<Option<R>, E> {
705 match self {
706 PairInner::GivenRight { right, left_cell } => {
707 let left = left_cell.take().map(Ok).unwrap_or_else(|| f(right))?;
708 let _ = unsafe { ptr::read(left_cell) };
709 let old_right = unsafe { ptr::read(right) };
710 unsafe {
711 ptr::write(self, Self::from_left(left));
712 }
713 Ok(Some(old_right))
714 }
715 PairInner::GivenLeft { right_cell, .. } => Ok(right_cell.take()),
716 }
717 }
718
719 fn try_into_left_with<F: FnOnce(R) -> Result<L, E>, E>(self, f: F) -> Result<L, E> {
720 match self {
721 PairInner::GivenLeft { left, .. } => Ok(left),
722 PairInner::GivenRight {
723 right,
724 mut left_cell,
725 } => left_cell.take().map_or_else(|| f(right), Ok),
726 }
727 }
728
729 fn try_into_right_with<F: FnOnce(L) -> Result<R, E>, E>(self, f: F) -> Result<R, E> {
730 match self {
731 PairInner::GivenRight { right, .. } => Ok(right),
732 PairInner::GivenLeft {
733 left,
734 mut right_cell,
735 } => right_cell.take().map_or_else(|| f(left), Ok),
736 }
737 }
738}
739
740impl<L: Debug, R: Debug, C> Debug for Pair<L, R, C> {
741 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
742 f.debug_tuple("Pair")
743 .field(&self.left_opt())
744 .field(&self.right_opt())
745 .finish()
746 }
747}
748
749impl<L: PartialEq, R: PartialEq, C> PartialEq for Pair<L, R, C> {
750 fn eq(&self, other: &Self) -> bool {
751 (self.left_opt(), self.right_opt()) == (other.left_opt(), other.right_opt())
752 }
753}
754
755impl<L: Hash, R: Hash, C> Hash for Pair<L, R, C> {
756 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
757 self.left_opt().hash(state);
758 self.right_opt().hash(state);
759 }
760}
761
762impl<L, R, C> From<Pair<L, R, C>> for EitherOrBoth<L, R> {
763 fn from(pair: Pair<L, R, C>) -> Self {
764 let (left, right) = match pair.inner {
765 PairInner::GivenLeft {
766 left,
767 mut right_cell,
768 } => (Some(left), right_cell.take()),
769 PairInner::GivenRight {
770 mut left_cell,
771 right,
772 } => (left_cell.take(), Some(right)),
773 };
774 match (left, right) {
775 (Some(left), Some(right)) => EitherOrBoth::Both(left, right),
776 (Some(left), None) => EitherOrBoth::Left(left),
777 (None, Some(right)) => EitherOrBoth::Right(right),
778 (None, None) => unreachable!(),
779 }
780 }
781}
782
783/// A trait for bidirectional conversion between two types.
784///
785/// This trait is used by [`Pair`] to convert between its left and right values.
786///
787/// # Example
788///
789/// ```rust
790/// use cached_pair::Converter;
791/// use std::convert::Infallible;
792/// use std::num::ParseIntError;
793///
794/// struct MyConverter;
795///
796/// impl Converter<i32, String> for MyConverter {
797/// type ToLeftError = ParseIntError;
798/// type ToRightError = Infallible;
799///
800/// fn convert_to_left(&self, right: &String) -> Result<i32, Self::ToLeftError> {
801/// right.parse()
802/// }
803///
804/// fn convert_to_right(&self, left: &i32) -> Result<String, Self::ToRightError> {
805/// Ok(left.to_string())
806/// }
807/// }
808/// ```
809pub trait Converter<L, R> {
810 /// The error type returned when converting from right to left.
811 type ToLeftError;
812
813 /// The error type returned when converting from left to right.
814 type ToRightError;
815
816 /// Converts a reference to a right value into a left value.
817 fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError>;
818
819 /// Converts a reference to a left value into a right value.
820 fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError>;
821}
822
823/// A standard converter using the `TryFrom` trait.
824///
825/// This is the default converter used by [`Pair`] when no converter is specified.
826/// Note that this converter requires the `TryFrom<&L> for R` and `TryFrom<&R> for L`
827/// implementations, which are not typically implemented by the library authors.
828#[derive(Default, Debug, Clone)]
829pub struct StdConverter;
830
831impl<L, R, EL, ER> Converter<L, R> for StdConverter
832where
833 for<'a> &'a L: TryInto<R, Error = ER>,
834 for<'a> &'a R: TryInto<L, Error = EL>,
835{
836 type ToLeftError = EL;
837 type ToRightError = ER;
838
839 fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError> {
840 right.try_into()
841 }
842
843 fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError> {
844 left.try_into()
845 }
846}
847
848/// A converter that uses closures for conversions.
849///
850/// This is useful when you want to provide custom conversion logic without implementing the [`TryFrom`] trait.
851#[derive(Clone)]
852pub struct FnConverter<F, G> {
853 to_left: F,
854 to_right: G,
855}
856
857impl<F, G> Debug for FnConverter<F, G> {
858 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
859 f.debug_struct("FnConverter")
860 .field("to_left", &"<function>")
861 .field("to_right", &"<function>")
862 .finish()
863 }
864}
865
866/// Creates a new [`FnConverter`] from two functions.
867///
868/// This is a convenience function for creating a converter that uses closures for conversions.
869/// Note that the type of the converter is not descriptable if you use the closure as an argument.
870/// Use [`boxed_fn_converter()`] instead if you need a descriptable type.
871///
872/// # Example
873///
874/// ```rust
875/// use cached_pair::{Pair, fn_converter};
876/// use std::convert::Infallible;
877/// use std::num::TryFromIntError;
878///
879/// let converter = fn_converter(
880/// // Right to left
881/// |i: &i32| -> Result<u8, TryFromIntError> { (*i - 10).try_into() },
882/// // Left to right
883/// |u: &u8| -> Result<i32, Infallible> { Ok((*u as i32) + 10) },
884/// );
885///
886/// let pair = Pair::from_right_conv(52i32, converter);
887/// assert_eq!(pair.try_left(), Ok(&42u8));
888/// ```
889pub fn fn_converter<F, G>(f: F, g: G) -> FnConverter<F, G> {
890 FnConverter {
891 to_left: f,
892 to_right: g,
893 }
894}
895
896impl<L, R, F, G, EL, ER> Converter<L, R> for FnConverter<F, G>
897where
898 for<'a> F: Fn(&'a R) -> Result<L, EL>,
899 for<'a> G: Fn(&'a L) -> Result<R, ER>,
900{
901 type ToLeftError = EL;
902 type ToRightError = ER;
903
904 fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError> {
905 (self.to_left)(right)
906 }
907
908 fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError> {
909 (self.to_right)(left)
910 }
911}
912
913/// A converter that uses boxed closures for conversions.
914///
915/// This is similar to [`FnConverter`] but uses trait objects,
916/// making its type always descriptable.
917///
918/// # Example
919///
920/// ```rust
921/// use cached_pair::{Pair, boxed_fn_converter, BoxedFnConverter};
922/// use std::convert::Infallible;
923/// use std::num::TryFromIntError;
924///
925/// let converter = boxed_fn_converter(
926/// // Right to left
927/// |i: &i32| -> Result<u8, TryFromIntError> { (*i - 100).try_into() },
928/// // Left to right
929/// |u: &u8| -> Result<i32, Infallible> { Ok((*u as i32) + 100) },
930/// );
931///
932/// // The type of the converter is descriptable! This is not the case with [`fn_converter()`].
933/// let pair: Pair<u8, i32, BoxedFnConverter<u8, i32, TryFromIntError, Infallible>> =
934/// Pair::from_right_conv(142i32, converter);
935/// assert_eq!(pair.try_left(), Ok(&42u8));
936/// ```
937pub struct BoxedFnConverter<L, R, EL = Infallible, ER = Infallible> {
938 to_left: Box<dyn for<'a> Fn(&'a R) -> Result<L, EL>>,
939 to_right: Box<dyn for<'a> Fn(&'a L) -> Result<R, ER>>,
940}
941
942impl<L, R, EL, ER> Debug for BoxedFnConverter<L, R, EL, ER> {
943 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
944 f.debug_struct("BoxedFnConverter")
945 .field("to_left", &"<boxed function>")
946 .field("to_right", &"<boxed function>")
947 .finish()
948 }
949}
950
951/// Creates a new [`BoxedFnConverter`] from two closures.
952///
953/// This is a convenience function for creating a converter that uses boxed closures for conversions.
954/// The resulting converter has a descriptable type, unlike [`fn_converter()`].
955///
956/// # Example
957///
958/// ```rust
959/// use cached_pair::{Pair, boxed_fn_converter};
960/// use std::convert::Infallible;
961/// use std::num::TryFromIntError;
962///
963/// let converter = boxed_fn_converter(
964/// |i: &i32| -> Result<u8, TryFromIntError> { (*i - 100).try_into() },
965/// |u: &u8| -> Result<i32, Infallible> { Ok((*u as i32) + 100) },
966/// );
967///
968/// let pair = Pair::from_right_conv(142i32, converter);
969/// assert_eq!(pair.try_left(), Ok(&42u8));
970/// ```
971pub fn boxed_fn_converter<L, R, F, G, EL, ER>(f: F, g: G) -> BoxedFnConverter<L, R, EL, ER>
972where
973 for<'a> F: Fn(&'a R) -> Result<L, EL> + 'static,
974 for<'a> G: Fn(&'a L) -> Result<R, ER> + 'static,
975{
976 BoxedFnConverter {
977 to_left: Box::new(f),
978 to_right: Box::new(g),
979 }
980}
981
982impl<L, R, EL, ER> Converter<L, R> for BoxedFnConverter<L, R, EL, ER> {
983 type ToLeftError = EL;
984 type ToRightError = ER;
985
986 fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError> {
987 (self.to_left)(right)
988 }
989
990 fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError> {
991 (self.to_right)(left)
992 }
993}
994
995/// A private trait for [`OnceCell`] to use an unstable method [`OnceCell::get_or_try_init()`] in stable code.
996trait OnceCellExt<T> {
997 fn get_or_try_init2<E, F>(&self, init: F) -> Result<&T, E>
998 where
999 F: FnOnce() -> Result<T, E>;
1000}
1001
1002impl<T> OnceCellExt<T> for OnceCell<T> {
1003 fn get_or_try_init2<E, F>(&self, init: F) -> Result<&T, E>
1004 where
1005 F: FnOnce() -> Result<T, E>,
1006 {
1007 match self.get() {
1008 Some(v) => Ok(v),
1009 None => {
1010 let v = init()?;
1011 let _ = self.set(v); // We are sure the `set` will succeed.
1012 Ok(unsafe { self.get().unwrap_unchecked() })
1013 }
1014 }
1015 }
1016}
1017
1018/// A private trait for [`Result`] to use an unstable method [`Result::into_ok()`] in stable code.
1019trait ResultExt<T, E> {
1020 fn into_ok2(self) -> T
1021 where
1022 E: Into<Infallible>;
1023}
1024
1025impl<T, E> ResultExt<T, E> for Result<T, E> {
1026 #[allow(unreachable_code)]
1027 fn into_ok2(self) -> T
1028 where
1029 E: Into<Infallible>,
1030 {
1031 match self {
1032 Ok(v) => v,
1033 Err(e) => match e.into() {},
1034 }
1035 }
1036}