use bytes::{Buf, BufMut};
use crate::kvp::{KeyValuePair, KvpValue};
use crate::varint::{MoqtProfile, VarInt};
pub const SUBGROUP_FILTER_PARAMETER: u64 = 0x25;
pub const OBJECT_ID_FILTER_PARAMETER: u64 = 0x26;
pub const PRIORITY_FILTER_PARAMETER: u64 = 0x27;
pub const OBJECT_PROPERTY_FILTER_PARAMETER: u64 = 0x28;
pub const TRACK_PROPERTY_FILTER_PARAMETER: u64 = 0x29;
pub fn is_range_filter(parameter_type: u64) -> bool {
(SUBGROUP_FILTER_PARAMETER..=TRACK_PROPERTY_FILTER_PARAMETER).contains(¶meter_type)
}
pub fn carries_a_property_type(parameter_type: u64) -> bool {
parameter_type == OBJECT_PROPERTY_FILTER_PARAMETER
|| parameter_type == TRACK_PROPERTY_FILTER_PARAMETER
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FilterRange {
pub start: u64,
pub end: Option<u64>,
}
impl FilterRange {
pub fn contains(&self, value: u64) -> bool {
value >= self.start && self.end.is_none_or(|end| value <= end)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RangeFilter {
pub parameter_type: u64,
pub set_id: u8,
pub property_type: Option<u64>,
pub ranges: Vec<FilterRange>,
}
pub type RangeFilterKey = (u64, u8, Option<u64>);
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum RangeFilterError {
#[error("parameter type {0} is not a Range Filter")]
NotARangeFilter(u64),
#[error("range filter value is malformed: {detail}")]
Malformed {
detail: &'static str,
},
#[error("range filter delta {delta} past {base} runs off the end of the 64-bit space")]
DeltaOverflow {
base: u64,
delta: u64,
},
#[error("priority filter names {0}, which a Publisher Priority cannot hold")]
PriorityAboveTheField(u64),
#[error("property filter names property type {0}, which is not an integer-valued one")]
PropertyTypeIsNotAnInteger(u64),
}
const NO_SET_ID: &str = "it ends before the SetID";
const NO_PROPERTY_TYPE: &str = "it ends before the Property Type this filter type carries";
impl RangeFilter {
pub fn decode_moqt<P: MoqtProfile>(
parameter_type: u64,
bytes: &[u8],
) -> Result<Self, RangeFilterError> {
if !is_range_filter(parameter_type) {
return Err(RangeFilterError::NotARangeFilter(parameter_type));
}
if bytes.is_empty() {
return Ok(RangeFilter {
parameter_type,
set_id: 0,
property_type: None,
ranges: Vec::new(),
});
}
let mut buf = bytes;
if buf.remaining() < 1 {
return Err(RangeFilterError::Malformed { detail: NO_SET_ID });
}
let set_id = buf.get_u8();
let property_type = if carries_a_property_type(parameter_type) {
Some(
VarInt::decode_moqt::<P>(&mut buf)
.map_err(|_| RangeFilterError::Malformed { detail: NO_PROPERTY_TYPE })?
.into_inner(),
)
} else {
None
};
let mut ranges = Vec::new();
let mut previous_end: u64 = 0;
while buf.has_remaining() {
let delta = VarInt::decode_moqt::<P>(&mut buf)
.map_err(|_| RangeFilterError::Malformed { detail: "a Range's Start is short" })?
.into_inner();
let start = previous_end
.checked_add(delta)
.ok_or(RangeFilterError::DeltaOverflow { base: previous_end, delta })?;
if !buf.has_remaining() {
ranges.push(FilterRange { start, end: None });
break;
}
let delta = VarInt::decode_moqt::<P>(&mut buf)
.map_err(|_| RangeFilterError::Malformed { detail: "a Range's End is short" })?
.into_inner();
let end = start
.checked_add(delta)
.ok_or(RangeFilterError::DeltaOverflow { base: start, delta })?;
ranges.push(FilterRange { start, end: Some(end) });
previous_end = end;
}
let filter = RangeFilter { parameter_type, set_id, property_type, ranges };
filter.check_its_own_types()?;
Ok(filter)
}
fn check_its_own_types(&self) -> Result<(), RangeFilterError> {
if let Some(property_type) = self.property_type {
if !property_type.is_multiple_of(2) {
return Err(RangeFilterError::PropertyTypeIsNotAnInteger(property_type));
}
}
if self.parameter_type == PRIORITY_FILTER_PARAMETER {
for range in &self.ranges {
for value in [Some(range.start), range.end].into_iter().flatten() {
if value > 255 {
return Err(RangeFilterError::PriorityAboveTheField(value));
}
}
}
}
Ok(())
}
pub fn encode_moqt<P: MoqtProfile>(
&self,
buf: &mut impl BufMut,
) -> Result<(), RangeFilterError> {
if !is_range_filter(self.parameter_type) {
return Err(RangeFilterError::NotARangeFilter(self.parameter_type));
}
match (carries_a_property_type(self.parameter_type), self.property_type) {
(true, None) => {
return Err(RangeFilterError::Malformed {
detail: "this filter type carries a Property Type and none was given",
})
}
(false, Some(_)) => {
return Err(RangeFilterError::Malformed {
detail: "this filter type carries no Property Type and one was given",
})
}
_ => {}
}
self.check_its_own_types()?;
let mut out = Vec::new();
out.push(self.set_id);
if let Some(property_type) = self.property_type {
VarInt::from_u64_moqt(property_type).encode_moqt::<P>(&mut out);
}
let mut previous_end: u64 = 0;
for (index, range) in self.ranges.iter().enumerate() {
let start_delta =
range.start.checked_sub(previous_end).ok_or(RangeFilterError::Malformed {
detail: "the Ranges are not in ascending order",
})?;
VarInt::from_u64_moqt(start_delta).encode_moqt::<P>(&mut out);
match range.end {
Some(end) => {
let end_delta =
end.checked_sub(range.start).ok_or(RangeFilterError::Malformed {
detail: "a Range ends before it starts",
})?;
VarInt::from_u64_moqt(end_delta).encode_moqt::<P>(&mut out);
previous_end = end;
}
None if index + 1 == self.ranges.len() => {}
None => {
return Err(RangeFilterError::Malformed {
detail: "only the final Range may be left open",
})
}
}
}
buf.put_slice(&out);
Ok(())
}
pub fn passes(&self, value: u64) -> bool {
self.ranges.iter().any(|range| range.contains(value))
}
pub fn key(&self) -> RangeFilterKey {
(self.parameter_type, self.set_id, self.property_type)
}
}
pub fn decode_all_moqt<P: MoqtProfile>(
parameters: &[KeyValuePair],
) -> Result<Vec<RangeFilter>, RangeFilterError> {
let mut filters = Vec::new();
for parameter in parameters {
let parameter_type = parameter.key.into_inner();
if !is_range_filter(parameter_type) {
continue;
}
let bytes = match ¶meter.value {
KvpValue::Bytes(bytes) => bytes.as_slice(),
KvpValue::Varint(_) => {
return Err(RangeFilterError::Malformed {
detail: "its value is a bare varint where the type defines a filter",
})
}
};
filters.push(RangeFilter::decode_moqt::<P>(parameter_type, bytes)?);
}
Ok(filters)
}
pub fn total_ranges(filters: &[RangeFilter]) -> usize {
filters.iter().map(|filter| filter.ranges.len()).sum()
}
pub fn first_repeated_key(filters: &[RangeFilter]) -> Option<RangeFilterKey> {
let mut seen: Vec<RangeFilterKey> = Vec::with_capacity(filters.len());
for filter in filters {
let key = filter.key();
if seen.contains(&key) {
return Some(key);
}
seen.push(key);
}
None
}