use std::path::{Path, PathBuf};
use ironlab_ir::{Figure, IrError};
const FIGURE_EXTENSIONS: [&str; 3] = [".fig.json", ".json", ".fig"];
#[derive(Debug, thiserror::Error)]
pub enum OpenError {
#[error(
"{}: unsupported file type; expected a .fig file (Protocol Buffers) or a .json file such as .fig.json (JSON)",
.path.display()
)]
UnsupportedFormat {
path: PathBuf,
},
#[error("{}: {source}", .path.display())]
Io {
path: PathBuf,
source: std::io::Error,
},
#[error("{}: {source}", .path.display())]
Invalid {
path: PathBuf,
source: IrError,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Format {
Protobuf,
Json,
}
impl Format {
fn of(path: &Path) -> Option<Self> {
match path.extension().and_then(|extension| extension.to_str()) {
Some(ext) if ext.eq_ignore_ascii_case("fig") => Some(Self::Protobuf),
Some(ext) if ext.eq_ignore_ascii_case("json") => Some(Self::Json),
_ => None,
}
}
}
pub fn write_figure(path: &Path, figure: &Figure) -> Result<(), SaveError> {
let bytes = match Format::of(path) {
Some(Format::Protobuf) => figure.to_protobuf(),
Some(Format::Json) => figure.to_json().into_bytes(),
None => {
return Err(SaveError::UnsupportedFormat {
path: path.to_path_buf(),
});
}
};
std::fs::write(path, bytes).map_err(|source| SaveError::Io {
path: path.to_path_buf(),
source,
})
}
#[derive(Debug, thiserror::Error)]
pub enum SaveError {
#[error(
"{}: unsupported file type; expected a .fig file (Protocol Buffers) or a .json file such as .fig.json (JSON)",
.path.display()
)]
UnsupportedFormat {
path: PathBuf,
},
#[error("{}: {source}", .path.display())]
Io {
path: PathBuf,
source: std::io::Error,
},
}
pub fn read_figure(path: &Path) -> Result<Figure, OpenError> {
let io = |source| OpenError::Io {
path: path.to_path_buf(),
source,
};
let figure = match Format::of(path) {
Some(Format::Protobuf) => Figure::from_protobuf(&std::fs::read(path).map_err(io)?),
Some(Format::Json) => Figure::from_json(&std::fs::read_to_string(path).map_err(io)?),
None => {
return Err(OpenError::UnsupportedFormat {
path: path.to_path_buf(),
});
}
};
figure.map_err(|source| OpenError::Invalid {
path: path.to_path_buf(),
source,
})
}
#[must_use]
pub fn figure_stem(name: &str) -> &str {
FIGURE_EXTENSIONS
.iter()
.find_map(|extension| {
let split = name.len().checked_sub(extension.len())?;
let (stem, suffix) = (name.get(..split)?, name.get(split..)?);
(!stem.is_empty() && suffix.eq_ignore_ascii_case(extension)).then_some(stem)
})
.unwrap_or(name)
}