Skip to main content

molframe_core/topology/
model.rs

1//! The models of a structure, in deposition order.
2
3use super::csr::stored_range;
4use crate::index::ModelIndex;
5use crate::limits::{CapacityError, TableError};
6use std::ops::Range;
7use std::sync::Arc;
8
9/// The models of a structure, in deposition order.
10#[derive(Clone, Debug, Default)]
11pub struct ModelTable {
12    first_chain: Arc<Vec<u32>>,
13    chain_count: Arc<Vec<u32>>,
14    model_num: Arc<Vec<i32>>,
15}
16
17impl ModelTable {
18    /// The number of models.
19    #[must_use]
20    pub fn len(&self) -> usize {
21        self.model_num.len()
22    }
23
24    /// Returns true when the structure has no models.
25    #[must_use]
26    pub fn is_empty(&self) -> bool {
27        self.model_num.is_empty()
28    }
29
30    /// Appends a model covering a range of chains.
31    ///
32    /// # Errors
33    ///
34    /// Returns [`TableError`] for a reversed range or exhausted index space.
35    pub fn push(&mut self, model_num: i32, chains: Range<u32>) -> Result<ModelIndex, TableError> {
36        let position = u32::try_from(self.model_num.len())
37            .map_err(|_| TableError::Capacity(CapacityError::new("model table")))?;
38        let chain_count = chains
39            .end
40            .checked_sub(chains.start)
41            .ok_or(TableError::ReversedRange { table: "model" })?;
42        Arc::make_mut(&mut self.first_chain).push(chains.start);
43        Arc::make_mut(&mut self.chain_count).push(chain_count);
44        Arc::make_mut(&mut self.model_num).push(model_num);
45        Ok(ModelIndex::new(position))
46    }
47
48    /// The number the model was deposited under.
49    ///
50    /// Never renumbered. A file whose models are 1, 5 and 7 keeps those numbers,
51    /// because a result that cites model 5 must mean the same model the
52    /// depositor called 5.
53    #[must_use]
54    pub fn model_num(&self, model: ModelIndex) -> Option<i32> {
55        self.model_num.get(model.as_usize()).copied()
56    }
57
58    /// The chains this model contains.
59    #[must_use]
60    pub fn chains(&self, model: ModelIndex) -> Option<Range<u32>> {
61        stored_range(&self.first_chain, &self.chain_count, model.as_usize())
62    }
63
64    /// Every model position.
65    ///
66    pub fn iter(&self) -> impl Iterator<Item = ModelIndex> + '_ {
67        self.model_num
68            .iter()
69            .enumerate()
70            .filter_map(|(position, _)| u32::try_from(position).ok().map(ModelIndex::new))
71    }
72}