1#![forbid(unsafe_code)]
2
3use serde::de::{self, SeqAccess, Visitor};
4use serde::ser::SerializeTuple;
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use std::fmt;
7
8pub const FEATURE_COUNT: usize = 35;
9
10const MAX_KEY_BYTES: usize = 128;
11const PERCEIVED_AGE_INDEX: usize = 11;
12const FEATURE_BITS: u64 = (1_u64 << FEATURE_COUNT) - 1;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct TypeError {
16 kind: ErrorKind,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20enum ErrorKind {
21 InvalidKey,
22 InvalidObjectId,
23 FeatureValue {
24 index: usize,
25 value: u8,
26 maximum: u8,
27 },
28 EmptyFeatureMask,
29 UnknownFeatureBits,
30 SegmentOrdinal,
31 SegmentTime,
32}
33
34impl TypeError {
35 fn new(kind: ErrorKind) -> Self {
36 Self { kind }
37 }
38}
39
40impl fmt::Display for TypeError {
41 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self.kind {
43 ErrorKind::InvalidKey => formatter.write_str(
44 "key must contain 1 to 128 ASCII letters, digits, or . _ - / : characters",
45 ),
46 ErrorKind::InvalidObjectId => {
47 formatter.write_str("object ID must contain exactly eight base64url characters")
48 }
49 ErrorKind::FeatureValue {
50 index,
51 value,
52 maximum,
53 } => write!(
54 formatter,
55 "feature at index {index} has value {value}, exceeding {maximum}"
56 ),
57 ErrorKind::EmptyFeatureMask => {
58 formatter.write_str("feature mask must contain at least one bit")
59 }
60 ErrorKind::UnknownFeatureBits => {
61 formatter.write_str("feature mask may contain only bits 0 through 34")
62 }
63 ErrorKind::SegmentOrdinal => {
64 formatter.write_str("segment ordinal must be less than segment count")
65 }
66 ErrorKind::SegmentTime => {
67 formatter.write_str("segment start must be earlier than segment end")
68 }
69 }
70 }
71}
72
73impl std::error::Error for TypeError {}
74
75#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
76#[serde(transparent)]
77pub struct Key(String);
78
79impl Key {
80 pub fn parse(value: &str) -> Result<Self, TypeError> {
81 if valid_key(value) {
82 Ok(Self(value.to_owned()))
83 } else {
84 Err(TypeError::new(ErrorKind::InvalidKey))
85 }
86 }
87}
88
89fn valid_key(value: &str) -> bool {
90 let bytes = value.as_bytes();
91 (1..=MAX_KEY_BYTES).contains(&bytes.len())
92 && bytes.iter().all(|byte| {
93 byte.is_ascii_alphanumeric() || matches!(*byte, b'.' | b'_' | b'-' | b'/' | b':')
94 })
95}
96
97impl AsRef<str> for Key {
98 fn as_ref(&self) -> &str {
99 &self.0
100 }
101}
102
103impl<'de> Deserialize<'de> for Key {
104 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
105 where
106 D: Deserializer<'de>,
107 {
108 let value = String::deserialize(deserializer)?;
109 Self::parse(&value).map_err(de::Error::custom)
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
114#[serde(transparent)]
115pub struct ObjectId(String);
116
117impl ObjectId {
118 pub fn parse(value: &str) -> Result<Self, TypeError> {
119 let bytes = value.as_bytes();
120 if bytes.len() == 8
121 && bytes
122 .iter()
123 .all(|byte| byte.is_ascii_alphanumeric() || matches!(*byte, b'-' | b'_'))
124 {
125 Ok(Self(value.to_owned()))
126 } else {
127 Err(TypeError::new(ErrorKind::InvalidObjectId))
128 }
129 }
130}
131
132impl AsRef<str> for ObjectId {
133 fn as_ref(&self) -> &str {
134 &self.0
135 }
136}
137
138impl<'de> Deserialize<'de> for ObjectId {
139 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
140 where
141 D: Deserializer<'de>,
142 {
143 let value = String::deserialize(deserializer)?;
144 Self::parse(&value).map_err(de::Error::custom)
145 }
146}
147
148#[derive(Debug, Clone, PartialEq, Eq)]
149pub struct FeatureVector([u8; FEATURE_COUNT]);
150
151impl FeatureVector {
152 pub fn new(values: [u8; FEATURE_COUNT]) -> Result<Self, TypeError> {
153 for (index, value) in values.iter().copied().enumerate() {
154 let maximum = if index == PERCEIVED_AGE_INDEX {
155 120
156 } else {
157 100
158 };
159 if value > maximum {
160 return Err(TypeError::new(ErrorKind::FeatureValue {
161 index,
162 value,
163 maximum,
164 }));
165 }
166 }
167 Ok(Self(values))
168 }
169}
170
171impl AsRef<[u8; FEATURE_COUNT]> for FeatureVector {
172 fn as_ref(&self) -> &[u8; FEATURE_COUNT] {
173 &self.0
174 }
175}
176
177impl Serialize for FeatureVector {
178 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
179 where
180 S: Serializer,
181 {
182 let mut tuple = serializer.serialize_tuple(FEATURE_COUNT)?;
183 for value in self.0 {
184 tuple.serialize_element(&value)?;
185 }
186 tuple.end()
187 }
188}
189
190struct FeatureVectorVisitor;
191
192impl<'de> Visitor<'de> for FeatureVectorVisitor {
193 type Value = FeatureVector;
194
195 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
196 write!(formatter, "an array of {FEATURE_COUNT} feature values")
197 }
198
199 fn visit_seq<A>(self, mut sequence: A) -> Result<Self::Value, A::Error>
200 where
201 A: SeqAccess<'de>,
202 {
203 let mut values = [0; FEATURE_COUNT];
204 for (index, slot) in values.iter_mut().enumerate() {
205 *slot = sequence
206 .next_element()?
207 .ok_or_else(|| de::Error::invalid_length(index, &self))?;
208 }
209 if sequence.next_element::<de::IgnoredAny>()?.is_some() {
210 return Err(de::Error::invalid_length(FEATURE_COUNT + 1, &self));
211 }
212 FeatureVector::new(values).map_err(de::Error::custom)
213 }
214}
215
216impl<'de> Deserialize<'de> for FeatureVector {
217 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
218 where
219 D: Deserializer<'de>,
220 {
221 deserializer.deserialize_tuple(FEATURE_COUNT, FeatureVectorVisitor)
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
226pub struct FeatureMask(u64);
227
228impl FeatureMask {
229 pub fn from_bits(bits: u64) -> Result<Self, TypeError> {
230 if bits == 0 {
231 Err(TypeError::new(ErrorKind::EmptyFeatureMask))
232 } else if bits & !FEATURE_BITS != 0 {
233 Err(TypeError::new(ErrorKind::UnknownFeatureBits))
234 } else {
235 Ok(Self(bits))
236 }
237 }
238}
239
240impl From<FeatureMask> for u64 {
241 fn from(mask: FeatureMask) -> Self {
242 mask.0
243 }
244}
245
246impl Serialize for FeatureMask {
247 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
248 where
249 S: Serializer,
250 {
251 serializer.serialize_u64(self.0)
252 }
253}
254
255impl<'de> Deserialize<'de> for FeatureMask {
256 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
257 where
258 D: Deserializer<'de>,
259 {
260 let bits = u64::deserialize(deserializer)?;
261 Self::from_bits(bits).map_err(de::Error::custom)
262 }
263}
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
266pub enum RecordingKind {
267 VoiceNote,
268 Meeting,
269 Call,
270 Other,
271}
272
273#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
274pub struct SegmentRef {
275 pub source_object: ObjectId,
276 pub clip_object: ObjectId,
277 pub ordinal: u16,
278 pub segment_count: u16,
279 pub start_ms: u64,
280 pub end_ms: u64,
281 pub policy: Key,
282}
283
284impl SegmentRef {
285 pub fn validate(&self) -> Result<(), TypeError> {
286 if self.ordinal >= self.segment_count {
287 Err(TypeError::new(ErrorKind::SegmentOrdinal))
288 } else if self.start_ms >= self.end_ms {
289 Err(TypeError::new(ErrorKind::SegmentTime))
290 } else {
291 Ok(())
292 }
293 }
294}
295
296#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
297pub struct LabeledSample {
298 pub sample_id: Key,
299 pub attempt_id: Key,
300 pub speaker_id: Key,
301 pub cohort_id: Key,
302 pub group_id: Key,
303 pub clip_object: ObjectId,
304 pub primary_language: Key,
305 pub recording_kind: RecordingKind,
306 pub usable_speech_ms: u32,
307 pub recording_quality: u8,
308 pub features: FeatureVector,
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314 use serde::de::IntoDeserializer;
315 use serde::ser::{Impossible, SerializeStruct};
316
317 #[derive(Debug)]
318 struct CodecError(String);
319
320 impl fmt::Display for CodecError {
321 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
322 formatter.write_str(&self.0)
323 }
324 }
325
326 impl std::error::Error for CodecError {}
327
328 impl serde::ser::Error for CodecError {
329 fn custom<T: fmt::Display>(message: T) -> Self {
330 Self(message.to_string())
331 }
332 }
333
334 impl serde::de::Error for CodecError {
335 fn custom<T: fmt::Display>(message: T) -> Self {
336 Self(message.to_string())
337 }
338 }
339
340 #[derive(Debug)]
341 enum Value {
342 U8(u8),
343 U16(u16),
344 U32(u32),
345 U64(u64),
346 String(String),
347 Sequence(Vec<Value>),
348 Struct(Vec<(String, Value)>),
349 Variant(String),
350 }
351
352 struct ValueSerializer;
353
354 impl Serializer for ValueSerializer {
355 type Ok = Value;
356 type Error = CodecError;
357 type SerializeSeq = Impossible<Value, CodecError>;
358 type SerializeTuple = TupleBuilder;
359 type SerializeTupleStruct = Impossible<Value, CodecError>;
360 type SerializeTupleVariant = Impossible<Value, CodecError>;
361 type SerializeMap = Impossible<Value, CodecError>;
362 type SerializeStruct = StructBuilder;
363 type SerializeStructVariant = Impossible<Value, CodecError>;
364
365 fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> {
366 Ok(Value::U8(value))
367 }
368
369 fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> {
370 Ok(Value::U16(value))
371 }
372
373 fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> {
374 Ok(Value::U32(value))
375 }
376
377 fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> {
378 Ok(Value::U64(value))
379 }
380
381 fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
382 Ok(Value::String(value.to_owned()))
383 }
384
385 fn serialize_unit_variant(
386 self,
387 _name: &'static str,
388 _variant_index: u32,
389 variant: &'static str,
390 ) -> Result<Self::Ok, Self::Error> {
391 Ok(Value::Variant(variant.to_owned()))
392 }
393
394 fn serialize_newtype_struct<T>(
395 self,
396 _name: &'static str,
397 value: &T,
398 ) -> Result<Self::Ok, Self::Error>
399 where
400 T: ?Sized + Serialize,
401 {
402 value.serialize(self)
403 }
404
405 fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
406 where
407 T: ?Sized + Serialize,
408 {
409 value.serialize(self)
410 }
411
412 fn serialize_tuple(self, length: usize) -> Result<Self::SerializeTuple, Self::Error> {
413 Ok(TupleBuilder(Vec::with_capacity(length)))
414 }
415
416 fn serialize_struct(
417 self,
418 _name: &'static str,
419 length: usize,
420 ) -> Result<Self::SerializeStruct, Self::Error> {
421 Ok(StructBuilder(Vec::with_capacity(length)))
422 }
423
424 fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> {
425 unsupported()
426 }
427
428 fn serialize_i8(self, _value: i8) -> Result<Self::Ok, Self::Error> {
429 unsupported()
430 }
431
432 fn serialize_i16(self, _value: i16) -> Result<Self::Ok, Self::Error> {
433 unsupported()
434 }
435
436 fn serialize_i32(self, _value: i32) -> Result<Self::Ok, Self::Error> {
437 unsupported()
438 }
439
440 fn serialize_i64(self, _value: i64) -> Result<Self::Ok, Self::Error> {
441 unsupported()
442 }
443
444 fn serialize_i128(self, _value: i128) -> Result<Self::Ok, Self::Error> {
445 unsupported()
446 }
447
448 fn serialize_u128(self, _value: u128) -> Result<Self::Ok, Self::Error> {
449 unsupported()
450 }
451
452 fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
453 unsupported()
454 }
455
456 fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
457 unsupported()
458 }
459
460 fn serialize_char(self, _value: char) -> Result<Self::Ok, Self::Error> {
461 unsupported()
462 }
463
464 fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
465 unsupported()
466 }
467
468 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
469 unsupported()
470 }
471
472 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
473 unsupported()
474 }
475
476 fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
477 unsupported()
478 }
479
480 fn serialize_newtype_variant<T>(
481 self,
482 _name: &'static str,
483 _variant_index: u32,
484 _variant: &'static str,
485 _value: &T,
486 ) -> Result<Self::Ok, Self::Error>
487 where
488 T: ?Sized + Serialize,
489 {
490 unsupported()
491 }
492
493 fn serialize_seq(self, _length: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
494 unsupported()
495 }
496
497 fn serialize_tuple_struct(
498 self,
499 _name: &'static str,
500 _length: usize,
501 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
502 unsupported()
503 }
504
505 fn serialize_tuple_variant(
506 self,
507 _name: &'static str,
508 _variant_index: u32,
509 _variant: &'static str,
510 _length: usize,
511 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
512 unsupported()
513 }
514
515 fn serialize_map(self, _length: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
516 unsupported()
517 }
518
519 fn serialize_struct_variant(
520 self,
521 _name: &'static str,
522 _variant_index: u32,
523 _variant: &'static str,
524 _length: usize,
525 ) -> Result<Self::SerializeStructVariant, Self::Error> {
526 unsupported()
527 }
528 }
529
530 struct TupleBuilder(Vec<Value>);
531
532 impl serde::ser::SerializeTuple for TupleBuilder {
533 type Ok = Value;
534 type Error = CodecError;
535
536 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
537 where
538 T: ?Sized + Serialize,
539 {
540 self.0.push(value.serialize(ValueSerializer)?);
541 Ok(())
542 }
543
544 fn end(self) -> Result<Self::Ok, Self::Error> {
545 Ok(Value::Sequence(self.0))
546 }
547 }
548
549 struct StructBuilder(Vec<(String, Value)>);
550
551 impl SerializeStruct for StructBuilder {
552 type Ok = Value;
553 type Error = CodecError;
554
555 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
556 where
557 T: ?Sized + Serialize,
558 {
559 self.0
560 .push((key.to_owned(), value.serialize(ValueSerializer)?));
561 Ok(())
562 }
563
564 fn end(self) -> Result<Self::Ok, Self::Error> {
565 Ok(Value::Struct(self.0))
566 }
567 }
568
569 fn unsupported<T>() -> Result<T, CodecError> {
570 Err(CodecError("unsupported test value".to_owned()))
571 }
572
573 impl<'de> IntoDeserializer<'de, CodecError> for Value {
574 type Deserializer = Self;
575
576 fn into_deserializer(self) -> Self::Deserializer {
577 self
578 }
579 }
580
581 impl<'de> Deserializer<'de> for Value {
582 type Error = CodecError;
583
584 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
585 where
586 V: Visitor<'de>,
587 {
588 match self {
589 Self::U8(value) => visitor.visit_u8(value),
590 Self::U16(value) => visitor.visit_u16(value),
591 Self::U32(value) => visitor.visit_u32(value),
592 Self::U64(value) => visitor.visit_u64(value),
593 Self::String(value) => visitor.visit_string(value),
594 Self::Sequence(values) => {
595 visitor.visit_seq(serde::de::value::SeqDeserializer::<_, CodecError>::new(
596 values.into_iter(),
597 ))
598 }
599 Self::Struct(fields) => {
600 visitor.visit_map(serde::de::value::MapDeserializer::<_, CodecError>::new(
601 fields.into_iter(),
602 ))
603 }
604 Self::Variant(name) => visitor.visit_enum(serde::de::value::StringDeserializer::<
605 CodecError,
606 >::new(name)),
607 }
608 }
609
610 serde::forward_to_deserialize_any! {
611 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
612 bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
613 map struct enum identifier ignored_any
614 }
615 }
616
617 fn round_trip<T>(value: &T) -> T
618 where
619 T: Serialize + for<'de> Deserialize<'de>,
620 {
621 let encoded = value.serialize(ValueSerializer).expect("serialize");
622 T::deserialize(encoded).expect("deserialize")
623 }
624
625 fn key(value: &str) -> Key {
626 Key::parse(value).expect("valid key")
627 }
628
629 fn object(value: &str) -> ObjectId {
630 ObjectId::parse(value).expect("valid object ID")
631 }
632
633 fn segment() -> SegmentRef {
634 SegmentRef {
635 source_object: object("source_1"),
636 clip_object: object("clip___1"),
637 ordinal: 0,
638 segment_count: 1,
639 start_ms: 10,
640 end_ms: 20,
641 policy: key("policy:v1"),
642 }
643 }
644
645 #[test]
646 fn accepts_all_key_characters_and_boundaries() {
647 for value in ["a", "Az09._-/:", &"x".repeat(MAX_KEY_BYTES)] {
648 assert!(Key::parse(value).is_ok(), "{value:?}");
649 }
650 }
651
652 #[test]
653 fn rejects_invalid_key_shapes() {
654 for value in [
655 "",
656 &"x".repeat(MAX_KEY_BYTES + 1),
657 "has space",
658 "line\nbreak",
659 "é",
660 "key+value",
661 ] {
662 assert!(Key::parse(value).is_err(), "{value:?}");
663 }
664 }
665
666 #[test]
667 fn accepts_and_rejects_object_id_shapes() {
668 for value in ["Ab09-_xy", "________", "00000000"] {
669 assert!(ObjectId::parse(value).is_ok(), "{value:?}");
670 }
671 for value in [
672 "",
673 "1234567",
674 "123456789",
675 "abc+defg",
676 "abc/defg",
677 "abc=defg",
678 "pending:",
679 "pending:N",
680 "é1234567",
681 ] {
682 assert!(ObjectId::parse(value).is_err(), "{value:?}");
683 }
684 }
685
686 #[test]
687 fn validates_feature_boundaries_and_age_exception() {
688 let mut values = [100; FEATURE_COUNT];
689 values[PERCEIVED_AGE_INDEX] = 120;
690 assert_eq!(
691 FeatureVector::new(values)
692 .expect("boundary values")
693 .as_ref(),
694 &values
695 );
696
697 let mut invalid_age = [0; FEATURE_COUNT];
698 invalid_age[PERCEIVED_AGE_INDEX] = 121;
699 assert!(FeatureVector::new(invalid_age).is_err());
700
701 let mut invalid_other = [0; FEATURE_COUNT];
702 invalid_other[0] = 101;
703 assert!(FeatureVector::new(invalid_other).is_err());
704 invalid_other[0] = 0;
705 invalid_other[FEATURE_COUNT - 1] = 101;
706 assert!(FeatureVector::new(invalid_other).is_err());
707 }
708
709 #[test]
710 fn validates_feature_mask_bits() {
711 assert!(FeatureMask::from_bits(0).is_err());
712 assert!(FeatureMask::from_bits(1_u64 << FEATURE_COUNT).is_err());
713 assert!(FeatureMask::from_bits(u64::MAX).is_err());
714
715 let mask = FeatureMask::from_bits(FEATURE_BITS).expect("all defined bits");
716 assert_eq!(u64::from(mask), FEATURE_BITS);
717 }
718
719 #[test]
720 fn validates_segment_bounds() {
721 let mut value = segment();
722 assert!(value.validate().is_ok());
723
724 value.ordinal = value.segment_count;
725 assert!(value.validate().is_err());
726 value.ordinal = 0;
727 value.segment_count = 0;
728 assert!(value.validate().is_err());
729
730 value.segment_count = 1;
731 value.start_ms = value.end_ms;
732 assert!(value.validate().is_err());
733 value.start_ms = value.end_ms + 1;
734 assert!(value.validate().is_err());
735 }
736
737 #[test]
738 fn serde_round_trips_public_values() {
739 let feature = FeatureVector::new([42; FEATURE_COUNT]).expect("features");
740 assert_eq!(round_trip(&key("sample:1")), key("sample:1"));
741 assert_eq!(round_trip(&object("object_1")), object("object_1"));
742 assert_eq!(round_trip(&feature), feature);
743
744 let mask = FeatureMask::from_bits(5).expect("mask");
745 assert_eq!(round_trip(&mask), mask);
746
747 for kind in [
748 RecordingKind::VoiceNote,
749 RecordingKind::Meeting,
750 RecordingKind::Call,
751 RecordingKind::Other,
752 ] {
753 assert_eq!(round_trip(&kind), kind);
754 }
755 }
756
757 #[test]
758 fn serde_round_trips_shared_records() {
759 let segment = segment();
760 assert_eq!(round_trip(&segment), segment);
761
762 let sample = LabeledSample {
763 sample_id: key("sample:1"),
764 attempt_id: key("attempt:1"),
765 speaker_id: key("speaker:1"),
766 cohort_id: key("cohort:1"),
767 group_id: key("group:1"),
768 clip_object: object("clip___1"),
769 primary_language: key("en-US"),
770 recording_kind: RecordingKind::VoiceNote,
771 usable_speech_ms: 12_345,
772 recording_quality: 88,
773 features: FeatureVector::new([50; FEATURE_COUNT]).expect("features"),
774 };
775 assert_eq!(round_trip(&sample), sample);
776 }
777
778 #[test]
779 fn serde_rejects_invalid_validated_values() {
780 assert!(Key::deserialize(Value::String("not valid".to_owned())).is_err());
781 assert!(ObjectId::deserialize(Value::String("pending:".to_owned())).is_err());
782 assert!(FeatureMask::deserialize(Value::U64(0)).is_err());
783
784 let mut values = (0..FEATURE_COUNT).map(|_| Value::U8(0)).collect::<Vec<_>>();
785 values[PERCEIVED_AGE_INDEX] = Value::U8(121);
786 assert!(FeatureVector::deserialize(Value::Sequence(values)).is_err());
787 }
788}