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