refcon/
lib.rs

1#![cfg_attr(not(test), no_std)]
2//! # What is Refcon?
3//!
4//! This crate provides the [`Refcon`] enum, which is used to wrap either a
5//! concrete instance of a type `T`, or a reference to one.
6//!
7//! By implementing [`AsRef<T>`], [`Refcon`] lets either variant seamlessly
8//! behave as a reference to `T`.
9//!
10//! ```ignore
11//! const ZERO = ABigStruct::costly_initializer();
12//! let v: Vec<ABigStruct> = (0..10_000)
13//!     .map(|i|
14//!          if i < 1_000 {
15//!              Refcon::from(&ZERO)
16//!          } else {
17//!              Refcon::from(ABigStruct::new(i))
18//!          })
19//!     .collect();
20//!
21//! // [...]
22//!
23//! for x in v.iter() {
24//!   x.do_something();
25//! }
26//! ```
27//!
28//! ## When **not** to use Refcon
29//!   - `T` is smaller than two machine words – you should just copy everything
30//!   in this case anyways;
31//!   - you can not afford/do not want to pay for the double indirection price
32//!   while accessing the inner value;
33//!   - you do not want to pay for the price of the additional memory copy while
34//!   constructing the concrete variant;
35//!
36//! ## When to use Refcon
37//!   - You want to mix values & references: _e.g._ if you have a vector
38//!   containing either reference to pre-computed values or ad-hoc ones or if an
39//!   iterator in a trait may iterate over immediate or reference values
40//!   depending on the implementation.
41
42#[cfg(test)]
43mod tests;
44
45pub enum Refcon<'a, T> {
46    Ref(&'a T),
47    Concrete(T),
48}
49
50impl<'a, T> Refcon<'a, T> {
51    /// Return true if the wrapped value is a reference to `T`.
52    pub fn is_ref(&self) -> bool {
53        matches!(self, Refcon::Ref(_))
54    }
55
56    /// Return true if the wrapped value is a concrete instance of `T`.
57    pub fn is_concrete(&self) -> bool {
58        matches!(self, Refcon::Concrete(_))
59    }
60}
61
62impl<T> AsRef<T> for Refcon<'_, T> {
63    fn as_ref(&self) -> &T {
64        match self {
65            Refcon::Concrete(t) => t,
66            Refcon::Ref(t) => t,
67        }
68    }
69}
70
71impl<T> From<T> for Refcon<'_, T> {
72    fn from(value: T) -> Self {
73        Refcon::Concrete(value)
74    }
75}
76
77impl<'a, T> From<&'a T> for Refcon<'a, T> {
78    fn from(value: &'a T) -> Self {
79        Refcon::Ref(value)
80    }
81}