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;