use std::collections::HashMap;
use alpine::messages::{CapabilitySet, ChannelFormat};
use alpine::profile::StreamProfile;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapabilityMatchMode {
Strict,
Lenient,
}
#[derive(Debug, Clone)]
pub struct CapabilityValidation {
pub warnings: Vec<String>,
}
#[derive(Debug, Clone, Default)]
pub struct CapabilityDeprecationRegistry {
vendor_extensions: HashMap<String, String>,
}
impl CapabilityDeprecationRegistry {
pub fn new() -> Self {
Self {
vendor_extensions: HashMap::new(),
}
}
pub fn register_vendor_extension(
&mut self,
name: impl Into<String>,
message: impl Into<String>,
) {
self.vendor_extensions.insert(name.into(), message.into());
}
pub fn warnings_for(&self, caps: &CapabilitiesSummary) -> Vec<String> {
let mut warnings = Vec::new();
if let Some(extensions) = caps.vendor_extensions.as_ref() {
for (name, msg) in self.vendor_extensions.iter() {
if extensions.contains_key(name) {
warnings.push(format!("capability '{}' deprecated: {}", name, msg));
}
}
}
warnings
}
}
#[derive(Debug, Clone)]
pub struct CapabilitiesSummary {
pub channel_formats: Vec<ChannelFormat>,
pub max_channels: u32,
pub grouping_supported: bool,
pub streaming_supported: bool,
pub encryption_supported: bool,
pub vendor_extensions: Option<HashMap<String, serde_json::Value>>,
}
impl From<&CapabilitySet> for CapabilitiesSummary {
fn from(caps: &CapabilitySet) -> Self {
Self {
channel_formats: caps.channel_formats.clone(),
max_channels: caps.max_channels,
grouping_supported: caps.grouping_supported,
streaming_supported: caps.streaming_supported,
encryption_supported: caps.encryption_supported,
vendor_extensions: caps.vendor_extensions.clone(),
}
}
}
impl CapabilitiesSummary {
pub fn supports_format(&self, format: &ChannelFormat) -> bool {
self.channel_formats.contains(format)
}
pub fn validate_stream(
&self,
format: ChannelFormat,
channel_count: usize,
) -> Result<(), String> {
if !self.streaming_supported {
return Err("streaming not supported by device".into());
}
if !self.supports_format(&format) {
return Err(format!("channel format {:?} not supported", format));
}
if channel_count as u32 > self.max_channels {
return Err(format!(
"channel count {} exceeds device max {}",
channel_count, self.max_channels
));
}
Ok(())
}
pub fn validate_stream_with_mode(
&self,
format: ChannelFormat,
channel_count: usize,
mode: CapabilityMatchMode,
) -> Result<CapabilityValidation, String> {
match mode {
CapabilityMatchMode::Strict => {
self.validate_stream(format, channel_count)?;
Ok(CapabilityValidation {
warnings: Vec::new(),
})
}
CapabilityMatchMode::Lenient => {
let mut warnings = Vec::new();
if !self.streaming_supported {
warnings.push("streaming not supported by device".to_string());
}
if !self.supports_format(&format) {
warnings.push(format!("channel format {:?} not supported", format));
}
if channel_count as u32 > self.max_channels {
warnings.push(format!(
"channel count {} exceeds device max {}",
channel_count, self.max_channels
));
}
Ok(CapabilityValidation { warnings })
}
}
}
pub fn deprecation_warnings(&self, registry: &CapabilityDeprecationRegistry) -> Vec<String> {
registry.warnings_for(self)
}
pub fn validate_profile(&self, profile: &StreamProfile) -> Result<(), String> {
if !self.streaming_supported {
return Err("streaming not supported by device".into());
}
profile
.clone()
.compile()
.map(|_| ())
.map_err(|err| err.to_string())
}
}