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