molframe_core/topology/
entity.rs1use crate::index::EntityIndex;
15use crate::limits::CapacityError;
16use crate::optional::OptionalSymbol;
17use crate::symbol::SymbolId;
18use std::ops::Range;
19use std::sync::Arc;
20
21#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
23#[non_exhaustive]
24pub enum EntityKind {
25 Polymer,
27 NonPolymer,
29 Water,
31 Branched,
33 #[default]
35 Unknown,
36}
37
38#[derive(Clone, Debug, Default)]
44pub struct EntityTable {
45 kind: Arc<Vec<EntityKind>>,
46 id: Arc<Vec<OptionalSymbol>>,
47 description: Arc<Vec<OptionalSymbol>>,
48 sequence_span: Arc<Vec<Range<u32>>>,
49 sequence_pool: Arc<Vec<SymbolId>>,
50}
51
52impl EntityTable {
53 #[must_use]
55 pub fn len(&self) -> usize {
56 self.kind.len()
57 }
58
59 #[must_use]
61 pub fn is_empty(&self) -> bool {
62 self.kind.is_empty()
63 }
64
65 pub fn push(
71 &mut self,
72 id: SymbolId,
73 kind: EntityKind,
74 description: OptionalSymbol,
75 canonical_sequence: &[SymbolId],
76 ) -> Result<EntityIndex, CapacityError> {
77 self.push_with_optional_id(
78 OptionalSymbol::some(id),
79 kind,
80 description,
81 canonical_sequence,
82 )
83 }
84
85 pub fn push_without_id(
91 &mut self,
92 kind: EntityKind,
93 description: OptionalSymbol,
94 canonical_sequence: &[SymbolId],
95 ) -> Result<EntityIndex, CapacityError> {
96 self.push_with_optional_id(OptionalSymbol::NONE, kind, description, canonical_sequence)
97 }
98
99 fn push_with_optional_id(
100 &mut self,
101 id: OptionalSymbol,
102 kind: EntityKind,
103 description: OptionalSymbol,
104 canonical_sequence: &[SymbolId],
105 ) -> Result<EntityIndex, CapacityError> {
106 let error = || CapacityError::new("entity table");
107 let start = u32::try_from(self.sequence_pool.len()).map_err(|_| error())?;
108 let added = u32::try_from(canonical_sequence.len()).map_err(|_| error())?;
109 let end = start.checked_add(added).ok_or_else(error)?;
110 let position = u32::try_from(self.kind.len()).map_err(|_| error())?;
111 Arc::make_mut(&mut self.sequence_pool).extend_from_slice(canonical_sequence);
112 Arc::make_mut(&mut self.kind).push(kind);
113 Arc::make_mut(&mut self.id).push(id);
114 Arc::make_mut(&mut self.description).push(description);
115 Arc::make_mut(&mut self.sequence_span).push(start..end);
116 Ok(EntityIndex::new(position))
117 }
118
119 #[must_use]
121 pub fn kind(&self, entity: EntityIndex) -> Option<EntityKind> {
122 self.kind.get(entity.as_usize()).copied()
123 }
124
125 #[must_use]
127 pub fn id(&self, entity: EntityIndex) -> Option<SymbolId> {
128 self.id
129 .get(entity.as_usize())
130 .copied()
131 .and_then(OptionalSymbol::get)
132 }
133
134 #[must_use]
141 pub fn find_by_id(&self, id: SymbolId) -> Option<EntityIndex> {
142 self.id
143 .iter()
144 .position(|candidate| candidate.get() == Some(id))
145 .and_then(|position| u32::try_from(position).ok())
146 .map(EntityIndex::new)
147 }
148
149 #[must_use]
151 pub fn description(&self, entity: EntityIndex) -> Option<SymbolId> {
152 self.description
153 .get(entity.as_usize())
154 .copied()
155 .and_then(OptionalSymbol::get)
156 }
157
158 #[must_use]
163 pub fn canonical_sequence(&self, entity: EntityIndex) -> &[SymbolId] {
164 let Some(span) = self.sequence_span.get(entity.as_usize()) else {
165 return &[];
166 };
167
168 sequence_slice(&self.sequence_pool, span)
169 }
170
171 pub fn iter(&self) -> impl Iterator<Item = EntityIndex> + '_ {
174 self.kind
175 .iter()
176 .enumerate()
177 .filter_map(|(position, _)| u32::try_from(position).ok().map(EntityIndex::new))
178 }
179}
180
181fn sequence_slice<'a>(pool: &'a [SymbolId], span: &Range<u32>) -> &'a [SymbolId] {
182 let Ok(start) = usize::try_from(span.start) else {
183 return &[];
184 };
185 let Ok(end) = usize::try_from(span.end) else {
186 return &[];
187 };
188
189 match pool.get(start..end) {
190 Some(sequence) => sequence,
191 None => &[],
192 }
193}