Skip to main content

few/
lib.rs

1////////////////////////////////////////////////////////////////////////////////
2// Few -- A generalization of `std::Option` allowing for up to two optional
3// values.
4////////////////////////////////////////////////////////////////////////////////
5// Copyright 2020 Skylor R. Schermer
6// This code is dual licenced using the MIT or Apache 2 license.
7// See licence-mit.md and licence-apache.md for details.
8////////////////////////////////////////////////////////////////////////////////
9//! A generalization of `std::Option` allowing for up to two optional values.
10//! 
11//! This library provides a `Few` enum with three variants:
12//! 
13//! ```rust
14//! pub enum Few<T> {
15//!     Zero,
16//!     One(T),
17//!     Two(T, T),
18//! }
19//! ```
20//! 
21//! Very few methods are defined for it, and for most purposes, [`std::Option`],
22//! [`std::Vec`], or [`smallvec`] should be used instead. This library was
23//! developed to provide a data structure for pattern matching on the result of
24//! set-like `intersect`, `union`, and `minus` operations over contiguous
25//! ranges.
26//!
27//! # Features
28//!
29//! | Feature | Description |
30//! | ------- | ----------- |
31//! | "serde" | Enables serialization and deserialization of data using [serde](https://crates.io/crates/serde). |
32//!
33//! By default, there are no features enabled.
34//!
35//! [`std::Option`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html
36//! [`std::Vec`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html
37//! [`smallvec`]: https://crates.io/crates/smallvec
38////////////////////////////////////////////////////////////////////////////////
39#![warn(anonymous_parameters)]
40#![warn(bad_style)]
41#![warn(bare_trait_objects)]
42#![warn(const_err)]
43#![warn(dead_code)]
44#![warn(elided_lifetimes_in_paths)]
45#![warn(improper_ctypes)]
46#![warn(missing_copy_implementations)]
47#![warn(missing_debug_implementations)]
48#![warn(missing_doc_code_examples)]
49#![warn(missing_docs)]
50#![warn(no_mangle_generic_items)]
51#![warn(non_shorthand_field_patterns)]
52#![warn(nonstandard_style)]
53#![warn(overflowing_literals)]
54#![warn(path_statements)]
55#![warn(patterns_in_fns_without_body)]
56#![warn(private_in_public)]
57#![warn(rust_2018_idioms)]
58#![warn(trivial_casts)]
59#![warn(trivial_numeric_casts)]
60#![warn(unconditional_recursion)]
61#![warn(unreachable_pub)]
62#![warn(unused)]
63#![warn(unused_allocation)]
64#![warn(unused_comparisons)]
65#![warn(unused_parens)]
66#![warn(unused_qualifications)]
67#![warn(unused_results)]
68#![warn(variant_size_differences)]
69#![warn(while_true)]
70
71// External library imports.
72#[cfg(feature = "serde")]
73use serde::{ Serialize, Deserialize };
74
75
76////////////////////////////////////////////////////////////////////////////////
77// Few
78////////////////////////////////////////////////////////////////////////////////
79/// A type which may contain zero, one, or two of a value.
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
81#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
82pub enum Few<T> {
83    /// No value present.
84    Zero,
85    /// One value present.
86    One(T),
87    /// Two values present.
88    Two(T, T),
89}
90
91impl<T> Few<T> {
92    /// Returns true if the `Few` is a `Zero` value.
93    pub fn is_zero(&self) -> bool {
94        match self {
95            Few::Zero => true,
96            _         => false,
97        }
98    }
99
100    /// Returns true if the `Few` is a `One` value.
101    pub fn is_one(&self) -> bool {
102        match self {
103            Few::One(_) => true,
104            _           => false,
105        }
106    }
107
108    /// Returns true if the `Few` is a `Two` value.
109    pub fn is_two(&self) -> bool {
110        match self {
111            Few::Two(_, _) => true,
112            _              => false,
113        }
114    }
115
116    /// Returns true if the `Few` is a `One` or `Two` value containing the given
117    /// value.
118    pub fn contains<U>(&self, x: &U) -> bool
119        where U: PartialEq<T>
120    {
121        match self {
122            Few::Zero      => false,
123            Few::One(v)    => x == v,
124            Few::Two(a, b) => x == a || x == b,
125        }
126    }
127
128    /// Maps a `Few<T>` to `Few<U>` by applying a function to a contained value.
129    pub fn map<F, U>(self, mut f: F) -> Few<U>
130        where F: FnMut(T) -> U,
131    {
132        match self {
133            Few::Zero      => Few::Zero,
134            Few::One(v)    => Few::One((f)(v)),
135            Few::Two(a, b) => Few::Two((f)(a), (f)(b)),
136        }
137    }
138}
139
140impl<T> Iterator for Few<T> {
141    type Item = T;
142
143    fn next(&mut self) -> Option<T> {
144        let mut res = None;
145        replace_with(self, |curr|
146            match curr {
147                Few::Zero      => { res = None;    Few::Zero },
148                Few::One(v)    => { res = Some(v); Few::Zero },
149                Few::Two(a, b) => { res = Some(a); Few::One(b) },
150            }
151        );
152        res
153    }
154}
155
156impl<T> DoubleEndedIterator for Few<T> {
157    fn next_back(&mut self) -> Option<T> {
158        let mut res = None;
159        replace_with(self, |curr|
160            match curr {
161                Few::Zero      => { res = None;    Few::Zero },
162                Few::One(v)    => { res = Some(v); Few::Zero },
163                Few::Two(a, b) => { res = Some(b); Few::One(a) },
164            }
165        );
166        res
167    }
168}
169
170impl<T> ExactSizeIterator for Few<T> {
171    fn len(&self) -> usize {
172        match self {
173            Few::Zero      => 0,
174            Few::One(_)    => 1,
175            Few::Two(_, _) => 2,
176        }
177    }
178}
179
180impl<T> std::iter::FusedIterator for Few<T> {}
181
182
183impl<T> Default for Few<T> {
184    fn default() -> Self {
185        Few::Zero
186    }
187}
188
189impl<T> From<T> for Few<T> {
190    fn from(value: T) -> Self {
191        Few::One(value)
192    }
193}
194
195impl<T> From<(T, T)> for Few<T> {
196    fn from(value: (T, T)) -> Self {
197        Few::Two(value.0, value.1)
198    }
199}
200
201impl<T> From<Option<T>> for Few<T> {
202    fn from(value: Option<T>) -> Self {
203        match value {
204            None        => Few::Zero,
205            Some(value) => Few::One(value),
206        }
207    }
208}
209
210impl<T> From<Option<(T, T)>> for Few<T> {
211    fn from(value: Option<(T, T)>) -> Self {
212        match value {
213            None         => Few::Zero,
214            Some((a, b)) => Few::Two(a, b),
215        }
216    }
217}
218
219impl<T> From<(Option<T>, Option<T>)> for Few<T> {
220    fn from(value: (Option<T>, Option<T>)) -> Self {
221        match (value.0, value.1) {
222            (None,    None)    => Few::Zero,
223            (Some(a), None)    => Few::One(a),
224            (None,    Some(b)) => Few::One(b),
225            (Some(a), Some(b)) => Few::Two(a, b),
226        }
227    }
228}
229
230impl<T> Into<Option<(T, T)>> for Few<T> where T: Clone {
231    fn into(self) -> Option<(T, T)> {
232        match self {
233            Few::Zero      => None,
234            Few::One(v)    => Some((v.clone(), v)),
235            Few::Two(a, b) => Some((a, b)),
236        }
237    }
238}
239
240
241////////////////////////////////////////////////////////////////////////////////
242// replace_with
243////////////////////////////////////////////////////////////////////////////////
244/// Replaces the value behind a mut reference with the result of a closure
245/// called on the value. Will abort if a panic occurs in the given closure.
246#[inline]
247fn replace_with<T, F>(val: &mut T, replace: F)
248    where F: FnOnce(T) -> T {
249    let guard = ExitGuard;
250
251    unsafe {
252        let old = std::ptr::read(val);
253        let new = replace(old);
254        std::ptr::write(val, new);
255    }
256
257    std::mem::forget(guard);
258}
259
260struct ExitGuard;
261
262impl Drop for ExitGuard {
263    fn drop(&mut self) {
264        panic!("`replace_with` closure unwind");
265    }
266}