Skip to main content

kcode_speaker_types/
lib.rs

1#![forbid(unsafe_code)]
2
3use serde::{Deserialize, Deserializer, Serialize};
4use std::fmt;
5
6pub const FEATURE_COUNT: usize = 24;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct TypeError(&'static str);
10
11impl TypeError {
12    const fn new(message: &'static str) -> Self {
13        Self(message)
14    }
15}
16
17impl fmt::Display for TypeError {
18    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
19        formatter.write_str(self.0)
20    }
21}
22
23impl std::error::Error for TypeError {}
24
25#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
26#[serde(transparent)]
27pub struct Key(String);
28
29impl Key {
30    pub fn parse(value: &str) -> Result<Self, TypeError> {
31        if value.is_empty() || value.len() > 128 {
32            return Err(TypeError::new(
33                "key must contain between 1 and 128 ASCII characters",
34            ));
35        }
36
37        if !value.bytes().all(|byte| {
38            byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-' | b'/' | b':')
39        }) {
40            return Err(TypeError::new(
41                "key may contain only ASCII letters, digits, '.', '_', '-', '/', and ':'",
42            ));
43        }
44
45        Ok(Self(value.to_owned()))
46    }
47}
48
49impl AsRef<str> for Key {
50    fn as_ref(&self) -> &str {
51        &self.0
52    }
53}
54
55impl<'de> Deserialize<'de> for Key {
56    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
57    where
58        D: Deserializer<'de>,
59    {
60        let value = String::deserialize(deserializer)?;
61        Self::parse(&value).map_err(serde::de::Error::custom)
62    }
63}
64
65#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
66#[serde(transparent)]
67pub struct ObjectId(String);
68
69impl ObjectId {
70    pub fn parse(value: &str) -> Result<Self, TypeError> {
71        if value.len() != 8 {
72            return Err(TypeError::new(
73                "object ID must contain exactly eight base64url characters",
74            ));
75        }
76
77        if !value
78            .bytes()
79            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))
80        {
81            return Err(TypeError::new(
82                "object ID may contain only base64url characters",
83            ));
84        }
85
86        Ok(Self(value.to_owned()))
87    }
88}
89
90impl AsRef<str> for ObjectId {
91    fn as_ref(&self) -> &str {
92        &self.0
93    }
94}
95
96impl<'de> Deserialize<'de> for ObjectId {
97    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98    where
99        D: Deserializer<'de>,
100    {
101        let value = String::deserialize(deserializer)?;
102        Self::parse(&value).map_err(serde::de::Error::custom)
103    }
104}
105
106#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
107#[serde(transparent)]
108pub struct FeatureVector([u8; FEATURE_COUNT]);
109
110impl FeatureVector {
111    pub const fn new(values: [u8; FEATURE_COUNT]) -> Result<Self, TypeError> {
112        let mut index = 0;
113        while index < FEATURE_COUNT {
114            if values[index] > 100 {
115                return Err(TypeError::new(
116                    "feature values must be integers in the range 0..=100",
117                ));
118            }
119            index += 1;
120        }
121
122        Ok(Self(values))
123    }
124}
125
126impl AsRef<[u8; FEATURE_COUNT]> for FeatureVector {
127    fn as_ref(&self) -> &[u8; FEATURE_COUNT] {
128        &self.0
129    }
130}
131
132impl<'de> Deserialize<'de> for FeatureVector {
133    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
134    where
135        D: Deserializer<'de>,
136    {
137        let values = <[u8; FEATURE_COUNT]>::deserialize(deserializer)?;
138        Self::new(values).map_err(serde::de::Error::custom)
139    }
140}
141
142#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
143#[serde(transparent)]
144pub struct FeatureMask(u64);
145
146impl FeatureMask {
147    const ALLOWED_BITS: u64 = (1_u64 << FEATURE_COUNT) - 1;
148
149    pub const fn from_bits(bits: u64) -> Result<Self, TypeError> {
150        if bits == 0 {
151            return Err(TypeError::new("feature mask must be nonempty"));
152        }
153
154        if bits & !Self::ALLOWED_BITS != 0 {
155            return Err(TypeError::new(
156                "feature mask may contain only bits 0 through 23",
157            ));
158        }
159
160        Ok(Self(bits))
161    }
162}
163
164impl From<FeatureMask> for u64 {
165    fn from(mask: FeatureMask) -> Self {
166        mask.0
167    }
168}
169
170impl<'de> Deserialize<'de> for FeatureMask {
171    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
172    where
173        D: Deserializer<'de>,
174    {
175        let bits = u64::deserialize(deserializer)?;
176        Self::from_bits(bits).map_err(serde::de::Error::custom)
177    }
178}
179
180#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
181pub enum RecordingKind {
182    VoiceNote,
183    Meeting,
184    Call,
185    Other,
186}
187
188#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
189pub struct SegmentRef {
190    pub source_object: ObjectId,
191    pub clip_object: ObjectId,
192    pub ordinal: u16,
193    pub segment_count: u16,
194    pub start_ms: u64,
195    pub end_ms: u64,
196    pub policy: Key,
197}
198
199impl SegmentRef {
200    pub fn validate(&self) -> Result<(), TypeError> {
201        if self.ordinal >= self.segment_count {
202            return Err(TypeError::new(
203                "segment ordinal must be less than segment count",
204            ));
205        }
206
207        if self.start_ms >= self.end_ms {
208            return Err(TypeError::new(
209                "segment start must be less than segment end",
210            ));
211        }
212
213        Ok(())
214    }
215}
216
217#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
218pub struct LabeledSample {
219    pub sample_id: Key,
220    pub attempt_id: Key,
221    pub speaker_id: Key,
222    pub cohort_id: Key,
223    pub group_id: Key,
224    pub clip_object: ObjectId,
225    pub primary_language: Key,
226    pub recording_kind: RecordingKind,
227    pub usable_speech_ms: u32,
228    pub recording_quality: u8,
229    pub features: FeatureVector,
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235    use serde::de::{DeserializeOwned, IntoDeserializer, Visitor};
236    use serde::ser::{
237        SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
238        SerializeTupleStruct, SerializeTupleVariant,
239    };
240
241    const FIRST_FEATURE: FeatureMask = match FeatureMask::from_bits(1) {
242        Ok(mask) => mask,
243        Err(_) => panic!("bit zero is a valid nonempty feature mask"),
244    };
245
246    #[derive(Debug, Eq, PartialEq)]
247    struct WireError(String);
248
249    impl fmt::Display for WireError {
250        fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
251            formatter.write_str(&self.0)
252        }
253    }
254
255    impl std::error::Error for WireError {}
256
257    impl serde::ser::Error for WireError {
258        fn custom<T>(message: T) -> Self
259        where
260            T: fmt::Display,
261        {
262            Self(message.to_string())
263        }
264    }
265
266    impl serde::de::Error for WireError {
267        fn custom<T>(message: T) -> Self
268        where
269            T: fmt::Display,
270        {
271            Self(message.to_string())
272        }
273    }
274
275    #[derive(Clone, Debug, PartialEq)]
276    enum WireValue {
277        Unit,
278        Bool(bool),
279        I64(i64),
280        U64(u64),
281        String(String),
282        Seq(Vec<WireValue>),
283        Map(Vec<(WireValue, WireValue)>),
284    }
285
286    #[derive(Clone, Copy)]
287    struct WireSerializer;
288
289    struct SequenceSerializer {
290        values: Vec<WireValue>,
291    }
292
293    impl SequenceSerializer {
294        fn push<T>(&mut self, value: &T) -> Result<(), WireError>
295        where
296            T: ?Sized + Serialize,
297        {
298            self.values.push(value.serialize(WireSerializer)?);
299            Ok(())
300        }
301
302        fn finish(self) -> WireValue {
303            WireValue::Seq(self.values)
304        }
305    }
306
307    impl SerializeSeq for SequenceSerializer {
308        type Ok = WireValue;
309        type Error = WireError;
310
311        fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
312        where
313            T: ?Sized + Serialize,
314        {
315            self.push(value)
316        }
317
318        fn end(self) -> Result<Self::Ok, Self::Error> {
319            Ok(self.finish())
320        }
321    }
322
323    impl SerializeTuple for SequenceSerializer {
324        type Ok = WireValue;
325        type Error = WireError;
326
327        fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
328        where
329            T: ?Sized + Serialize,
330        {
331            self.push(value)
332        }
333
334        fn end(self) -> Result<Self::Ok, Self::Error> {
335            Ok(self.finish())
336        }
337    }
338
339    impl SerializeTupleStruct for SequenceSerializer {
340        type Ok = WireValue;
341        type Error = WireError;
342
343        fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
344        where
345            T: ?Sized + Serialize,
346        {
347            self.push(value)
348        }
349
350        fn end(self) -> Result<Self::Ok, Self::Error> {
351            Ok(self.finish())
352        }
353    }
354
355    struct TupleVariantSerializer {
356        variant: &'static str,
357        values: Vec<WireValue>,
358    }
359
360    impl SerializeTupleVariant for TupleVariantSerializer {
361        type Ok = WireValue;
362        type Error = WireError;
363
364        fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
365        where
366            T: ?Sized + Serialize,
367        {
368            self.values.push(value.serialize(WireSerializer)?);
369            Ok(())
370        }
371
372        fn end(self) -> Result<Self::Ok, Self::Error> {
373            Ok(WireValue::Map(vec![(
374                WireValue::String(self.variant.to_owned()),
375                WireValue::Seq(self.values),
376            )]))
377        }
378    }
379
380    struct MapSerializer {
381        entries: Vec<(WireValue, WireValue)>,
382        next_key: Option<WireValue>,
383    }
384
385    impl SerializeMap for MapSerializer {
386        type Ok = WireValue;
387        type Error = WireError;
388
389        fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
390        where
391            T: ?Sized + Serialize,
392        {
393            if self.next_key.is_some() {
394                return Err(WireError("map key is missing a value".to_owned()));
395            }
396            self.next_key = Some(key.serialize(WireSerializer)?);
397            Ok(())
398        }
399
400        fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
401        where
402            T: ?Sized + Serialize,
403        {
404            let key = self
405                .next_key
406                .take()
407                .ok_or_else(|| WireError("map value is missing a key".to_owned()))?;
408            self.entries.push((key, value.serialize(WireSerializer)?));
409            Ok(())
410        }
411
412        fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
413        where
414            K: ?Sized + Serialize,
415            V: ?Sized + Serialize,
416        {
417            self.entries.push((
418                key.serialize(WireSerializer)?,
419                value.serialize(WireSerializer)?,
420            ));
421            Ok(())
422        }
423
424        fn end(self) -> Result<Self::Ok, Self::Error> {
425            if self.next_key.is_some() {
426                return Err(WireError("map key is missing a value".to_owned()));
427            }
428            Ok(WireValue::Map(self.entries))
429        }
430    }
431
432    impl SerializeStruct for MapSerializer {
433        type Ok = WireValue;
434        type Error = WireError;
435
436        fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
437        where
438            T: ?Sized + Serialize,
439        {
440            self.entries.push((
441                WireValue::String(key.to_owned()),
442                value.serialize(WireSerializer)?,
443            ));
444            Ok(())
445        }
446
447        fn end(self) -> Result<Self::Ok, Self::Error> {
448            Ok(WireValue::Map(self.entries))
449        }
450    }
451
452    struct StructVariantSerializer {
453        variant: &'static str,
454        entries: Vec<(WireValue, WireValue)>,
455    }
456
457    impl SerializeStructVariant for StructVariantSerializer {
458        type Ok = WireValue;
459        type Error = WireError;
460
461        fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
462        where
463            T: ?Sized + Serialize,
464        {
465            self.entries.push((
466                WireValue::String(key.to_owned()),
467                value.serialize(WireSerializer)?,
468            ));
469            Ok(())
470        }
471
472        fn end(self) -> Result<Self::Ok, Self::Error> {
473            Ok(WireValue::Map(vec![(
474                WireValue::String(self.variant.to_owned()),
475                WireValue::Map(self.entries),
476            )]))
477        }
478    }
479
480    impl serde::Serializer for WireSerializer {
481        type Ok = WireValue;
482        type Error = WireError;
483        type SerializeSeq = SequenceSerializer;
484        type SerializeTuple = SequenceSerializer;
485        type SerializeTupleStruct = SequenceSerializer;
486        type SerializeTupleVariant = TupleVariantSerializer;
487        type SerializeMap = MapSerializer;
488        type SerializeStruct = MapSerializer;
489        type SerializeStructVariant = StructVariantSerializer;
490
491        fn serialize_bool(self, value: bool) -> Result<Self::Ok, Self::Error> {
492            Ok(WireValue::Bool(value))
493        }
494
495        fn serialize_i8(self, value: i8) -> Result<Self::Ok, Self::Error> {
496            Ok(WireValue::I64(i64::from(value)))
497        }
498
499        fn serialize_i16(self, value: i16) -> Result<Self::Ok, Self::Error> {
500            Ok(WireValue::I64(i64::from(value)))
501        }
502
503        fn serialize_i32(self, value: i32) -> Result<Self::Ok, Self::Error> {
504            Ok(WireValue::I64(i64::from(value)))
505        }
506
507        fn serialize_i64(self, value: i64) -> Result<Self::Ok, Self::Error> {
508            Ok(WireValue::I64(value))
509        }
510
511        fn serialize_i128(self, value: i128) -> Result<Self::Ok, Self::Error> {
512            let value = i64::try_from(value)
513                .map_err(|_| WireError("i128 is outside the test wire range".to_owned()))?;
514            Ok(WireValue::I64(value))
515        }
516
517        fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> {
518            Ok(WireValue::U64(u64::from(value)))
519        }
520
521        fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> {
522            Ok(WireValue::U64(u64::from(value)))
523        }
524
525        fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> {
526            Ok(WireValue::U64(u64::from(value)))
527        }
528
529        fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> {
530            Ok(WireValue::U64(value))
531        }
532
533        fn serialize_u128(self, value: u128) -> Result<Self::Ok, Self::Error> {
534            let value = u64::try_from(value)
535                .map_err(|_| WireError("u128 is outside the test wire range".to_owned()))?;
536            Ok(WireValue::U64(value))
537        }
538
539        fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
540            Err(WireError(
541                "floating-point values are unsupported by the test wire".to_owned(),
542            ))
543        }
544
545        fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
546            Err(WireError(
547                "floating-point values are unsupported by the test wire".to_owned(),
548            ))
549        }
550
551        fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
552            Ok(WireValue::String(value.to_string()))
553        }
554
555        fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
556            Ok(WireValue::String(value.to_owned()))
557        }
558
559        fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
560            Ok(WireValue::Seq(
561                value
562                    .iter()
563                    .map(|byte| WireValue::U64(u64::from(*byte)))
564                    .collect(),
565            ))
566        }
567
568        fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
569            Ok(WireValue::Unit)
570        }
571
572        fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
573        where
574            T: ?Sized + Serialize,
575        {
576            value.serialize(self)
577        }
578
579        fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
580            Ok(WireValue::Unit)
581        }
582
583        fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
584            Ok(WireValue::Unit)
585        }
586
587        fn serialize_unit_variant(
588            self,
589            _name: &'static str,
590            _variant_index: u32,
591            variant: &'static str,
592        ) -> Result<Self::Ok, Self::Error> {
593            Ok(WireValue::String(variant.to_owned()))
594        }
595
596        fn serialize_newtype_struct<T>(
597            self,
598            _name: &'static str,
599            value: &T,
600        ) -> Result<Self::Ok, Self::Error>
601        where
602            T: ?Sized + Serialize,
603        {
604            value.serialize(self)
605        }
606
607        fn serialize_newtype_variant<T>(
608            self,
609            _name: &'static str,
610            _variant_index: u32,
611            variant: &'static str,
612            value: &T,
613        ) -> Result<Self::Ok, Self::Error>
614        where
615            T: ?Sized + Serialize,
616        {
617            Ok(WireValue::Map(vec![(
618                WireValue::String(variant.to_owned()),
619                value.serialize(self)?,
620            )]))
621        }
622
623        fn serialize_seq(self, length: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
624            Ok(SequenceSerializer {
625                values: Vec::with_capacity(length.unwrap_or(0)),
626            })
627        }
628
629        fn serialize_tuple(self, length: usize) -> Result<Self::SerializeTuple, Self::Error> {
630            Ok(SequenceSerializer {
631                values: Vec::with_capacity(length),
632            })
633        }
634
635        fn serialize_tuple_struct(
636            self,
637            _name: &'static str,
638            length: usize,
639        ) -> Result<Self::SerializeTupleStruct, Self::Error> {
640            Ok(SequenceSerializer {
641                values: Vec::with_capacity(length),
642            })
643        }
644
645        fn serialize_tuple_variant(
646            self,
647            _name: &'static str,
648            _variant_index: u32,
649            variant: &'static str,
650            length: usize,
651        ) -> Result<Self::SerializeTupleVariant, Self::Error> {
652            Ok(TupleVariantSerializer {
653                variant,
654                values: Vec::with_capacity(length),
655            })
656        }
657
658        fn serialize_map(self, length: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
659            Ok(MapSerializer {
660                entries: Vec::with_capacity(length.unwrap_or(0)),
661                next_key: None,
662            })
663        }
664
665        fn serialize_struct(
666            self,
667            _name: &'static str,
668            length: usize,
669        ) -> Result<Self::SerializeStruct, Self::Error> {
670            Ok(MapSerializer {
671                entries: Vec::with_capacity(length),
672                next_key: None,
673            })
674        }
675
676        fn serialize_struct_variant(
677            self,
678            _name: &'static str,
679            _variant_index: u32,
680            variant: &'static str,
681            length: usize,
682        ) -> Result<Self::SerializeStructVariant, Self::Error> {
683            Ok(StructVariantSerializer {
684                variant,
685                entries: Vec::with_capacity(length),
686            })
687        }
688    }
689
690    impl<'de> IntoDeserializer<'de, WireError> for WireValue {
691        type Deserializer = Self;
692
693        fn into_deserializer(self) -> Self::Deserializer {
694            self
695        }
696    }
697
698    impl<'de> serde::Deserializer<'de> for WireValue {
699        type Error = WireError;
700
701        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
702        where
703            V: Visitor<'de>,
704        {
705            match self {
706                Self::Unit => visitor.visit_unit(),
707                Self::Bool(value) => visitor.visit_bool(value),
708                Self::I64(value) => visitor.visit_i64(value),
709                Self::U64(value) => visitor.visit_u64(value),
710                Self::String(value) => visitor.visit_string(value),
711                Self::Seq(values) => {
712                    let mut sequence = serde::de::value::SeqDeserializer::new(values.into_iter());
713                    let result = visitor.visit_seq(&mut sequence)?;
714                    sequence.end()?;
715                    Ok(result)
716                }
717                Self::Map(entries) => {
718                    let mut map = serde::de::value::MapDeserializer::new(entries.into_iter());
719                    let result = visitor.visit_map(&mut map)?;
720                    map.end()?;
721                    Ok(result)
722                }
723            }
724        }
725
726        fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
727        where
728            V: Visitor<'de>,
729        {
730            match self {
731                Self::Unit => visitor.visit_none(),
732                value => visitor.visit_some(value),
733            }
734        }
735
736        fn deserialize_enum<V>(
737            self,
738            _name: &'static str,
739            _variants: &'static [&'static str],
740            visitor: V,
741        ) -> Result<V::Value, Self::Error>
742        where
743            V: Visitor<'de>,
744        {
745            match self {
746                Self::String(value) => visitor.visit_enum(serde::de::value::StringDeserializer::<
747                    WireError,
748                >::new(value)),
749                _ => Err(WireError(
750                    "the test wire supports only unit enum variants".to_owned(),
751                )),
752            }
753        }
754
755        fn deserialize_newtype_struct<V>(
756            self,
757            _name: &'static str,
758            visitor: V,
759        ) -> Result<V::Value, Self::Error>
760        where
761            V: Visitor<'de>,
762        {
763            visitor.visit_newtype_struct(self)
764        }
765
766        fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
767        where
768            V: Visitor<'de>,
769        {
770            match self {
771                Self::String(value) => visitor.visit_string(value),
772                value => value.deserialize_any(visitor),
773            }
774        }
775
776        fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
777        where
778            V: Visitor<'de>,
779        {
780            visitor.visit_unit()
781        }
782
783        serde::forward_to_deserialize_any! {
784            bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
785            bytes byte_buf unit unit_struct seq tuple tuple_struct map struct
786        }
787    }
788
789    fn round_trip<T>(value: &T) -> T
790    where
791        T: Serialize + DeserializeOwned,
792    {
793        let wire = value.serialize(WireSerializer).unwrap();
794        T::deserialize(wire).unwrap()
795    }
796
797    fn deserialize_wire<T>(value: WireValue) -> Result<T, WireError>
798    where
799        T: DeserializeOwned,
800    {
801        T::deserialize(value)
802    }
803
804    fn sample_features() -> FeatureVector {
805        let mut values = [0; FEATURE_COUNT];
806        for (index, value) in values.iter_mut().enumerate() {
807            *value = u8::try_from(index * 4).unwrap();
808        }
809        FeatureVector::new(values).unwrap()
810    }
811
812    fn sample_segment() -> SegmentRef {
813        SegmentRef {
814            source_object: ObjectId::parse("Source_1").unwrap(),
815            clip_object: ObjectId::parse("Clip-001").unwrap(),
816            ordinal: 1,
817            segment_count: 3,
818            start_ms: 2_000,
819            end_ms: 4_750,
820            policy: Key::parse("speaker/profile-v2").unwrap(),
821        }
822    }
823
824    fn sample_label() -> LabeledSample {
825        LabeledSample {
826            sample_id: Key::parse("sample:1").unwrap(),
827            attempt_id: Key::parse("attempt:1").unwrap(),
828            speaker_id: Key::parse("speaker:1").unwrap(),
829            cohort_id: Key::parse("cohort:alpha").unwrap(),
830            group_id: Key::parse("group:control").unwrap(),
831            clip_object: ObjectId::parse("Clip-001").unwrap(),
832            primary_language: Key::parse("en-US").unwrap(),
833            recording_kind: RecordingKind::Meeting,
834            usable_speech_ms: 42_500,
835            recording_quality: 88,
836            features: sample_features(),
837        }
838    }
839
840    #[test]
841    fn keys_enforce_the_documented_alphabet_and_bounds() {
842        assert_eq!(
843            Key::parse("speaker_1/en:primary").unwrap().as_ref(),
844            "speaker_1/en:primary"
845        );
846        assert!(Key::parse(&"a".repeat(128)).is_ok());
847        assert!(Key::parse("").is_err());
848        assert!(Key::parse(&"a".repeat(129)).is_err());
849        assert!(Key::parse("not allowed").is_err());
850        assert!(Key::parse("café").is_err());
851    }
852
853    #[test]
854    fn keys_and_object_ids_have_deterministic_ordering() {
855        assert!(Key::parse("a").unwrap() < Key::parse("b").unwrap());
856        assert!(ObjectId::parse("AAAAAAA-").unwrap() < ObjectId::parse("AAAAAAA_").unwrap());
857    }
858
859    #[test]
860    fn object_ids_are_exactly_eight_base64url_characters() {
861        assert_eq!(ObjectId::parse("Ab0-_xyz").unwrap().as_ref(), "Ab0-_xyz");
862        assert!(ObjectId::parse("short").is_err());
863        assert!(ObjectId::parse("123456789").is_err());
864        assert!(ObjectId::parse("pending:").is_err());
865        assert!(ObjectId::parse("1234567=").is_err());
866    }
867
868    #[test]
869    fn every_feature_uses_the_uniform_zero_to_one_hundred_boundary() {
870        assert_eq!(FEATURE_COUNT, 24);
871        assert!(FeatureVector::new([0; FEATURE_COUNT]).is_ok());
872        assert!(FeatureVector::new([100; FEATURE_COUNT]).is_ok());
873
874        for index in 0..FEATURE_COUNT {
875            let mut values = [0; FEATURE_COUNT];
876            values[index] = 101;
877            assert!(
878                FeatureVector::new(values).is_err(),
879                "feature index {index} accepted a value above 100"
880            );
881        }
882
883        let mut former_age_exception = [0; FEATURE_COUNT];
884        former_age_exception[10] = 101;
885        assert!(FeatureVector::new(former_age_exception).is_err());
886    }
887
888    #[test]
889    fn feature_masks_are_const_nonempty_and_limited_to_the_frozen_24_bits() {
890        assert_eq!(u64::from(FIRST_FEATURE), 1);
891        assert!(FeatureMask::from_bits(0).is_err());
892
893        let all_features = (1_u64 << FEATURE_COUNT) - 1;
894        assert_eq!(
895            u64::from(FeatureMask::from_bits(all_features).unwrap()),
896            all_features
897        );
898        assert!(FeatureMask::from_bits(1_u64 << FEATURE_COUNT).is_err());
899        assert!(FeatureMask::from_bits(1_u64 << 34).is_err());
900    }
901
902    #[test]
903    fn segments_require_valid_ordinals_and_nonempty_time_ranges() {
904        let mut segment = sample_segment();
905        assert!(segment.validate().is_ok());
906
907        segment.ordinal = segment.segment_count;
908        assert!(segment.validate().is_err());
909
910        segment.ordinal = 0;
911        segment.segment_count = 0;
912        assert!(segment.validate().is_err());
913
914        segment.segment_count = 1;
915        segment.start_ms = segment.end_ms;
916        assert!(segment.validate().is_err());
917
918        segment.start_ms = u64::MAX - 1;
919        segment.end_ms = u64::MAX;
920        assert!(segment.validate().is_ok());
921    }
922
923    #[test]
924    fn serde_round_trips_validated_values_and_public_records() {
925        let key = Key::parse("speaker:round-trip").unwrap();
926        assert_eq!(round_trip(&key), key);
927
928        let object_id = ObjectId::parse("Ab0-_xyz").unwrap();
929        assert_eq!(round_trip(&object_id), object_id);
930
931        let features = sample_features();
932        assert_eq!(round_trip(&features), features);
933
934        let mask = FeatureMask::from_bits((1_u64 << FEATURE_COUNT) - 1).unwrap();
935        assert_eq!(round_trip(&mask), mask);
936
937        assert_eq!(
938            round_trip(&RecordingKind::VoiceNote),
939            RecordingKind::VoiceNote
940        );
941
942        let segment = sample_segment();
943        assert_eq!(round_trip(&segment), segment);
944
945        let label = sample_label();
946        assert_eq!(round_trip(&label), label);
947    }
948
949    #[test]
950    fn invalid_deserialization_cannot_bypass_private_validation() {
951        assert!(deserialize_wire::<Key>(WireValue::String(String::new())).is_err());
952        assert!(deserialize_wire::<Key>(WireValue::String("invalid key".to_owned())).is_err());
953        assert!(deserialize_wire::<ObjectId>(WireValue::String("pending:".to_owned())).is_err());
954
955        let mut invalid_features = vec![WireValue::U64(0); FEATURE_COUNT];
956        invalid_features[10] = WireValue::U64(101);
957        assert!(deserialize_wire::<FeatureVector>(WireValue::Seq(invalid_features)).is_err());
958        assert!(
959            deserialize_wire::<FeatureVector>(WireValue::Seq(vec![
960                WireValue::U64(0);
961                FEATURE_COUNT - 1
962            ]))
963            .is_err()
964        );
965
966        assert!(deserialize_wire::<FeatureMask>(WireValue::U64(0)).is_err());
967        assert!(deserialize_wire::<FeatureMask>(WireValue::U64(1_u64 << FEATURE_COUNT)).is_err());
968    }
969}