euphony_store/
timeline.rs1use 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}