1#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
24#[repr(transparent)]
25pub struct BufferFlags(pub i32);
26
27impl BufferFlags {
28 pub const INVALID: Self = Self(0);
30 pub const VALID: Self = Self(1);
32 pub const SILENT: Self = Self(2);
35
36 #[inline]
38 #[must_use]
39 pub const fn is_valid(self) -> bool {
40 self.0 == Self::VALID.0
41 }
42
43 #[inline]
45 #[must_use]
46 pub const fn is_silent(self) -> bool {
47 self.0 == Self::SILENT.0
48 }
49
50 #[inline]
52 #[must_use]
53 pub const fn is_invalid(self) -> bool {
54 self.0 == Self::INVALID.0
55 }
56}
57
58impl Default for BufferFlags {
59 #[inline]
62 fn default() -> Self {
63 Self::INVALID
64 }
65}
66
67#[derive(Copy, Clone, PartialEq, Eq, Debug)]
85pub struct ConnectionProperty {
86 pub buffer: usize,
88 pub valid_frame_count: u32,
91 pub flags: BufferFlags,
93 pub signature: u32,
97}
98
99impl ConnectionProperty {
100 #[inline]
103 #[must_use]
104 pub const fn empty() -> Self {
105 Self {
106 buffer: 0,
107 valid_frame_count: 0,
108 flags: BufferFlags::INVALID,
109 signature: CONNECTION_PROPERTY_SIGNATURE,
110 }
111 }
112}
113
114pub const CONNECTION_PROPERTY_SIGNATURE: u32 = u32::from_be_bytes([b'A', b'P', b'O', b'C']);
122
123#[cfg(windows)]
124impl From<windows::Win32::Media::Audio::Apo::APO_BUFFER_FLAGS> for BufferFlags {
125 #[inline]
126 fn from(value: windows::Win32::Media::Audio::Apo::APO_BUFFER_FLAGS) -> Self {
127 Self(value.0)
128 }
129}
130
131#[cfg(windows)]
132impl From<BufferFlags> for windows::Win32::Media::Audio::Apo::APO_BUFFER_FLAGS {
133 #[inline]
134 fn from(value: BufferFlags) -> Self {
135 Self(value.0)
136 }
137}
138
139#[cfg(windows)]
140impl From<windows::Win32::Media::Audio::Apo::APO_CONNECTION_PROPERTY> for ConnectionProperty {
141 #[inline]
142 fn from(value: windows::Win32::Media::Audio::Apo::APO_CONNECTION_PROPERTY) -> Self {
143 Self {
144 buffer: value.pBuffer,
145 valid_frame_count: value.u32ValidFrameCount,
146 flags: value.u32BufferFlags.into(),
147 signature: value.u32Signature,
148 }
149 }
150}
151
152#[cfg(windows)]
153impl From<ConnectionProperty> for windows::Win32::Media::Audio::Apo::APO_CONNECTION_PROPERTY {
154 #[inline]
155 fn from(value: ConnectionProperty) -> Self {
156 Self {
157 pBuffer: value.buffer,
158 u32ValidFrameCount: value.valid_frame_count,
159 u32BufferFlags: value.flags.into(),
160 u32Signature: value.signature,
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn buffer_flag_constants_match_microsoft_values() {
171 assert_eq!(BufferFlags::INVALID.0, 0);
172 assert_eq!(BufferFlags::VALID.0, 1);
173 assert_eq!(BufferFlags::SILENT.0, 2);
174 }
175
176 #[test]
177 fn buffer_flag_predicates_classify_correctly() {
178 assert!(BufferFlags::VALID.is_valid());
179 assert!(!BufferFlags::VALID.is_silent());
180 assert!(!BufferFlags::VALID.is_invalid());
181
182 assert!(BufferFlags::SILENT.is_silent());
183 assert!(!BufferFlags::SILENT.is_valid());
184
185 assert!(BufferFlags::INVALID.is_invalid());
186 assert!(!BufferFlags::INVALID.is_valid());
187 }
188
189 #[test]
190 fn buffer_flags_default_is_invalid() {
191 assert_eq!(BufferFlags::default(), BufferFlags::INVALID);
192 }
193
194 #[test]
195 fn buffer_flags_unknown_value_round_trips() {
196 let f = BufferFlags(99);
200 assert!(!f.is_valid());
201 assert!(!f.is_silent());
202 assert!(!f.is_invalid());
203 assert_eq!(f.0, 99);
204 }
205
206 #[test]
207 fn connection_property_empty_has_signature() {
208 let cp = ConnectionProperty::empty();
209 assert_eq!(cp.signature, CONNECTION_PROPERTY_SIGNATURE);
210 assert_eq!(cp.buffer, 0);
211 assert_eq!(cp.valid_frame_count, 0);
212 assert!(cp.flags.is_invalid());
213 }
214
215 #[test]
216 fn signature_value_spells_apoc_in_be_bytes() {
217 assert_eq!(CONNECTION_PROPERTY_SIGNATURE, 0x4150_4F43);
218 let bytes = CONNECTION_PROPERTY_SIGNATURE.to_be_bytes();
219 assert_eq!(&bytes, b"APOC");
220 }
221
222 #[cfg(windows)]
223 #[test]
224 fn buffer_flags_round_trip_through_windows_type() {
225 use windows::Win32::Media::Audio::Apo::APO_BUFFER_FLAGS;
226 for f in [
227 BufferFlags::INVALID,
228 BufferFlags::VALID,
229 BufferFlags::SILENT,
230 BufferFlags(42),
231 ] {
232 let w: APO_BUFFER_FLAGS = f.into();
233 let back: BufferFlags = w.into();
234 assert_eq!(f, back);
235 }
236 }
237
238 #[cfg(windows)]
239 #[test]
240 fn buffer_flags_constants_match_windows_constants() {
241 use windows::Win32::Media::Audio::Apo::{BUFFER_INVALID, BUFFER_SILENT, BUFFER_VALID};
242 assert_eq!(BufferFlags::INVALID, BUFFER_INVALID.into());
243 assert_eq!(BufferFlags::VALID, BUFFER_VALID.into());
244 assert_eq!(BufferFlags::SILENT, BUFFER_SILENT.into());
245 }
246
247 #[cfg(windows)]
248 #[test]
249 fn connection_property_round_trips_through_windows_type() {
250 use windows::Win32::Media::Audio::Apo::APO_CONNECTION_PROPERTY;
251 let cp = ConnectionProperty {
252 buffer: 0xDEAD_BEEF,
253 valid_frame_count: 1024,
254 flags: BufferFlags::VALID,
255 signature: CONNECTION_PROPERTY_SIGNATURE,
256 };
257 let w: APO_CONNECTION_PROPERTY = cp.into();
258 assert_eq!(w.pBuffer, 0xDEAD_BEEF);
259 assert_eq!(w.u32ValidFrameCount, 1024);
260 assert_eq!(w.u32BufferFlags.0, 1);
261 assert_eq!(w.u32Signature, CONNECTION_PROPERTY_SIGNATURE);
262
263 let back: ConnectionProperty = w.into();
264 assert_eq!(cp, back);
265 }
266}