chara_card 0.4.1

A library to deal with character card formats and `.charx` in Rust.
Documentation
use crate::charx::source::Source;
use crate::charx::Error;
use std::borrow::Cow;
use std::fs::File;
use std::io::{Read, Seek};
use std::ops::Deref;
use zip::ZipArchive;

#[derive(Debug, Clone)]
pub struct Data {
    pub bytes: Cow<'static, [u8]>,
    pub mime: &'static str,
}

impl Data {
    pub fn new(data: Cow<'static, [u8]>, ext: &str) -> Self {
        if let Some(inferred) = infer::get(&data) {
            return Self {
                bytes: data,
                mime: inferred.mime_type(),
            };
        }

        let mime = mime_guess::from_ext(ext)
            .first_raw()
            .unwrap_or("application/octet-stream");

        Self { bytes: data, mime }
    }
}

impl Deref for Data {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        self.bytes.as_ref()
    }
}

impl AsRef<[u8]> for Data {
    fn as_ref(&self) -> &[u8] {
        self.bytes.as_ref()
    }
}

#[derive(Debug, Clone)]
pub struct Asset {
    pub data: Option<Data>,
    pub source: Source,
}

impl Asset {
    pub fn data(&self) -> Option<&Data> {
        self.data.as_ref()
    }

    pub fn source(&self) -> &Source {
        &self.source
    }

    pub fn try_from(
        source: Source,
        ext: &str,
        archive: &mut ZipArchive<impl Read + Seek>,
    ) -> Result<Self, Error> {
        Ok(match source {
            Source::CCDefault => Self {
                data: None,
                source: Source::CCDefault,
            },

            Source::Embedded(path) => {
                let mut file = archive.by_path(&path)?;

                let mut buffer = Vec::new();
                if let Err(e) = file.read_to_end(&mut buffer) {
                    return Err(Error::Io(path, e));
                }

                Self {
                    data: Some(Data::new(Cow::Owned(buffer), ext)),
                    source: Source::Embedded(path),
                }
            }

            Source::File(path) => {
                let mut file = match File::open(&path) {
                    Ok(file) => file,
                    Err(e) => return Err(Error::Io(path, e)),
                };

                let mut buffer = Vec::new();
                if let Err(e) = file.read_to_end(&mut buffer) {
                    return Err(Error::Io(path, e));
                }

                Self {
                    data: Some(Data::new(Cow::Owned(buffer), ext)),
                    source: Source::File(path),
                }
            }

            Source::Misc(url) => Self {
                data: None,
                source: Source::Misc(url),
            },
        })
    }
}