Skip to main content

molframe_core/optional/
value.rs

1//! Absent-or-present values that cost no more than a present one.
2//!
3//! A great many identifier columns are genuinely optional: a file may or may not
4//! carry the depositor's own chain label, and a component that is not part of a
5//! polymer has no sequence position. `Option` doubles the width of those columns
6//! because a 32-bit identifier has no spare bit pattern for the tag.
7//!
8//! These types reserve one value instead. At a residue table of a hundred
9//! thousand rows and three such columns, that is the difference between one and
10//! two megabytes — memory that geometric kernels would otherwise have as cache.
11//!
12//! The reserved values are chosen where no real datum can land: an identifier
13//! is never `u32::MAX` because the dictionary refuses to grow that far, and a
14//! sequence position is never `i32::MIN`.
15
16use crate::symbol::SymbolId;
17use std::fmt;
18
19/// An interned identifier that may be absent.
20///
21/// # Examples
22///
23/// ```
24/// use molframe_core::{Interner, OptionalSymbol};
25///
26/// let mut interner = Interner::new();
27/// let present = OptionalSymbol::some(interner.intern("A")?);
28///
29/// assert!(present.get().is_some());
30/// assert_eq!(OptionalSymbol::NONE.get(), None);
31/// assert_eq!(size_of::<OptionalSymbol>(), 4);
32/// # Ok::<(), molframe_core::DictionaryFull>(())
33/// ```
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35#[repr(transparent)]
36pub struct OptionalSymbol(u32);
37
38impl OptionalSymbol {
39    /// The value is absent.
40    pub const NONE: Self = Self(u32::MAX);
41
42    /// Wraps a present identifier.
43    #[must_use]
44    pub const fn some(symbol: SymbolId) -> Self {
45        Self(symbol.get())
46    }
47
48    /// The identifier, if present.
49    #[must_use]
50    pub const fn get(self) -> Option<SymbolId> {
51        if self.0 == u32::MAX {
52            None
53        } else {
54            Some(SymbolId::from_raw(self.0))
55        }
56    }
57
58    /// Returns true when no identifier is held.
59    #[must_use]
60    pub const fn is_none(self) -> bool {
61        self.0 == u32::MAX
62    }
63
64    /// Returns true when an identifier is held.
65    #[must_use]
66    pub const fn is_some(self) -> bool {
67        self.0 != u32::MAX
68    }
69}
70
71impl Default for OptionalSymbol {
72    fn default() -> Self {
73        Self::NONE
74    }
75}
76
77impl From<Option<SymbolId>> for OptionalSymbol {
78    fn from(symbol: Option<SymbolId>) -> Self {
79        match symbol {
80            Some(symbol) => Self::some(symbol),
81            None => Self::NONE,
82        }
83    }
84}
85
86impl From<OptionalSymbol> for Option<SymbolId> {
87    fn from(optional: OptionalSymbol) -> Self {
88        optional.get()
89    }
90}
91
92impl fmt::Debug for OptionalSymbol {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        match self.get() {
95            Some(symbol) => write!(f, "Some({symbol:?})"),
96            None => f.write_str("None"),
97        }
98    }
99}
100
101/// A signed number that may be absent.
102///
103/// Sequence positions and the depositor's own residue numbers use this: both
104/// are genuinely optional, and both may legitimately be negative, so the
105/// reserved value is the one no numbering scheme reaches.
106///
107/// # Examples
108///
109/// ```
110/// use molframe_core::OptionalI32;
111///
112/// assert_eq!(OptionalI32::some(-5).get(), Some(-5));
113/// assert_eq!(OptionalI32::NONE.get(), None);
114/// assert_eq!(size_of::<OptionalI32>(), 4);
115/// ```
116#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
117#[repr(transparent)]
118pub struct OptionalI32(i32);
119
120impl OptionalI32 {
121    /// The value is absent.
122    pub const NONE: Self = Self(i32::MIN);
123
124    /// Wraps a present value.
125    ///
126    /// The reserved value maps to absent, which is the only lossy case and is
127    /// unreachable for any real numbering.
128    #[must_use]
129    pub const fn some(value: i32) -> Self {
130        Self(value)
131    }
132
133    /// The value, if present.
134    #[must_use]
135    pub const fn get(self) -> Option<i32> {
136        if self.0 == i32::MIN {
137            None
138        } else {
139            Some(self.0)
140        }
141    }
142
143    /// Returns true when no value is held.
144    #[must_use]
145    pub const fn is_none(self) -> bool {
146        self.0 == i32::MIN
147    }
148
149    /// Returns true when a value is held.
150    #[must_use]
151    pub const fn is_some(self) -> bool {
152        self.0 != i32::MIN
153    }
154}
155
156impl Default for OptionalI32 {
157    fn default() -> Self {
158        Self::NONE
159    }
160}
161
162impl From<Option<i32>> for OptionalI32 {
163    fn from(value: Option<i32>) -> Self {
164        match value {
165            Some(value) => Self::some(value),
166            None => Self::NONE,
167        }
168    }
169}
170
171impl From<OptionalI32> for Option<i32> {
172    fn from(optional: OptionalI32) -> Self {
173        optional.get()
174    }
175}
176
177impl fmt::Debug for OptionalI32 {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        match self.get() {
180            Some(value) => write!(f, "Some({value})"),
181            None => f.write_str("None"),
182        }
183    }
184}
185
186#[cfg(test)]
187#[path = "value_tests.rs"]
188mod tests;