mod error;
mod parser;
#[cfg(feature = "python")]
mod python;
pub use error::Error;
use parser::{
parse_bruker_raw, parse_csv, parse_gsas_raw, parse_rasx, parse_xrdml, parse_xy, ParsedPattern,
};
#[cfg(feature = "python")]
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::{Cursor, Read, Seek, SeekFrom};
use std::path::Path;
#[cfg_attr(feature = "python", pyclass(get_all))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Pattern {
pub x: Vec<f64>,
pub y: Vec<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub e: Option<Vec<f64>>,
}
impl Pattern {
pub fn new(x: Vec<f64>, y: Vec<f64>, e: Option<Vec<f64>>) -> Result<Self, Error> {
if x.len() != y.len() {
return Err(Error::Parse(
"x and y must have the same length".into(),
));
}
if let Some(ref e_vec) = e {
if e_vec.len() != x.len() {
return Err(Error::Parse(
"e must have the same length as x and y".into(),
));
}
}
Ok(Pattern { x, y, e })
}
}
impl From<ParsedPattern> for Pattern {
fn from(data: ParsedPattern) -> Self {
Pattern {
x: data.x,
y: data.y,
e: data.e,
}
}
}
pub fn read<P: AsRef<Path>>(path: P) -> Result<Pattern, Error> {
let path = path.as_ref();
let file = File::open(path)?;
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or("");
read_reader(file, filename)
}
pub fn read_reader<R: Read + Seek>(
reader: R,
filename: &str,
) -> Result<Pattern, Error> {
let ext = Path::new(filename)
.extension()
.and_then(|s| s.to_str())
.unwrap_or("")
.to_lowercase();
let mut reader = reader;
let data = match ext.as_str() {
"raw" => {
let mut buffer = [0u8; 1024];
let bytes_read = reader.read(&mut buffer)?;
reader.seek(SeekFrom::Start(0))?;
let chunk = &buffer[..bytes_read];
let is_binary = chunk.iter().any(|&b| b == 0);
if is_binary {
parse_bruker_raw(reader)?
} else {
parse_gsas_raw(reader)?
}
}
"rasx" => parse_rasx(reader)?,
"xrdml" => parse_xrdml(reader)?,
"xy" | "xye" => parse_xy(reader)?,
"csv" => parse_csv(reader)?,
_ => return Err(Error::UnknownFormat),
};
Ok(data.into())
}
pub fn read_bytes<B: AsRef<[u8]>>(bytes: B, filename: &str) -> Result<Pattern, Error> {
let cursor = Cursor::new(bytes.as_ref());
read_reader(cursor, filename)
}