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}