#[macro_use]
extern crate nom;
#[macro_use]
pub mod basic;
#[macro_use]
pub mod model;
pub mod parser;
pub mod writer;
#[cfg(feature = "xml")]
pub mod xml;
#[cfg(feature = "xml")]
use std::convert::{TryFrom, TryInto};
use std::fs::File;
#[cfg(feature = "xml")]
use std::io::BufRead;
use std::io::{self, BufWriter, Read, Write};
use std::path::Path;
use crate::writer::{AsciiWriter, BinaryWriter, WriteVtk};
pub use model::IOBuffer;
pub use model::Vtk;
#[derive(Debug)]
pub enum Error {
IO(io::Error),
Write(writer::Error),
Parse(nom::ErrorKind<u32>),
#[cfg(feature = "xml")]
XML(xml::Error),
UnknownFileExtension(Option<String>),
Load(model::Error),
Unknown,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Error::IO(source) => write!(f, "IO error: {}", source),
Error::Write(source) => write!(f, "Write error: {}", source),
Error::Parse(source) => write!(f, "Parse error: {:?}", source),
#[cfg(feature = "xml")]
Error::XML(source) => write!(f, "XML error: {}", source),
Error::UnknownFileExtension(Some(ext)) => {
write!(f, "Unknown file extension: {:?}", ext)
}
Error::UnknownFileExtension(None) => write!(f, "Missing file extension"),
Error::Load(source) => write!(f, "Load error: {}", source),
Error::Unknown => write!(f, "Unknown error"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::IO(source) => Some(source),
Error::Write(source) => Some(source),
Error::Parse(_) => None,
#[cfg(feature = "xml")]
Error::XML(source) => Some(source),
Error::UnknownFileExtension(_) => None,
Error::Load(source) => Some(source),
Error::Unknown => None,
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error::IO(e)
}
}
#[cfg(feature = "xml")]
impl From<xml::Error> for Error {
fn from(e: xml::Error) -> Error {
Error::XML(e)
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> io::Error {
match err {
Error::IO(e) => e,
_ => io::Error::new(io::ErrorKind::Other, format!("{:?}", err)),
}
}
}
impl From<writer::Error> for Error {
fn from(e: writer::Error) -> Error {
Error::Write(e)
}
}
impl Vtk {
fn parse_vtk<F>(mut reader: impl Read, parse: F, buf: &mut Vec<u8>) -> Result<Vtk, Error>
where
F: Fn(&[u8]) -> nom::IResult<&[u8], Vtk>,
{
use nom::IResult;
reader.read_to_end(buf)?;
match parse(buf) {
IResult::Done(_, vtk) => Ok(vtk),
IResult::Error(e) => Err(Error::Parse(e.into_error_kind())),
IResult::Incomplete(_) => Err(Error::Unknown),
}
}
fn import_vtk<F>(file_path: &Path, parse: F) -> Result<Vtk, Error>
where
F: Fn(&[u8]) -> nom::IResult<&[u8], Vtk>,
{
let file = File::open(file_path)?;
Vtk::parse_vtk(file, parse, &mut Vec::new())
}
pub fn parse_legacy_be(reader: impl Read) -> Result<Vtk, Error> {
Vtk::parse_vtk(reader, parser::parse_be, &mut Vec::new())
}
pub fn parse_legacy_le(reader: impl Read) -> Result<Vtk, Error> {
Vtk::parse_vtk(reader, parser::parse_le, &mut Vec::new())
}
pub fn parse_legacy_buf_be(reader: impl Read, buf: &mut Vec<u8>) -> Result<Vtk, Error> {
Vtk::parse_vtk(reader, parser::parse_be, buf)
}
pub fn parse_legacy_buf_le(reader: impl Read, buf: &mut Vec<u8>) -> Result<Vtk, Error> {
Vtk::parse_vtk(reader, parser::parse_le, buf)
}
#[cfg(feature = "xml")]
pub fn parse_xml(reader: impl BufRead) -> Result<Vtk, Error> {
let vtk_file = xml::parse(reader)?;
Ok(vtk_file.try_into()?)
}
#[cfg(feature = "async_blocked")]
async fn import_vtk_async<F>(file_path: &Path, parse: F) -> Result<Vtk, Error>
where
F: Fn(&[u8]) -> nom::IResult<&[u8], Vtk>,
{
use nom::IResult;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
let mut file = File::open(file_path).await?;
let mut buf = Vec::new();
file.read_to_end(&mut buf).await?;
match parse(&buf) {
IResult::Done(_, vtk) => Ok(vtk),
IResult::Error(e) => Err(Error::Parse(e.into_error_kind())),
IResult::Incomplete(_) => Err(Error::Unknown),
}
}
pub fn import(file_path: impl AsRef<Path>) -> Result<Vtk, Error> {
Vtk::import_impl(file_path.as_ref())
}
fn import_impl(path: &Path) -> Result<Vtk, Error> {
let ext = path
.extension()
.and_then(|s| s.to_str())
.ok_or(Error::UnknownFileExtension(None))?;
match ext {
"vtk" => Vtk::import_vtk(path, parser::parse_be),
#[cfg(feature = "xml")]
ext => {
let ft = xml::FileType::try_from_ext(ext)
.ok_or(Error::UnknownFileExtension(Some(ext.to_string())))?;
let vtk_file = xml::import(path)?;
let exp_ft = xml::FileType::from(vtk_file.data_set_type);
if ft != exp_ft {
Err(Error::XML(xml::Error::TypeExtensionMismatch))
} else {
let mut vtk: Vtk = vtk_file.try_into()?;
vtk.file_path = Some(path.into());
Ok(vtk)
}
}
#[cfg(not(feature = "xml"))]
_ => Err(Error::UnknownFileExtension(None)),
}
}
#[cfg(feature = "async_blocked")]
pub async fn import_async(file_path: impl AsRef<Path>) -> Result<Vtk, Error> {
let path = file_path.as_ref();
let ext = path.extension().and_then(|s| s.to_str()).ok_or()?;
match ext {
"vtk" => import_vtk_async(path, parser::parse_be).await,
#[cfg(feature = "xml")]
ext => {
let ft = xml::FileType::try_from_ext(ext)
.ok_or(Error::UnknownFileExtension(Some(ext.to_string())))?;
let vtk_file = xml::import_async(path).await?;
let exp_ft = xml::FileType::from(vtk_file.data_set_type);
if ft != exp_ft {
Err(Error::XML(xml::Error::TypeExtensionMismatch))
} else {
Ok(vtk_file.try_into()?)
}
}
#[cfg(not(feature = "xml"))]
_ => Err(Error::UnknownFileExtension(None)),
}
}
#[cfg(feature = "unstable")]
pub fn import_xml(file_path: impl AsRef<Path>) -> Result<xml::VTKFile, Error> {
let path = file_path.as_ref();
let ext = path
.extension()
.and_then(|s| s.to_str())
.ok_or(Error::UnknownFileExtension(None))?;
let _ = xml::FileType::try_from_ext(ext)
.ok_or(Error::UnknownFileExtension(Some(ext.to_string())))?;
Ok(xml::import(path)?)
}
pub fn import_legacy_le(file_path: impl AsRef<Path>) -> Result<Vtk, Error> {
Vtk::import_vtk(file_path.as_ref(), parser::parse_le)
}
#[deprecated(since = "0.6.2", note = "Please use Vtk::import_legacy_le instead")]
pub fn import_le(file_path: impl AsRef<Path>) -> Result<Vtk, Error> {
Vtk::import_legacy_le(file_path.as_ref())
}
pub fn import_legacy_be(file_path: impl AsRef<Path>) -> Result<Vtk, Error> {
Vtk::import_vtk(file_path.as_ref(), parser::parse_be)
}
#[deprecated(since = "0.6.2", note = "Please use Vtk::import_legacy_be instead")]
pub fn import_be(file_path: impl AsRef<Path>) -> Result<Vtk, Error> {
Vtk::import_legacy_be(file_path.as_ref())
}
pub fn export(self, file_path: impl AsRef<Path>) -> Result<(), Error> {
self.export_impl(file_path.as_ref())
}
fn export_impl(self, path: &Path) -> Result<(), Error> {
let ext = path
.extension()
.and_then(|s| s.to_str())
.ok_or(Error::UnknownFileExtension(None))?;
match ext {
"vtk" => {
let file = File::create(path)?;
BinaryWriter(BufWriter::new(file)).write_vtk(self)?;
Ok(())
}
#[cfg(feature = "xml")]
ext => {
let ft = xml::FileType::try_from_ext(ext)
.ok_or(Error::UnknownFileExtension(Some(ext.to_string())))?;
let vtk_file = xml::VTKFile::try_from(self)?;
let exp_ft = xml::FileType::from(vtk_file.data_set_type);
if ft != exp_ft {
Err(Error::XML(xml::Error::TypeExtensionMismatch))
} else {
xml::export(&vtk_file, path)?;
Ok(())
}
}
#[cfg(not(feature = "xml"))]
_ => Err(Error::UnknownFileExtension(None)),
}
}
pub fn write_legacy(self, writer: impl std::io::Write) -> Result<(), Error> {
BinaryWriter(writer).write_vtk(self)?;
Ok(())
}
pub fn write_legacy_ascii(self, writer: impl std::fmt::Write) -> Result<(), Error> {
AsciiWriter(writer).write_vtk(self)?;
Ok(())
}
#[cfg(feature = "xml")]
pub fn write_xml(self, writer: impl Write) -> Result<(), Error> {
let vtk_file = xml::VTKFile::try_from(self)?;
xml::write(&vtk_file, writer)?;
Ok(())
}
pub fn export_le(self, file_path: impl AsRef<Path>) -> Result<(), Error> {
let file = File::create(file_path.as_ref())?;
BinaryWriter(BufWriter::new(file)).write_vtk_le(self)?;
Ok(())
}
pub fn export_be(self, file_path: impl AsRef<Path>) -> Result<(), Error> {
let file = File::create(file_path.as_ref())?;
BinaryWriter(BufWriter::new(file)).write_vtk_be(self)?;
Ok(())
}
pub fn export_ascii(self, file_path: impl AsRef<Path>) -> Result<(), Error> {
let mut out_str = AsciiWriter(String::new());
out_str.write_vtk(self)?;
let mut file = File::create(file_path.as_ref())?;
file.write_all(out_str.0.as_bytes())?;
Ok(())
}
}