use crate::descriptors::{SegmentationDescriptor, SegmentationTypeId, SegmentationUpidType};
pub const MAX_SECTION_LEN_TS: usize = 4096;
pub const PROFILE_UPID_TYPE: SegmentationUpidType = SegmentationUpidType::Uri;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum PlacementOpportunity {
ProviderStart,
ProviderEnd,
DistributorStart,
DistributorEnd,
}
impl PlacementOpportunity {
#[must_use]
pub fn from_segmentation_type_id(id: SegmentationTypeId) -> Option<Self> {
match id {
SegmentationTypeId::ProviderPlacementOpportunityStart => Some(Self::ProviderStart),
SegmentationTypeId::ProviderPlacementOpportunityEnd => Some(Self::ProviderEnd),
SegmentationTypeId::DistributorPlacementOpportunityStart => {
Some(Self::DistributorStart)
}
SegmentationTypeId::DistributorPlacementOpportunityEnd => Some(Self::DistributorEnd),
_ => None,
}
}
#[must_use]
pub fn segmentation_type_id(self) -> SegmentationTypeId {
match self {
Self::ProviderStart => SegmentationTypeId::ProviderPlacementOpportunityStart,
Self::ProviderEnd => SegmentationTypeId::ProviderPlacementOpportunityEnd,
Self::DistributorStart => SegmentationTypeId::DistributorPlacementOpportunityStart,
Self::DistributorEnd => SegmentationTypeId::DistributorPlacementOpportunityEnd,
}
}
#[must_use]
pub fn is_start(self) -> bool {
matches!(self, Self::ProviderStart | Self::DistributorStart)
}
#[must_use]
pub fn is_provider(self) -> bool {
matches!(self, Self::ProviderStart | Self::ProviderEnd)
}
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::ProviderStart => "Provider Placement Opportunity Start",
Self::ProviderEnd => "Provider Placement Opportunity End",
Self::DistributorStart => "Distributor Placement Opportunity Start",
Self::DistributorEnd => "Distributor Placement Opportunity End",
}
}
}
broadcast_common::impl_spec_display!(PlacementOpportunity);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum ProfileViolation {
Ok,
EventCancelled,
DurationMissing,
UpidTypeNotUri,
}
impl ProfileViolation {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::Ok => "ok",
Self::EventCancelled => "segmentation_event_cancel_indicator set (§5.3.5.3)",
Self::DurationMissing => "segmentation_duration_flag clear on a Start (§5.3.5.5)",
Self::UpidTypeNotUri => "segmentation_upid_type is not 0x0F URI (§5.3.5.10)",
}
}
}
broadcast_common::impl_spec_display!(ProfileViolation);
#[must_use]
pub fn validate_po_segmentation(d: &SegmentationDescriptor<'_>) -> ProfileViolation {
if d.segmentation_event_cancel_indicator {
return ProfileViolation::EventCancelled;
}
let po = PlacementOpportunity::from_segmentation_type_id(d.segmentation_type_id);
if let Some(po) = po {
if d.segmentation_upid_type != PROFILE_UPID_TYPE {
return ProfileViolation::UpidTypeNotUri;
}
if po.is_start() && d.segmentation_duration.is_none() {
return ProfileViolation::DurationMissing;
}
}
ProfileViolation::Ok
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classifies_the_four_po_type_ids() {
assert_eq!(
PlacementOpportunity::from_segmentation_type_id(
SegmentationTypeId::ProviderPlacementOpportunityStart
),
Some(PlacementOpportunity::ProviderStart)
);
assert_eq!(
PlacementOpportunity::from_segmentation_type_id(
SegmentationTypeId::DistributorPlacementOpportunityEnd
),
Some(PlacementOpportunity::DistributorEnd)
);
assert_eq!(
PlacementOpportunity::from_segmentation_type_id(SegmentationTypeId::ProgramStart),
None
);
}
#[test]
fn po_round_trips_type_id_and_flags() {
for po in [
PlacementOpportunity::ProviderStart,
PlacementOpportunity::ProviderEnd,
PlacementOpportunity::DistributorStart,
PlacementOpportunity::DistributorEnd,
] {
let id = po.segmentation_type_id();
assert_eq!(
PlacementOpportunity::from_segmentation_type_id(id),
Some(po)
);
}
assert!(PlacementOpportunity::ProviderStart.is_start());
assert!(!PlacementOpportunity::ProviderEnd.is_start());
assert!(PlacementOpportunity::ProviderStart.is_provider());
assert!(!PlacementOpportunity::DistributorStart.is_provider());
assert_eq!(
PlacementOpportunity::ProviderStart
.segmentation_type_id()
.to_u8(),
0x34
);
assert_eq!(
PlacementOpportunity::DistributorEnd
.segmentation_type_id()
.to_u8(),
0x37
);
}
}