Skip to main content

kcode_speaker_types/
lib.rs

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}