use crate::column::Presence;
use crate::execution::Batch;
use crate::optional::OptionalSymbol;
use crate::provider::{ChunkDescriptor, ProviderError};
use crate::symbol::{AltId, DictionaryFull, Interner, SymbolId};
use crate::{Diagnostic, Element};
use std::fmt;
#[derive(Debug)]
pub enum StructureBatchError {
Diagnostic(Diagnostic),
DemandTooSmall {
required: usize,
available: usize,
},
RecordExceedsBudget {
required: usize,
available: usize,
},
Identity(ProviderError),
Memory(crate::MemoryBudgetError),
DictionaryFull,
}
impl fmt::Display for StructureBatchError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Diagnostic(error) => error.fmt(formatter),
Self::DemandTooSmall {
required,
available,
} => write!(
formatter,
"record requires {required} bytes but demand permits {available}"
),
Self::RecordExceedsBudget {
required,
available,
} => write!(
formatter,
"record requires {required} bytes but budget permits {available}"
),
Self::Identity(error) => error.fmt(formatter),
Self::Memory(error) => error.fmt(formatter),
Self::DictionaryFull => formatter.write_str("batch identifier dictionary is full"),
}
}
}
impl std::error::Error for StructureBatchError {}
impl From<Diagnostic> for StructureBatchError {
fn from(error: Diagnostic) -> Self {
Self::Diagnostic(error)
}
}
impl From<ProviderError> for StructureBatchError {
fn from(error: ProviderError) -> Self {
Self::Identity(error)
}
}
impl From<DictionaryFull> for StructureBatchError {
fn from(_: DictionaryFull) -> Self {
Self::DictionaryFull
}
}
impl From<crate::MemoryBudgetError> for StructureBatchError {
fn from(error: crate::MemoryBudgetError) -> Self {
Self::Memory(error)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ContinuityLevel {
#[default]
None,
Model,
Chain,
Residue,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct BatchContinuity {
pub before: ContinuityLevel,
pub after: ContinuityLevel,
}
#[derive(Clone, Copy, Debug)]
pub struct StructureAtomRecord<'a> {
pub model: i32,
pub chain: &'a str,
pub component: &'a str,
pub sequence: i32,
pub insertion: &'a str,
pub atom: &'a str,
pub alternate: &'a str,
pub element: Element,
pub position: Option<[f32; 3]>,
pub occupancy: (f32, Presence),
pub b_factor: (f32, Presence),
pub formal_charge: (i8, Presence),
pub atom_site_id: u32,
pub heterogen: bool,
}
#[derive(Clone, Debug)]
pub struct StructureBatch {
pub(super) descriptor: ChunkDescriptor,
pub(super) continuity: BatchContinuity,
pub(super) dictionary: Interner,
pub(super) model: Vec<i32>,
pub(super) chain: Vec<SymbolId>,
pub(super) component: Vec<SymbolId>,
pub(super) sequence: Vec<i32>,
pub(super) insertion: Vec<OptionalSymbol>,
pub(super) atom: Vec<SymbolId>,
pub(super) alternate: Vec<AltId>,
pub(super) element: Vec<u8>,
pub(super) position: Vec<[f32; 3]>,
pub(super) coordinate_presence: Vec<Presence>,
pub(super) occupancy: Vec<f32>,
pub(super) occupancy_presence: Vec<Presence>,
pub(super) b_factor: Vec<f32>,
pub(super) b_factor_presence: Vec<Presence>,
pub(super) formal_charge: Vec<i8>,
pub(super) formal_charge_presence: Vec<Presence>,
pub(super) atom_site_id: Vec<u32>,
pub(super) heterogen: Vec<u8>,
pub(super) diagnostics: Vec<Diagnostic>,
}
impl StructureBatch {
#[must_use]
pub fn can_reuse(&self, rows: u32, max_retained_bytes: usize) -> bool {
let rows = rows as usize;
self.model.capacity() >= rows && self.retained_bytes() <= max_retained_bytes
}
#[must_use]
pub const fn descriptor(&self) -> ChunkDescriptor {
self.descriptor
}
#[must_use]
pub const fn continuity(&self) -> BatchContinuity {
self.continuity
}
#[must_use]
pub const fn dictionary(&self) -> &Interner {
&self.dictionary
}
#[must_use]
pub fn models(&self) -> &[i32] {
&self.model
}
#[must_use]
pub fn chains(&self) -> &[SymbolId] {
&self.chain
}
#[must_use]
pub fn components(&self) -> &[SymbolId] {
&self.component
}
#[must_use]
pub fn sequences(&self) -> &[i32] {
&self.sequence
}
#[must_use]
pub fn insertions(&self) -> &[OptionalSymbol] {
&self.insertion
}
#[must_use]
pub fn atoms(&self) -> &[SymbolId] {
&self.atom
}
#[must_use]
pub fn alternates(&self) -> &[AltId] {
&self.alternate
}
#[must_use]
pub fn elements(&self) -> &[u8] {
&self.element
}
#[must_use]
pub fn positions(&self) -> &[[f32; 3]] {
&self.position
}
#[must_use]
pub fn coordinate_presence(&self) -> &[Presence] {
&self.coordinate_presence
}
#[must_use]
pub fn occupancies(&self) -> (&[f32], &[Presence]) {
(&self.occupancy, &self.occupancy_presence)
}
#[must_use]
pub fn b_factors(&self) -> (&[f32], &[Presence]) {
(&self.b_factor, &self.b_factor_presence)
}
#[must_use]
pub fn formal_charges(&self) -> (&[i8], &[Presence]) {
(&self.formal_charge, &self.formal_charge_presence)
}
#[must_use]
pub fn atom_site_ids(&self) -> &[u32] {
&self.atom_site_id
}
#[must_use]
pub fn heterogens(&self) -> &[u8] {
&self.heterogen
}
#[must_use]
pub fn diagnostics(&self) -> &[Diagnostic] {
&self.diagnostics
}
}
impl Batch for StructureBatch {
fn rows(&self) -> usize {
self.model.len()
}
fn retained_bytes(&self) -> usize {
let mut bytes = self.dictionary.retained_bytes();
bytes = bytes.saturating_add(self.model.capacity_bytes());
bytes = bytes.saturating_add(self.chain.capacity_bytes());
bytes = bytes.saturating_add(self.component.capacity_bytes());
bytes = bytes.saturating_add(self.sequence.capacity_bytes());
bytes = bytes.saturating_add(self.insertion.capacity_bytes());
bytes = bytes.saturating_add(self.atom.capacity_bytes());
bytes = bytes.saturating_add(self.alternate.capacity_bytes());
bytes = bytes.saturating_add(self.element.capacity_bytes());
bytes = bytes.saturating_add(self.position.capacity_bytes());
bytes = bytes.saturating_add(self.coordinate_presence.capacity_bytes());
bytes = bytes.saturating_add(self.occupancy.capacity_bytes());
bytes = bytes.saturating_add(self.occupancy_presence.capacity_bytes());
bytes = bytes.saturating_add(self.b_factor.capacity_bytes());
bytes = bytes.saturating_add(self.b_factor_presence.capacity_bytes());
bytes = bytes.saturating_add(self.formal_charge.capacity_bytes());
bytes = bytes.saturating_add(self.formal_charge_presence.capacity_bytes());
bytes = bytes.saturating_add(self.atom_site_id.capacity_bytes());
bytes = bytes.saturating_add(self.heterogen.capacity_bytes());
bytes = bytes.saturating_add(self.diagnostics.capacity_bytes());
bytes.saturating_add(
self.diagnostics
.iter()
.map(Diagnostic::retained_bytes)
.sum::<usize>(),
)
}
}
trait VecCapacityBytes {
fn capacity_bytes(&self) -> usize;
}
impl<T> VecCapacityBytes for Vec<T> {
fn capacity_bytes(&self) -> usize {
self.capacity().saturating_mul(std::mem::size_of::<T>())
}
}