chara_card 0.4.1

A library to deal with character card formats and `.charx` in Rust.
Documentation
use crate::charx::asset::Asset;
use crate::charx::source::Source;
use crate::charx::Error;
use crate::raw::NestedCharacterCard;
use std::collections::HashMap;
use std::io::{Read, Seek};
use url::Url;
use zip::result::ZipError;
use zip::ZipArchive;

pub struct CharX {
    pub card: NestedCharacterCard,
    pub assets: HashMap<String, Vec<Asset>>,
}

impl<T: Read + Seek> TryFrom<CharXImport<T>> for CharX {
    type Error = Error;

    fn try_from(mut value: CharXImport<T>) -> Result<Self, Self::Error> {
        let mut assets = HashMap::new();
        for raw in value
            .card
            .data
            .v3
            .as_ref()
            .map(|v| v.assets.as_slice())
            .unwrap_or_default()
        {
            let source: Source = (&raw.uri).into();
            let asset = Asset::try_from(source, &raw.ext, &mut value.archive)?;

            assets
                .entry(raw.name.clone())
                .or_insert_with(Vec::new)
                .push(asset);
        }

        Ok(Self {
            card: value.card,
            assets,
        })
    }
}

pub struct CharXImport<T: Read + Seek> {
    card: NestedCharacterCard,
    archive: ZipArchive<T>,
}

impl<T: Read + Seek> CharXImport<T> {
    pub fn from_reader(reader: T) -> Result<Self, Error> {
        let mut archive = ZipArchive::new(reader)?;

        let file = match archive.by_name("card.json") {
            Ok(file) => file,
            Err(ZipError::FileNotFound) => return Err(Error::NotFound("card.json".into())),
            Err(e) => return Err(e.into()),
        };

        let card: NestedCharacterCard = serde_json::from_reader(file)?;

        Ok(Self {
            card: card,
            archive,
        })
    }

    pub fn externals(&self) -> impl Iterator<Item = &Url> {
        self.card
            .data
            .v3
            .as_ref()
            .map(|v| v.assets.iter())
            .unwrap_or_default()
            .map(|a| &a.uri)
            .filter(|u| u.scheme() != "embeded" && u.scheme() != "ccdefault")
    }
}