alpine_protocol_sdk/
capabilities.rs1use std::collections::HashMap;
2
3use alpine::messages::{CapabilitySet, ChannelFormat};
4use alpine::profile::StreamProfile;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum CapabilityMatchMode {
8 Strict,
9 Lenient,
10}
11
12#[derive(Debug, Clone)]
13pub struct CapabilityValidation {
14 pub warnings: Vec<String>,
15}
16
17#[derive(Debug, Clone, Default)]
18pub struct CapabilityDeprecationRegistry {
19 vendor_extensions: HashMap<String, String>,
20}
21
22impl CapabilityDeprecationRegistry {
23 pub fn new() -> Self {
24 Self {
25 vendor_extensions: HashMap::new(),
26 }
27 }
28
29 pub fn register_vendor_extension(
30 &mut self,
31 name: impl Into<String>,
32 message: impl Into<String>,
33 ) {
34 self.vendor_extensions.insert(name.into(), message.into());
35 }
36
37 pub fn warnings_for(&self, caps: &CapabilitiesSummary) -> Vec<String> {
38 let mut warnings = Vec::new();
39 if let Some(extensions) = caps.vendor_extensions.as_ref() {
40 for (name, msg) in self.vendor_extensions.iter() {
41 if extensions.contains_key(name) {
42 warnings.push(format!("capability '{}' deprecated: {}", name, msg));
43 }
44 }
45 }
46 warnings
47 }
48}
49
50#[derive(Debug, Clone)]
51pub struct CapabilitiesSummary {
52 pub channel_formats: Vec<ChannelFormat>,
53 pub max_channels: u32,
54 pub grouping_supported: bool,
55 pub streaming_supported: bool,
56 pub encryption_supported: bool,
57 pub vendor_extensions: Option<HashMap<String, serde_json::Value>>,
58}
59
60impl From<&CapabilitySet> for CapabilitiesSummary {
61 fn from(caps: &CapabilitySet) -> Self {
62 Self {
63 channel_formats: caps.channel_formats.clone(),
64 max_channels: caps.max_channels,
65 grouping_supported: caps.grouping_supported,
66 streaming_supported: caps.streaming_supported,
67 encryption_supported: caps.encryption_supported,
68 vendor_extensions: caps.vendor_extensions.clone(),
69 }
70 }
71}
72
73impl CapabilitiesSummary {
74 pub fn supports_format(&self, format: &ChannelFormat) -> bool {
75 self.channel_formats.contains(format)
76 }
77
78 pub fn validate_stream(
79 &self,
80 format: ChannelFormat,
81 channel_count: usize,
82 ) -> Result<(), String> {
83 if !self.streaming_supported {
84 return Err("streaming not supported by device".into());
85 }
86 if !self.supports_format(&format) {
87 return Err(format!("channel format {:?} not supported", format));
88 }
89 if channel_count as u32 > self.max_channels {
90 return Err(format!(
91 "channel count {} exceeds device max {}",
92 channel_count, self.max_channels
93 ));
94 }
95 Ok(())
96 }
97
98 pub fn validate_stream_with_mode(
99 &self,
100 format: ChannelFormat,
101 channel_count: usize,
102 mode: CapabilityMatchMode,
103 ) -> Result<CapabilityValidation, String> {
104 match mode {
105 CapabilityMatchMode::Strict => {
106 self.validate_stream(format, channel_count)?;
107 Ok(CapabilityValidation {
108 warnings: Vec::new(),
109 })
110 }
111 CapabilityMatchMode::Lenient => {
112 let mut warnings = Vec::new();
113 if !self.streaming_supported {
114 warnings.push("streaming not supported by device".to_string());
115 }
116 if !self.supports_format(&format) {
117 warnings.push(format!("channel format {:?} not supported", format));
118 }
119 if channel_count as u32 > self.max_channels {
120 warnings.push(format!(
121 "channel count {} exceeds device max {}",
122 channel_count, self.max_channels
123 ));
124 }
125 Ok(CapabilityValidation { warnings })
126 }
127 }
128 }
129
130 pub fn deprecation_warnings(&self, registry: &CapabilityDeprecationRegistry) -> Vec<String> {
131 registry.warnings_for(self)
132 }
133
134 pub fn validate_profile(&self, profile: &StreamProfile) -> Result<(), String> {
135 if !self.streaming_supported {
136 return Err("streaming not supported by device".into());
137 }
138 profile
139 .clone()
140 .compile()
141 .map(|_| ())
142 .map_err(|err| err.to_string())
143 }
144}