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}