use crate::facade::unsupported;
use crate::structure::Structure;
use molframe_core::diagnostic::{Code, Diagnostic, Findings};
use molframe_core::io::{Format, InputBuffer, Limits};
use std::io;
use std::io::Write;
use std::path::Path;
pub fn read_document(path: impl AsRef<Path>) -> Result<molframe_cif::Document, Findings> {
let path = path.as_ref();
let input = InputBuffer::open(path, Limits::default()).map_err(Findings::from)?;
let name = path.file_name().and_then(|name| name.to_str());
let format = Format::detect(Format::Auto, &input, name).map_err(Findings::from)?;
match format {
Format::Mmcif => molframe_cif::parse(&input)
.map(|(document, _)| document)
.map_err(Findings::from),
Format::Pdbml => molframe_cif::parse_pdbml_document(input.as_bytes()).map_err(|error| {
Findings::from(Diagnostic::new(Code::E1102).with_message(error.to_string()))
}),
#[cfg(feature = "bcif")]
Format::BinaryCif => molframe_bcif::read_document(&input, Limits::default())
.and_then(|document| document.to_document())
.map_err(Findings::from),
other => Err(unsupported(other).into()),
}
}
pub fn write_mmcif(structure: &Structure) -> Result<String, Findings> {
write_mmcif_with_options(structure, &molframe_cif::CifWriteOptions::new())
}
pub fn write_mmcif_with_options(
structure: &Structure,
options: &molframe_cif::CifWriteOptions,
) -> Result<String, Findings> {
let mut output = Vec::with_capacity(structure.atom_count() as usize * 100);
write_mmcif_to_with_options(structure, options, &mut output)
.map_err(|error| cif_write_findings(&error))?;
String::from_utf8(output).map_err(|error| {
cif_write_findings(&molframe_cif::CifWriteToError::Output(io::Error::new(
io::ErrorKind::InvalidData,
error,
)))
})
}
pub(crate) fn write_mmcif_to_with_options<W: Write>(
structure: &Structure,
options: &molframe_cif::CifWriteOptions,
output: &mut W,
) -> Result<(), molframe_cif::CifWriteToError> {
#[cfg(feature = "modelcif")]
if let Some(model) = structure
.engine()
.extensions()
.get::<molframe_modelcif::ModelCif>(molframe_modelcif::MODEL_CIF_EXTENSION)
{
return molframe_modelcif::write_canonical_to(structure.engine(), model, options, output);
}
molframe_cif::write_canonical_to(structure.engine(), options, output)
}
pub(crate) fn cif_write_findings(error: &molframe_cif::CifWriteToError) -> Findings {
match error {
molframe_cif::CifWriteToError::Projection(error) => Diagnostic::new(Code::E4105)
.with_message("structure cannot be projected to canonical CIF")
.with_context("reason", error.to_string()),
molframe_cif::CifWriteToError::Output(error) => Diagnostic::new(Code::E7901)
.with_message("canonical CIF output failed")
.with_context("reason", error.to_string()),
}
.into()
}