use std::path::Path;
use crate::error::RoxResult;
use crate::model::RoxChart;
pub trait Decoder {
fn decode(data: &[u8]) -> RoxResult<RoxChart>;
fn decode_from_path(path: impl AsRef<Path>) -> RoxResult<RoxChart> {
let data = std::fs::read(path)?;
Self::decode(&data)
}
}
pub trait Encoder {
fn encode(chart: &RoxChart) -> RoxResult<Vec<u8>>;
fn encode_to_path(chart: &RoxChart, path: impl AsRef<Path>) -> RoxResult<()> {
let data = Self::encode(chart)?;
std::fs::write(path, data)?;
Ok(())
}
fn encode_to_string(chart: &RoxChart) -> RoxResult<String> {
let data = Self::encode(chart)?;
String::from_utf8(data)
.map_err(|e| crate::error::RoxError::InvalidFormat(format!("Invalid UTF-8: {e}")))
}
}
pub trait Format {
const EXTENSIONS: &'static [&'static str];
#[must_use]
fn supports_extension(ext: &str) -> bool {
let ext_lower = ext.to_lowercase();
Self::EXTENSIONS.iter().any(|&e| e == ext_lower)
}
}
pub fn convert<D: Decoder, E: Encoder>(data: &[u8]) -> RoxResult<Vec<u8>> {
let chart = D::decode(data)?;
E::encode(&chart)
}
pub fn convert_file<D: Decoder, E: Encoder>(
input: impl AsRef<Path>,
output: impl AsRef<Path>,
) -> RoxResult<()> {
let chart = D::decode_from_path(input)?;
E::encode_to_path(&chart, output)
}