euphony_store/
timeline.rs

1use euphony_compiler::{
2    sample::{DefaultRate, Rate as _},
3    Hash, Writer,
4};
5use serde::{Deserialize, Serialize};
6use std::{io, ops};
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
9pub struct Timeline {
10    pub sample_rate: u32,
11    pub groups: Vec<Group>,
12}
13
14impl Default for Timeline {
15    #[inline]
16    fn default() -> Self {
17        Self {
18            sample_rate: DefaultRate::COUNT as _,
19            groups: Default::default(),
20        }
21    }
22}
23
24impl Timeline {
25    #[inline]
26    pub fn to_json<W: io::Write>(&self, w: W) -> io::Result<()> {
27        serde_json::to_writer(w, self)?;
28        Ok(())
29    }
30
31    #[inline]
32    pub fn reset(&mut self) {
33        self.sample_rate = DefaultRate::COUNT as _;
34        self.groups.clear();
35    }
36}
37
38#[derive(Clone, Debug, Default, Serialize, Deserialize)]
39pub struct Group {
40    pub name: String,
41    pub entries: HashDisplay,
42}
43
44#[derive(Clone, Debug, Default, Serialize, Deserialize)]
45pub struct HashDisplay(#[serde(with = "base64")] Hash);
46
47impl ops::Deref for HashDisplay {
48    type Target = Hash;
49
50    fn deref(&self) -> &Self::Target {
51        &self.0
52    }
53}
54
55mod base64 {
56    use base64::URL_SAFE_NO_PAD;
57    use euphony_compiler::Hash;
58    use serde::{self, Deserialize, Deserializer, Serializer};
59
60    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
61    where
62        S: Serializer,
63    {
64        if serializer.is_human_readable() {
65            let mut out = [b'A'; 64];
66            let len = base64::encode_config_slice(bytes, URL_SAFE_NO_PAD, &mut out);
67            let out = unsafe { core::str::from_utf8_unchecked_mut(&mut out) };
68            let out = &out[..len];
69            serializer.serialize_str(out)
70        } else {
71            serializer.serialize_bytes(bytes)
72        }
73    }
74
75    pub fn deserialize<'de, D>(deserializer: D) -> Result<Hash, D::Error>
76    where
77        D: Deserializer<'de>,
78    {
79        if deserializer.is_human_readable() {
80            let s = <&str>::deserialize(deserializer)?;
81            let mut out = Hash::default();
82            let len = base64::decode_config_slice(s, URL_SAFE_NO_PAD, &mut out)
83                .map_err(serde::de::Error::custom)?;
84
85            if len != out.len() {
86                return Err(serde::de::Error::custom("invalid hash length"));
87            }
88
89            Ok(out)
90        } else {
91            Hash::deserialize(deserializer)
92        }
93    }
94}
95
96impl Writer for Timeline {
97    #[inline]
98    fn is_cached(&self, _: &Hash) -> bool {
99        unimplemented!()
100    }
101
102    #[inline]
103    fn sink(&mut self, _hash: &Hash) -> euphony_node::BoxProcessor {
104        unimplemented!()
105    }
106
107    #[inline]
108    fn group<I: Iterator<Item = euphony_compiler::Entry>>(
109        &mut self,
110        name: &str,
111        hash: &Hash,
112        _entries: I,
113    ) {
114        self.groups.push(Group {
115            name: name.to_string(),
116            entries: HashDisplay(*hash),
117        });
118    }
119
120    fn buffer<
121        F: FnOnce(
122            Box<dyn euphony_compiler::BufferReader>,
123        ) -> euphony_compiler::Result<Vec<euphony_compiler::ConvertedBuffer>, E>,
124        E,
125    >(
126        &self,
127        _path: &str,
128        _sample_rate: u64,
129        _init: F,
130    ) -> euphony_compiler::Result<Vec<euphony_compiler::CachedBuffer>, E> {
131        unimplemented!()
132    }
133}