finalizable/
lib.rs

1#![no_std]
2#![cfg_attr(feature = "try", feature(try_trait_v2))]
3//! This crate provides a type ([`Finalizable`]) for values that can be finalized,
4//! with methods that operate on working values but leave finalized values unchanged.
5
6#[cfg(feature = "try")]
7use core::ops::{ControlFlow, FromResidual, Try};
8
9pub use Finalizable::*;
10
11/// A value that can be a working value or a finalized value.
12/// All operations on a single [`Finalizable<T>`] do not modify a finalized value.
13#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
14pub enum Finalizable<T> {
15    /// A working value.
16    Working(T),
17    /// A finalized value.
18    Finalized(T),
19}
20
21impl<T> Finalizable<T> {
22    /// Create a new finalizable value from a value and a boolean
23    /// that determines if it is a finalized or working value.
24    pub fn new(value: T, finalized: bool) -> Self {
25        match finalized {
26            true => Finalized(value),
27            false => Working(value),
28        }
29    }
30    /// Finalize a value. Returns a finalized version of the value.
31    pub fn finalize(self) -> Self {
32        Finalized(self.get())
33    }
34    /// Get the value, whether working or finalized.
35    pub fn get(self) -> T {
36        match self {
37            Working(x) => x,
38            Finalized(x) => x,
39        }
40    }
41    /// Get the value from a reference to a finalizable value,
42    /// whether working or finalized, as a reference to the underlying value.
43    pub fn get_as_ref(&self) -> &T {
44        self.as_ref().get()
45    }
46    /// Get the value from a mutable reference to a working value
47    /// as a mutable reference. Returns [`None`] if the value is a finalized value.
48    pub fn try_get_mut(&mut self) -> Option<&mut T> {
49        match self {
50            Working(x) => Some(x),
51            Finalized(_) => None,
52        }
53    }
54    /// Override a working value. Does nothing to a finalized value.
55    pub fn set(self, value: T) -> Self {
56        match self {
57            Working(_) => Working(value),
58            a @ Finalized(_) => a,
59        }
60    }
61    /// Check if a value is a working value.
62    pub fn is_working(&self) -> bool {
63        matches!(self, Working(_))
64    }
65    /// Check if a value is a finalized value.
66    pub fn is_finalized(&self) -> bool {
67        matches!(self, Finalized(_))
68    }
69    /// Get the value, but only if it is a working value.
70    /// Returns [`None`] if the value is a finalized value.
71    pub fn working_or_none(self) -> Option<T> {
72        match self {
73            Working(x) => Some(x),
74            Finalized(_) => None,
75        }
76    }
77    /// Get the value, but only if it is a finalized value.
78    /// Returns [`None`] if the value is a working value.
79    pub fn finalized_or_none(self) -> Option<T> {
80        match self {
81            Working(_) => None,
82            Finalized(x) => Some(x),
83        }
84    }
85    /// Get the value, but only if it is a finalized value.
86    /// Returns `default` if the value is a working value.
87    pub fn finalized_or(self, default: T) -> T {
88        match self {
89            Working(_) => default,
90            Finalized(x) => x,
91        }
92    }
93    /// Get the value, but only if it is a finalized value.
94    /// Calls `default` and returns its result if the value is a working value.
95    pub fn finalized_or_else<F: FnOnce(T) -> T>(self, op: F) -> T {
96        match self {
97            Working(x) => op(x),
98            Finalized(x) => x,
99        }
100    }
101    /// Turn a reference to a finalizable value into a finalizable reference.
102    pub fn as_ref(&self) -> Finalizable<&T> {
103        match self {
104            Working(x) => Working(x),
105            Finalized(x) => Finalized(x),
106        }
107    }
108    /// Apply a function to a working value. Does nothing to a finalized value.
109    pub fn map<F: FnOnce(T) -> T>(self, op: F) -> Self {
110        match self {
111            Working(x) => Working(op(x)),
112            a @ Finalized(_) => a,
113        }
114    }
115    /// Apply a function to a working value and finalize it.
116    /// Does nothing to a finalized value.
117    pub fn map_and_finalize<F: FnOnce(T) -> T>(self, op: F) -> Self {
118        self.map(op).finalize()
119    }
120    /// Get a finalized value, panicking with `msg` if the value is a working value.
121    pub fn expect_finalized(self, msg: &str) -> T {
122        match self {
123            Working(x) => x,
124            Finalized(_) => panic!("{}", msg),
125        }
126    }
127    /// Return `fin` if the value is a working value, returning a finalized value unchanged.
128    pub fn and(self, fin: Self) -> Self {
129        match self {
130            Working(_) => fin,
131            a @ Finalized(_) => a,
132        }
133    }
134    /// Call `op` on the value if it is a working value,
135    /// returning a finalized value unchanged.
136    pub fn and_then<F: FnOnce(T) -> Self>(self, op: F) -> Self {
137        match self {
138            Working(x) => op(x),
139            a @ Finalized(_) => a,
140        }
141    }
142    /// Call `op` on the value if it is a working value,
143    /// creating a new finalizable value by using the returned tuple
144    /// as the arguments to [`new`], returning a finalized value unchanged.
145    ///
146    /// [`new`]: Finalizable::new
147    pub fn and_then_new<F: FnOnce(T) -> (T, bool)>(self, op: F) -> Self {
148        self.and_then(|x| {
149            let (value, finalized) = op(x);
150            Finalizable::new(value, finalized)
151        })
152    }
153}
154
155impl<T> Finalizable<&T> {
156    /// Make a copy of a finalizable value by copying the underlying value.
157    pub fn copied(self) -> Finalizable<T>
158    where
159        T: Copy,
160    {
161        match self {
162            Working(x) => Working(*x),
163            Finalized(x) => Finalized(*x),
164        }
165    }
166    /// Make a clone of a finalizable value by cloning the underlying value.
167    pub fn cloned(self) -> Finalizable<T>
168    where
169        T: Clone,
170    {
171        match self {
172            Working(x) => Working(x.clone()),
173            Finalized(x) => Finalized(x.clone()),
174        }
175    }
176}
177
178#[cfg(feature = "try")]
179/// Acts like [`ControlFlow<T, T>`].
180/// Finalized values ([`Finalized`]) break,
181/// working values ([`Working`]) continue.
182impl<T> Try for Finalizable<T> {
183    type Output = T;
184    type Residual = Residual<T>;
185    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
186        match self {
187            Working(x) => ControlFlow::Continue(x),
188            Finalized(x) => ControlFlow::Break(Residual(x)),
189        }
190    }
191    fn from_output(output: Self::Output) -> Self {
192        Working(output)
193    }
194}
195
196#[cfg(feature = "try")]
197impl<T> FromResidual for Finalizable<T> {
198    fn from_residual(residual: <Self as Try>::Residual) -> Self {
199        Finalized(residual.0)
200    }
201}
202
203#[cfg(feature = "try")]
204/// The residual from applying `?` to a finalized value ([`Finalized`]).
205/// Used in the implementation of [`Try`] for [`Finalizable`].
206pub struct Residual<T>(pub T);