pub enum Extended<T> {
NegInf,
Finite(T),
PosInf,
}Expand description
A totally-ordered T extended with synthetic NegInf (bottom) and
PosInf (top) sentinels.
Used as the target of connections whose source type cannot fit
inside the destination — e.g. an Extended<i8> → i16 widening lifts
the source’s MIN/MAX into the open interval (NegInf, PosInf),
leaving the synthetic markers free to record overflow on the way
back through inner. The order is NegInf < every Finite(t) < PosInf,
making Extended<T> a bounded total order whenever T is one.
Extended is a pure range-extension wrapper; it does not encode
float NaN. NaN-bearing types live in
crate::float::N5, which is a transparent float newtype that
threads NaN through the N5 lattice.
Variants§
NegInf
Synthetic bottom: less than every Finite(t) and less than PosInf.
Finite(T)
A value of the underlying type, with its native order.
PosInf
Synthetic top: greater than every Finite(t) and greater than NegInf.
Implementations§
Source§impl<T> Extended<T>
impl<T> Extended<T>
Sourcepub fn fold<U>(self, neg_inf: U, pos_inf: U, f: impl FnOnce(T) -> U) -> U
pub fn fold<U>(self, neg_inf: U, pos_inf: U, f: impl FnOnce(T) -> U) -> U
Catamorphism: collapse an Extended<T> to a U by supplying
one value per variant.
The Rust analogue of Haskell’s
extended :: Extended a -> b -> b -> (a -> b) -> b. Argument
order follows Rust’s closure-last convention
(Iterator::fold, Option::map_or).
Endpoint arms are evaluated eagerly. For lazy endpoints, see
Extended::fold_with.
use connections::extended::Extended;
fn classify(x: Extended<i64>) -> &'static str {
x.fold("below", "above", |_| "in range")
}
assert_eq!(classify(Extended::NegInf), "below");
assert_eq!(classify(Extended::Finite(7)), "in range");
assert_eq!(classify(Extended::PosInf), "above");Sourcepub fn fold_with<U>(
self,
neg_inf: impl FnOnce() -> U,
pos_inf: impl FnOnce() -> U,
f: impl FnOnce(T) -> U,
) -> U
pub fn fold_with<U>( self, neg_inf: impl FnOnce() -> U, pos_inf: impl FnOnce() -> U, f: impl FnOnce(T) -> U, ) -> U
Lazy variant of Extended::fold: all three arms are wrapped
in FnOnce closures and only the matched arm is called.
Use when any endpoint default is expensive to compute.
Sourcepub const fn finite(self) -> Option<T>where
T: Copy,
pub const fn finite(self) -> Option<T>where
T: Copy,
Project to the wrapped value, discarding the synthetic bounds:
Some(t) for Finite, None for
NegInf / PosInf.
This is the forgetful half of the Extended<T> → Option<T>
projection: it is lossy on which bound was hit — both
NegInf and PosInf collapse to None. When the endpoint
identity matters, use fold, or (with the
try_trait feature) the ? operator, which propagates the
specific bound through Extended’s FromResidual impl.
The T: Copy bound is what lets this be a const fn on stable:
a const fn that consumes a generic enum cannot evaluate its
destructor without the nightly const_precise_live_drops
feature, and Copy types have no destructor. The bound is free
for every Extended<T> used as a Conn endpoint (that machinery
already requires A: Copy, B: Copy), but it does exclude
non-Copy payloads such as Extended<String>. For those, the
equivalent stable — but non-const — projection is
x.fold(None, None, Some), which moves the payload out with no
Copy bound.
use connections::extended::Extended;
assert_eq!(Extended::Finite(7_i32).finite(), Some(7));
assert_eq!(Extended::<i32>::NegInf.finite(), None);
assert_eq!(Extended::<i32>::PosInf.finite(), None);
// Non-`Copy` payloads can't use `finite`; `fold` is the
// bound-free (non-`const`) equivalent:
let s: Option<String> =
Extended::Finite(String::from("hi")).fold(None, None, Some);
assert_eq!(s, Some(String::from("hi")));