pub mod adj_data;
pub mod anim_data;
pub mod hlpb_data;
pub mod matl_data;
pub mod mesh_data;
pub mod meshex_data;
pub mod modl_data;
pub mod shdr_data;
pub mod skel_data;
use binrw::io::{Read, Seek, Write};
use ssbh_lib::prelude::*;
use std::convert::TryFrom;
use std::error::Error;
use std::path::Path;
pub use ssbh_lib::{CString, Color4f, Vector3, Vector4};
pub trait SsbhData: Sized {
type WriteError: Error;
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>>;
fn read<R: Read + Seek>(reader: &mut R) -> Result<Self, Box<dyn std::error::Error>>;
fn write<W: Write + Seek>(&self, writer: &mut W) -> Result<(), Self::WriteError>;
fn write_to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Self::WriteError>;
}
pub mod prelude {
pub use crate::adj_data::AdjData;
pub use crate::anim_data::AnimData;
pub use crate::hlpb_data::HlpbData;
pub use crate::matl_data::MatlData;
pub use crate::mesh_data::MeshData;
pub use crate::meshex_data::MeshExData;
pub use crate::modl_data::ModlData;
pub use crate::shdr_data::ShdrData;
pub use crate::skel_data::SkelData;
pub use crate::SsbhData;
}
macro_rules! ssbh_data_impl {
($ssbh_data:ty, $ssbh_lib:ty, $error:ty) => {
impl SsbhData for $ssbh_data {
type WriteError = $error;
fn from_file<P: AsRef<std::path::Path>>(
path: P,
) -> Result<Self, Box<dyn std::error::Error>> {
<$ssbh_lib>::from_file(path)?.try_into().map_err(Into::into)
}
fn read<R: Read + Seek>(reader: &mut R) -> Result<Self, Box<dyn std::error::Error>> {
<$ssbh_lib>::read(reader)?.try_into().map_err(Into::into)
}
fn write<W: Write + Seek>(&self, writer: &mut W) -> Result<(), Self::WriteError> {
<$ssbh_lib>::try_from(self)?
.write(writer)
.map_err(Into::into)
}
fn write_to_file<P: AsRef<std::path::Path>>(
&self,
path: P,
) -> Result<(), Self::WriteError> {
<$ssbh_lib>::try_from(self)?
.write_to_file(path)
.map_err(Into::into)
}
}
impl $ssbh_data {
pub fn from_file<P: AsRef<std::path::Path>>(
path: P,
) -> Result<Self, Box<dyn std::error::Error>> {
<Self as SsbhData>::from_file(path)
}
pub fn read<R: std::io::Read + std::io::Seek>(
reader: &mut R,
) -> Result<Self, Box<dyn std::error::Error>> {
<Self as SsbhData>::read(reader)
}
pub fn write<W: std::io::Write + std::io::Seek>(
&self,
writer: &mut W,
) -> Result<(), <Self as SsbhData>::WriteError> {
<Self as SsbhData>::write(self, writer)
}
pub fn write_to_file<P: AsRef<std::path::Path>>(
&self,
path: P,
) -> Result<(), <Self as SsbhData>::WriteError> {
<Self as SsbhData>::write_to_file(self, path)
}
}
};
}
macro_rules! ssbh_data_infallible_impl {
($ssbh_data:ty, $ssbh_lib:ty, $error:ty) => {
impl SsbhData for $ssbh_data {
type WriteError = $error;
fn from_file<P: AsRef<std::path::Path>>(
path: P,
) -> Result<Self, Box<dyn std::error::Error>> {
Ok(<$ssbh_lib>::from_file(path)?.into())
}
fn read<R: std::io::Read + std::io::Seek>(
reader: &mut R,
) -> Result<Self, Box<dyn std::error::Error>> {
Ok(<$ssbh_lib>::read(reader)?.into())
}
fn write<W: std::io::Write + std::io::Seek>(
&self,
writer: &mut W,
) -> Result<(), Self::WriteError> {
<$ssbh_lib>::from(self).write(writer)
}
fn write_to_file<P: AsRef<std::path::Path>>(
&self,
path: P,
) -> Result<(), Self::WriteError> {
<$ssbh_lib>::from(self).write_to_file(path)
}
}
impl $ssbh_data {
pub fn from_file<P: AsRef<std::path::Path>>(
path: P,
) -> Result<Self, Box<dyn std::error::Error>> {
<Self as SsbhData>::from_file(path)
}
pub fn read<R: std::io::Read + std::io::Seek>(
reader: &mut R,
) -> Result<Self, Box<dyn std::error::Error>> {
<Self as SsbhData>::read(reader)
}
pub fn write<W: std::io::Write + std::io::Seek>(
&self,
writer: &mut W,
) -> Result<(), <Self as SsbhData>::WriteError> {
<Self as SsbhData>::write(self, writer)
}
pub fn write_to_file<P: AsRef<std::path::Path>>(
&self,
path: P,
) -> Result<(), <Self as SsbhData>::WriteError> {
<Self as SsbhData>::write_to_file(self, path)
}
}
};
}
ssbh_data_impl!(adj_data::AdjData, Adj, adj_data::error::Error);
ssbh_data_impl!(anim_data::AnimData, Anim, anim_data::error::Error);
ssbh_data_impl!(matl_data::MatlData, Matl, matl_data::error::Error);
ssbh_data_impl!(mesh_data::MeshData, Mesh, mesh_data::error::Error);
ssbh_data_infallible_impl!(meshex_data::MeshExData, MeshEx, std::io::Error);
ssbh_data_infallible_impl!(modl_data::ModlData, Modl, std::io::Error);
ssbh_data_infallible_impl!(hlpb_data::HlpbData, Hlpb, std::io::Error);
ssbh_data_impl!(skel_data::SkelData, Skel, skel_data::error::Error);
#[cfg(test)]
pub(crate) fn group_hex(a: &str, words_per_line: usize) -> String {
use itertools::Itertools;
let words = a
.chars()
.collect::<Vec<char>>()
.chunks(8)
.map(|c| c.iter().collect::<String>())
.collect::<Vec<String>>();
words.chunks(words_per_line).map(|c| c.join(" ")).join("\n")
}
#[cfg(test)]
macro_rules! assert_hex_eq {
($a:expr, $b:expr) => {
pretty_assertions::assert_str_eq!(
crate::group_hex(&hex::encode($a), 8),
crate::group_hex(&hex::encode($b), 8)
)
};
}
#[cfg(test)]
pub(crate) use assert_hex_eq;