euphony-store 0.1.1

storage component for rendered output
Documentation
use euphony_compiler::{
    sample::{DefaultRate, Rate as _},
    Hash, Writer,
};
use serde::{Deserialize, Serialize};
use std::{io, ops};

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Timeline {
    pub sample_rate: u32,
    pub groups: Vec<Group>,
}

impl Default for Timeline {
    #[inline]
    fn default() -> Self {
        Self {
            sample_rate: DefaultRate::COUNT as _,
            groups: Default::default(),
        }
    }
}

impl Timeline {
    #[inline]
    pub fn to_json<W: io::Write>(&self, w: W) -> io::Result<()> {
        serde_json::to_writer(w, self)?;
        Ok(())
    }

    #[inline]
    pub fn reset(&mut self) {
        self.sample_rate = DefaultRate::COUNT as _;
        self.groups.clear();
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Group {
    pub name: String,
    pub entries: HashDisplay,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct HashDisplay(#[serde(with = "base64")] Hash);

impl ops::Deref for HashDisplay {
    type Target = Hash;

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

mod base64 {
    use base64::URL_SAFE_NO_PAD;
    use euphony_compiler::Hash;
    use serde::{self, Deserialize, Deserializer, Serializer};

    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if serializer.is_human_readable() {
            let mut out = [b'A'; 64];
            let len = base64::encode_config_slice(bytes, URL_SAFE_NO_PAD, &mut out);
            let out = unsafe { core::str::from_utf8_unchecked_mut(&mut out) };
            let out = &out[..len];
            serializer.serialize_str(out)
        } else {
            serializer.serialize_bytes(bytes)
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Hash, D::Error>
    where
        D: Deserializer<'de>,
    {
        if deserializer.is_human_readable() {
            let s = <&str>::deserialize(deserializer)?;
            let mut out = Hash::default();
            let len = base64::decode_config_slice(s, URL_SAFE_NO_PAD, &mut out)
                .map_err(serde::de::Error::custom)?;

            if len != out.len() {
                return Err(serde::de::Error::custom("invalid hash length"));
            }

            Ok(out)
        } else {
            Hash::deserialize(deserializer)
        }
    }
}

impl Writer for Timeline {
    #[inline]
    fn is_cached(&self, _: &Hash) -> bool {
        unimplemented!()
    }

    #[inline]
    fn sink(&mut self, _hash: &Hash) -> euphony_node::BoxProcessor {
        unimplemented!()
    }

    #[inline]
    fn group<I: Iterator<Item = euphony_compiler::Entry>>(
        &mut self,
        name: &str,
        hash: &Hash,
        _entries: I,
    ) {
        self.groups.push(Group {
            name: name.to_string(),
            entries: HashDisplay(*hash),
        });
    }

    fn buffer<
        F: FnOnce(
            Box<dyn euphony_compiler::BufferReader>,
        ) -> euphony_compiler::Result<Vec<euphony_compiler::ConvertedBuffer>, E>,
        E,
    >(
        &self,
        _path: &str,
        _sample_rate: u64,
        _init: F,
    ) -> euphony_compiler::Result<Vec<euphony_compiler::CachedBuffer>, E> {
        unimplemented!()
    }
}