#![forbid(unsafe_code)]
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;
pub const FEATURE_COUNT: usize = 24;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TypeError(&'static str);
impl TypeError {
const fn new(message: &'static str) -> Self {
Self(message)
}
}
impl fmt::Display for TypeError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.0)
}
}
impl std::error::Error for TypeError {}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(transparent)]
pub struct Key(String);
impl Key {
pub fn parse(value: &str) -> Result<Self, TypeError> {
if value.is_empty() || value.len() > 128 {
return Err(TypeError::new(
"key must contain between 1 and 128 ASCII characters",
));
}
if !value.bytes().all(|byte| {
byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-' | b'/' | b':')
}) {
return Err(TypeError::new(
"key may contain only ASCII letters, digits, '.', '_', '-', '/', and ':'",
));
}
Ok(Self(value.to_owned()))
}
}
impl AsRef<str> for Key {
fn as_ref(&self) -> &str {
&self.0
}
}
impl<'de> Deserialize<'de> for Key {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
Self::parse(&value).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(transparent)]
pub struct ObjectId(String);
impl ObjectId {
pub fn parse(value: &str) -> Result<Self, TypeError> {
if value.len() != 8 {
return Err(TypeError::new(
"object ID must contain exactly eight base64url characters",
));
}
if !value
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))
{
return Err(TypeError::new(
"object ID may contain only base64url characters",
));
}
Ok(Self(value.to_owned()))
}
}
impl AsRef<str> for ObjectId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl<'de> Deserialize<'de> for ObjectId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
Self::parse(&value).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
#[serde(transparent)]
pub struct FeatureVector([u8; FEATURE_COUNT]);
impl FeatureVector {
pub const fn new(values: [u8; FEATURE_COUNT]) -> Result<Self, TypeError> {
let mut index = 0;
while index < FEATURE_COUNT {
if values[index] > 100 {
return Err(TypeError::new(
"feature values must be integers in the range 0..=100",
));
}
index += 1;
}
Ok(Self(values))
}
}
impl AsRef<[u8; FEATURE_COUNT]> for FeatureVector {
fn as_ref(&self) -> &[u8; FEATURE_COUNT] {
&self.0
}
}
impl<'de> Deserialize<'de> for FeatureVector {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let values = <[u8; FEATURE_COUNT]>::deserialize(deserializer)?;
Self::new(values).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
#[serde(transparent)]
pub struct FeatureMask(u64);
impl FeatureMask {
const ALLOWED_BITS: u64 = (1_u64 << FEATURE_COUNT) - 1;
pub const fn from_bits(bits: u64) -> Result<Self, TypeError> {
if bits == 0 {
return Err(TypeError::new("feature mask must be nonempty"));
}
if bits & !Self::ALLOWED_BITS != 0 {
return Err(TypeError::new(
"feature mask may contain only bits 0 through 23",
));
}
Ok(Self(bits))
}
}
impl From<FeatureMask> for u64 {
fn from(mask: FeatureMask) -> Self {
mask.0
}
}
impl<'de> Deserialize<'de> for FeatureMask {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let bits = u64::deserialize(deserializer)?;
Self::from_bits(bits).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum RecordingKind {
VoiceNote,
Meeting,
Call,
Other,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct SegmentRef {
pub source_object: ObjectId,
pub clip_object: ObjectId,
pub ordinal: u16,
pub segment_count: u16,
pub start_ms: u64,
pub end_ms: u64,
pub policy: Key,
}
impl SegmentRef {
pub fn validate(&self) -> Result<(), TypeError> {
if self.ordinal >= self.segment_count {
return Err(TypeError::new(
"segment ordinal must be less than segment count",
));
}
if self.start_ms >= self.end_ms {
return Err(TypeError::new(
"segment start must be less than segment end",
));
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct LabeledSample {
pub sample_id: Key,
pub attempt_id: Key,
pub speaker_id: Key,
pub cohort_id: Key,
pub group_id: Key,
pub clip_object: ObjectId,
pub primary_language: Key,
pub recording_kind: RecordingKind,
pub usable_speech_ms: u32,
pub recording_quality: u8,
pub features: FeatureVector,
}
#[cfg(test)]
mod tests {
use super::*;
use serde::de::{DeserializeOwned, IntoDeserializer, Visitor};
use serde::ser::{
SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
SerializeTupleStruct, SerializeTupleVariant,
};
const FIRST_FEATURE: FeatureMask = match FeatureMask::from_bits(1) {
Ok(mask) => mask,
Err(_) => panic!("bit zero is a valid nonempty feature mask"),
};
#[derive(Debug, Eq, PartialEq)]
struct WireError(String);
impl fmt::Display for WireError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(&self.0)
}
}
impl std::error::Error for WireError {}
impl serde::ser::Error for WireError {
fn custom<T>(message: T) -> Self
where
T: fmt::Display,
{
Self(message.to_string())
}
}
impl serde::de::Error for WireError {
fn custom<T>(message: T) -> Self
where
T: fmt::Display,
{
Self(message.to_string())
}
}
#[derive(Clone, Debug, PartialEq)]
enum WireValue {
Unit,
Bool(bool),
I64(i64),
U64(u64),
String(String),
Seq(Vec<WireValue>),
Map(Vec<(WireValue, WireValue)>),
}
#[derive(Clone, Copy)]
struct WireSerializer;
struct SequenceSerializer {
values: Vec<WireValue>,
}
impl SequenceSerializer {
fn push<T>(&mut self, value: &T) -> Result<(), WireError>
where
T: ?Sized + Serialize,
{
self.values.push(value.serialize(WireSerializer)?);
Ok(())
}
fn finish(self) -> WireValue {
WireValue::Seq(self.values)
}
}
impl SerializeSeq for SequenceSerializer {
type Ok = WireValue;
type Error = WireError;
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
self.push(value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(self.finish())
}
}
impl SerializeTuple for SequenceSerializer {
type Ok = WireValue;
type Error = WireError;
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
self.push(value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(self.finish())
}
}
impl SerializeTupleStruct for SequenceSerializer {
type Ok = WireValue;
type Error = WireError;
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
self.push(value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(self.finish())
}
}
struct TupleVariantSerializer {
variant: &'static str,
values: Vec<WireValue>,
}
impl SerializeTupleVariant for TupleVariantSerializer {
type Ok = WireValue;
type Error = WireError;
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
self.values.push(value.serialize(WireSerializer)?);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Map(vec![(
WireValue::String(self.variant.to_owned()),
WireValue::Seq(self.values),
)]))
}
}
struct MapSerializer {
entries: Vec<(WireValue, WireValue)>,
next_key: Option<WireValue>,
}
impl SerializeMap for MapSerializer {
type Ok = WireValue;
type Error = WireError;
fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
if self.next_key.is_some() {
return Err(WireError("map key is missing a value".to_owned()));
}
self.next_key = Some(key.serialize(WireSerializer)?);
Ok(())
}
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
let key = self
.next_key
.take()
.ok_or_else(|| WireError("map value is missing a key".to_owned()))?;
self.entries.push((key, value.serialize(WireSerializer)?));
Ok(())
}
fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
where
K: ?Sized + Serialize,
V: ?Sized + Serialize,
{
self.entries.push((
key.serialize(WireSerializer)?,
value.serialize(WireSerializer)?,
));
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
if self.next_key.is_some() {
return Err(WireError("map key is missing a value".to_owned()));
}
Ok(WireValue::Map(self.entries))
}
}
impl SerializeStruct for MapSerializer {
type Ok = WireValue;
type Error = WireError;
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
self.entries.push((
WireValue::String(key.to_owned()),
value.serialize(WireSerializer)?,
));
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Map(self.entries))
}
}
struct StructVariantSerializer {
variant: &'static str,
entries: Vec<(WireValue, WireValue)>,
}
impl SerializeStructVariant for StructVariantSerializer {
type Ok = WireValue;
type Error = WireError;
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
self.entries.push((
WireValue::String(key.to_owned()),
value.serialize(WireSerializer)?,
));
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Map(vec![(
WireValue::String(self.variant.to_owned()),
WireValue::Map(self.entries),
)]))
}
}
impl serde::Serializer for WireSerializer {
type Ok = WireValue;
type Error = WireError;
type SerializeSeq = SequenceSerializer;
type SerializeTuple = SequenceSerializer;
type SerializeTupleStruct = SequenceSerializer;
type SerializeTupleVariant = TupleVariantSerializer;
type SerializeMap = MapSerializer;
type SerializeStruct = MapSerializer;
type SerializeStructVariant = StructVariantSerializer;
fn serialize_bool(self, value: bool) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Bool(value))
}
fn serialize_i8(self, value: i8) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::I64(i64::from(value)))
}
fn serialize_i16(self, value: i16) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::I64(i64::from(value)))
}
fn serialize_i32(self, value: i32) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::I64(i64::from(value)))
}
fn serialize_i64(self, value: i64) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::I64(value))
}
fn serialize_i128(self, value: i128) -> Result<Self::Ok, Self::Error> {
let value = i64::try_from(value)
.map_err(|_| WireError("i128 is outside the test wire range".to_owned()))?;
Ok(WireValue::I64(value))
}
fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::U64(u64::from(value)))
}
fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::U64(u64::from(value)))
}
fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::U64(u64::from(value)))
}
fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::U64(value))
}
fn serialize_u128(self, value: u128) -> Result<Self::Ok, Self::Error> {
let value = u64::try_from(value)
.map_err(|_| WireError("u128 is outside the test wire range".to_owned()))?;
Ok(WireValue::U64(value))
}
fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
Err(WireError(
"floating-point values are unsupported by the test wire".to_owned(),
))
}
fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
Err(WireError(
"floating-point values are unsupported by the test wire".to_owned(),
))
}
fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::String(value.to_string()))
}
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::String(value.to_owned()))
}
fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Seq(
value
.iter()
.map(|byte| WireValue::U64(u64::from(*byte)))
.collect(),
))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Unit)
}
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize,
{
value.serialize(self)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Unit)
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::Unit)
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Ok(WireValue::String(variant.to_owned()))
}
fn serialize_newtype_struct<T>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize,
{
value.serialize(self)
}
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize,
{
Ok(WireValue::Map(vec![(
WireValue::String(variant.to_owned()),
value.serialize(self)?,
)]))
}
fn serialize_seq(self, length: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Ok(SequenceSerializer {
values: Vec::with_capacity(length.unwrap_or(0)),
})
}
fn serialize_tuple(self, length: usize) -> Result<Self::SerializeTuple, Self::Error> {
Ok(SequenceSerializer {
values: Vec::with_capacity(length),
})
}
fn serialize_tuple_struct(
self,
_name: &'static str,
length: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Ok(SequenceSerializer {
values: Vec::with_capacity(length),
})
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
length: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Ok(TupleVariantSerializer {
variant,
values: Vec::with_capacity(length),
})
}
fn serialize_map(self, length: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Ok(MapSerializer {
entries: Vec::with_capacity(length.unwrap_or(0)),
next_key: None,
})
}
fn serialize_struct(
self,
_name: &'static str,
length: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Ok(MapSerializer {
entries: Vec::with_capacity(length),
next_key: None,
})
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
length: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Ok(StructVariantSerializer {
variant,
entries: Vec::with_capacity(length),
})
}
}
impl<'de> IntoDeserializer<'de, WireError> for WireValue {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
impl<'de> serde::Deserializer<'de> for WireValue {
type Error = WireError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Self::Unit => visitor.visit_unit(),
Self::Bool(value) => visitor.visit_bool(value),
Self::I64(value) => visitor.visit_i64(value),
Self::U64(value) => visitor.visit_u64(value),
Self::String(value) => visitor.visit_string(value),
Self::Seq(values) => {
let mut sequence = serde::de::value::SeqDeserializer::new(values.into_iter());
let result = visitor.visit_seq(&mut sequence)?;
sequence.end()?;
Ok(result)
}
Self::Map(entries) => {
let mut map = serde::de::value::MapDeserializer::new(entries.into_iter());
let result = visitor.visit_map(&mut map)?;
map.end()?;
Ok(result)
}
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Self::Unit => visitor.visit_none(),
value => visitor.visit_some(value),
}
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Self::String(value) => visitor.visit_enum(serde::de::value::StringDeserializer::<
WireError,
>::new(value)),
_ => Err(WireError(
"the test wire supports only unit enum variants".to_owned(),
)),
}
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Self::String(value) => visitor.visit_string(value),
value => value.deserialize_any(visitor),
}
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf unit unit_struct seq tuple tuple_struct map struct
}
}
fn round_trip<T>(value: &T) -> T
where
T: Serialize + DeserializeOwned,
{
let wire = value.serialize(WireSerializer).unwrap();
T::deserialize(wire).unwrap()
}
fn deserialize_wire<T>(value: WireValue) -> Result<T, WireError>
where
T: DeserializeOwned,
{
T::deserialize(value)
}
fn sample_features() -> FeatureVector {
let mut values = [0; FEATURE_COUNT];
for (index, value) in values.iter_mut().enumerate() {
*value = u8::try_from(index * 4).unwrap();
}
FeatureVector::new(values).unwrap()
}
fn sample_segment() -> SegmentRef {
SegmentRef {
source_object: ObjectId::parse("Source_1").unwrap(),
clip_object: ObjectId::parse("Clip-001").unwrap(),
ordinal: 1,
segment_count: 3,
start_ms: 2_000,
end_ms: 4_750,
policy: Key::parse("speaker/profile-v2").unwrap(),
}
}
fn sample_label() -> LabeledSample {
LabeledSample {
sample_id: Key::parse("sample:1").unwrap(),
attempt_id: Key::parse("attempt:1").unwrap(),
speaker_id: Key::parse("speaker:1").unwrap(),
cohort_id: Key::parse("cohort:alpha").unwrap(),
group_id: Key::parse("group:control").unwrap(),
clip_object: ObjectId::parse("Clip-001").unwrap(),
primary_language: Key::parse("en-US").unwrap(),
recording_kind: RecordingKind::Meeting,
usable_speech_ms: 42_500,
recording_quality: 88,
features: sample_features(),
}
}
#[test]
fn keys_enforce_the_documented_alphabet_and_bounds() {
assert_eq!(
Key::parse("speaker_1/en:primary").unwrap().as_ref(),
"speaker_1/en:primary"
);
assert!(Key::parse(&"a".repeat(128)).is_ok());
assert!(Key::parse("").is_err());
assert!(Key::parse(&"a".repeat(129)).is_err());
assert!(Key::parse("not allowed").is_err());
assert!(Key::parse("café").is_err());
}
#[test]
fn keys_and_object_ids_have_deterministic_ordering() {
assert!(Key::parse("a").unwrap() < Key::parse("b").unwrap());
assert!(ObjectId::parse("AAAAAAA-").unwrap() < ObjectId::parse("AAAAAAA_").unwrap());
}
#[test]
fn object_ids_are_exactly_eight_base64url_characters() {
assert_eq!(ObjectId::parse("Ab0-_xyz").unwrap().as_ref(), "Ab0-_xyz");
assert!(ObjectId::parse("short").is_err());
assert!(ObjectId::parse("123456789").is_err());
assert!(ObjectId::parse("pending:").is_err());
assert!(ObjectId::parse("1234567=").is_err());
}
#[test]
fn every_feature_uses_the_uniform_zero_to_one_hundred_boundary() {
assert_eq!(FEATURE_COUNT, 24);
assert!(FeatureVector::new([0; FEATURE_COUNT]).is_ok());
assert!(FeatureVector::new([100; FEATURE_COUNT]).is_ok());
for index in 0..FEATURE_COUNT {
let mut values = [0; FEATURE_COUNT];
values[index] = 101;
assert!(
FeatureVector::new(values).is_err(),
"feature index {index} accepted a value above 100"
);
}
let mut former_age_exception = [0; FEATURE_COUNT];
former_age_exception[10] = 101;
assert!(FeatureVector::new(former_age_exception).is_err());
}
#[test]
fn feature_masks_are_const_nonempty_and_limited_to_the_frozen_24_bits() {
assert_eq!(u64::from(FIRST_FEATURE), 1);
assert!(FeatureMask::from_bits(0).is_err());
let all_features = (1_u64 << FEATURE_COUNT) - 1;
assert_eq!(
u64::from(FeatureMask::from_bits(all_features).unwrap()),
all_features
);
assert!(FeatureMask::from_bits(1_u64 << FEATURE_COUNT).is_err());
assert!(FeatureMask::from_bits(1_u64 << 34).is_err());
}
#[test]
fn segments_require_valid_ordinals_and_nonempty_time_ranges() {
let mut segment = sample_segment();
assert!(segment.validate().is_ok());
segment.ordinal = segment.segment_count;
assert!(segment.validate().is_err());
segment.ordinal = 0;
segment.segment_count = 0;
assert!(segment.validate().is_err());
segment.segment_count = 1;
segment.start_ms = segment.end_ms;
assert!(segment.validate().is_err());
segment.start_ms = u64::MAX - 1;
segment.end_ms = u64::MAX;
assert!(segment.validate().is_ok());
}
#[test]
fn serde_round_trips_validated_values_and_public_records() {
let key = Key::parse("speaker:round-trip").unwrap();
assert_eq!(round_trip(&key), key);
let object_id = ObjectId::parse("Ab0-_xyz").unwrap();
assert_eq!(round_trip(&object_id), object_id);
let features = sample_features();
assert_eq!(round_trip(&features), features);
let mask = FeatureMask::from_bits((1_u64 << FEATURE_COUNT) - 1).unwrap();
assert_eq!(round_trip(&mask), mask);
assert_eq!(
round_trip(&RecordingKind::VoiceNote),
RecordingKind::VoiceNote
);
let segment = sample_segment();
assert_eq!(round_trip(&segment), segment);
let label = sample_label();
assert_eq!(round_trip(&label), label);
}
#[test]
fn invalid_deserialization_cannot_bypass_private_validation() {
assert!(deserialize_wire::<Key>(WireValue::String(String::new())).is_err());
assert!(deserialize_wire::<Key>(WireValue::String("invalid key".to_owned())).is_err());
assert!(deserialize_wire::<ObjectId>(WireValue::String("pending:".to_owned())).is_err());
let mut invalid_features = vec![WireValue::U64(0); FEATURE_COUNT];
invalid_features[10] = WireValue::U64(101);
assert!(deserialize_wire::<FeatureVector>(WireValue::Seq(invalid_features)).is_err());
assert!(
deserialize_wire::<FeatureVector>(WireValue::Seq(vec![
WireValue::U64(0);
FEATURE_COUNT - 1
]))
.is_err()
);
assert!(deserialize_wire::<FeatureMask>(WireValue::U64(0)).is_err());
assert!(deserialize_wire::<FeatureMask>(WireValue::U64(1_u64 << FEATURE_COUNT)).is_err());
}
}