1use crate::{Result, Shutter, Time, traits::*};
4use smallvec::SmallVec;
5use std::hash::{Hash, Hasher};
6
7#[cfg(feature = "rkyv")]
8use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12#[derive(Clone, Debug, PartialEq, Hash)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21#[cfg_attr(
22 feature = "serde",
23 serde(bound(
24 serialize = "D: Serialize, D::Animated: Serialize",
25 deserialize = "D: Deserialize<'de>, D::Animated: Deserialize<'de>"
26 ))
27)]
28#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
29pub enum GenericValue<D: DataSystem> {
30 Uniform(D),
32 Animated(D::Animated),
34}
35
36impl<D: DataSystem> GenericValue<D> {
37 pub fn uniform(value: D) -> Self {
39 GenericValue::Uniform(value)
40 }
41
42 pub fn animated<I>(samples: I) -> Result<Self>
47 where
48 I: IntoIterator<Item = (Time, D)>,
49 {
50 let mut samples_vec: Vec<(Time, D)> = samples.into_iter().collect();
51
52 if samples_vec.is_empty() {
53 return Err(crate::Error::EmptySamples);
54 }
55
56 let data_type = samples_vec[0].1.discriminant();
58 let expected_name = samples_vec[0].1.variant_name();
59
60 let mut expected_len: Option<usize> = None;
62 for (time, value) in &mut samples_vec {
63 if value.discriminant() != data_type {
64 return Err(crate::Error::GenericTypeMismatch {
65 expected: expected_name,
66 got: value.variant_name(),
67 });
68 }
69
70 if let Some(vec_len) = value.try_len() {
72 match expected_len {
73 None => expected_len = Some(vec_len),
74 Some(expected) => {
75 if vec_len > expected {
76 return Err(crate::Error::VectorLengthExceeded {
77 actual: vec_len,
78 expected,
79 time: *time,
80 });
81 } else if vec_len < expected {
82 value.pad_to_length(expected);
83 }
84 }
85 }
86 }
87 }
88
89 let (first_time, first_value) = samples_vec.remove(0);
91 let mut animated = D::Animated::from_single(first_time, first_value);
92
93 for (time, value) in samples_vec {
94 animated.try_insert(time, value)?;
95 }
96
97 Ok(GenericValue::Animated(animated))
98 }
99
100 pub fn add_at(&mut self, time: Time, value: D) -> Result<()> {
104 match self {
105 GenericValue::Uniform(_) => {
106 *self = GenericValue::animated(vec![(time, value)])?;
107 Ok(())
108 }
109 GenericValue::Animated(samples) => {
110 if value.discriminant() != samples.discriminant() {
111 return Err(crate::Error::GenericTypeMismatch {
112 expected: samples.variant_name(),
113 got: value.variant_name(),
114 });
115 }
116 samples.try_insert(time, value)
117 }
118 }
119 }
120
121 #[deprecated(since = "0.2.3", note = "renamed to `add_at`")]
123 pub fn add_sample(&mut self, time: Time, value: D) -> Result<()> {
124 self.add_at(time, value)
125 }
126
127 pub fn remove_at(&mut self, time: &Time) -> Option<D> {
134 match self {
135 GenericValue::Uniform(_) => None,
136 GenericValue::Animated(samples) => samples.remove_at(time),
137 }
138 }
139
140 #[deprecated(since = "0.2.2", note = "renamed to `remove_at`")]
142 pub fn remove_sample(&mut self, time: &Time) -> Option<D> {
143 self.remove_at(time)
144 }
145
146 pub fn remove_at_or_to_uniform(&mut self, time: &Time) -> Option<D> {
154 match self {
155 GenericValue::Uniform(_) => None,
156 GenericValue::Animated(samples) => {
157 let removed = samples.remove_at(time);
158 if removed.is_some() {
159 return removed;
160 }
161 if samples.sample_at(*time).is_some() {
164 let data = samples.interpolate(Time::default());
166 *self = GenericValue::Uniform(data);
167 }
168 None
169 }
170 }
171 }
172
173 pub fn sample_at(&self, time: Time) -> Option<D> {
178 match self {
179 GenericValue::Uniform(v) => Some(v.clone()),
180 GenericValue::Animated(samples) => samples.sample_at(time),
181 }
182 }
183
184 pub fn interpolate(&self, time: Time) -> D {
189 match self {
190 GenericValue::Uniform(v) => v.clone(),
191 GenericValue::Animated(samples) => samples.interpolate(time),
192 }
193 }
194
195 pub fn is_animated(&self) -> bool {
197 match self {
198 GenericValue::Uniform(_) => false,
199 GenericValue::Animated(samples) => samples.has_animation(),
200 }
201 }
202
203 pub fn sample_count(&self) -> usize {
205 match self {
206 GenericValue::Uniform(_) => 1,
207 GenericValue::Animated(samples) => samples.keyframe_count(),
208 }
209 }
210
211 pub fn times(&self) -> SmallVec<[Time; 10]> {
213 match self {
214 GenericValue::Uniform(_) => SmallVec::new_const(),
215 GenericValue::Animated(samples) => samples.times(),
216 }
217 }
218
219 pub fn discriminant(&self) -> D::DataType {
221 match self {
222 GenericValue::Uniform(data) => data.discriminant(),
223 GenericValue::Animated(animated) => animated.discriminant(),
224 }
225 }
226
227 pub fn variant_name(&self) -> &'static str {
229 match self {
230 GenericValue::Uniform(data) => data.variant_name(),
231 GenericValue::Animated(animated) => animated.variant_name(),
232 }
233 }
234
235 pub fn merge_with<F>(&self, other: &GenericValue<D>, combiner: F) -> Result<GenericValue<D>>
241 where
242 F: Fn(&D, &D) -> D,
243 {
244 match (self, other) {
245 (GenericValue::Uniform(a), GenericValue::Uniform(b)) => {
246 Ok(GenericValue::Uniform(combiner(a, b)))
247 }
248 _ => {
249 let mut all_times = std::collections::BTreeSet::new();
250 for t in self.times() {
251 all_times.insert(t);
252 }
253 for t in other.times() {
254 all_times.insert(t);
255 }
256
257 if all_times.is_empty() {
258 let a = self.interpolate(Time::default());
259 let b = other.interpolate(Time::default());
260 return Ok(GenericValue::Uniform(combiner(&a, &b)));
261 }
262
263 let combined_samples: Vec<(Time, D)> = all_times
264 .into_iter()
265 .map(|time| {
266 let a = self.interpolate(time);
267 let b = other.interpolate(time);
268 (time, combiner(&a, &b))
269 })
270 .collect();
271
272 if combined_samples.len() == 1 {
273 Ok(GenericValue::Uniform(
274 combined_samples.into_iter().next().unwrap().1,
276 ))
277 } else {
278 GenericValue::animated(combined_samples)
279 }
280 }
281 }
282 }
283
284 pub fn hash_with_shutter<H: Hasher>(&self, state: &mut H, shutter: &Shutter) {
289 match self {
290 GenericValue::Uniform(data) => {
291 data.hash(state);
292 }
293 GenericValue::Animated(animated) => {
294 const SAMPLE_POSITIONS: [f32; 5] = [0.0, 0.25, 0.5, 0.75, 1.0];
296
297 let samples: SmallVec<[D; 5]> = SAMPLE_POSITIONS
298 .iter()
299 .map(|&pos| {
300 let time = shutter.evaluate(pos);
301 animated.interpolate(time)
302 })
303 .collect();
304
305 let all_same = samples.windows(2).all(|w| w[0] == w[1]);
306
307 std::mem::discriminant(self).hash(state);
308
309 if all_same {
310 1usize.hash(state);
311 samples[0].hash(state);
312 } else {
313 samples.len().hash(state);
314 for sample in &samples {
315 sample.hash(state);
316 }
317 }
318 }
319 }
320 }
321}
322
323impl<D: DataSystem> From<D> for GenericValue<D> {
324 fn from(value: D) -> Self {
325 GenericValue::uniform(value)
326 }
327}
328
329impl<D: DataSystem> Eq for GenericValue<D> {}