1use std::{convert::TryInto, fmt};
7
8use nix::errno::Errno;
9
10#[derive(Debug, Eq, PartialEq)]
13pub struct SpaResult(i32);
14
15#[derive(PartialEq, Eq, Copy, Clone)]
19pub struct AsyncSeq(i32);
20
21#[derive(Debug, Eq, PartialEq)]
23pub enum SpaSuccess {
24 Sync(i32),
26 Async(AsyncSeq),
28}
29
30fn async_seq(res: i32) -> i32 {
31 let mask: i32 = spa_sys::SPA_ASYNC_SEQ_MASK.try_into().unwrap();
32 res & mask
33}
34
35fn is_async(val: i32) -> bool {
36 let bit: i32 = spa_sys::SPA_ASYNC_BIT.try_into().unwrap();
37 (val & spa_sys::SPA_ASYNC_MASK) == bit
38}
39
40impl AsyncSeq {
41 pub fn seq(&self) -> i32 {
43 async_seq(self.0)
44 }
45
46 pub fn raw(&self) -> i32 {
48 self.0
49 }
50
51 pub fn from_seq(seq: i32) -> Self {
53 let bit: i32 = spa_sys::SPA_ASYNC_BIT.try_into().unwrap();
54 let res = bit | async_seq(seq);
55
56 Self(res)
57 }
58
59 pub fn from_raw(val: i32) -> Self {
61 debug_assert!(is_async(val));
62 Self(val)
63 }
64}
65
66impl fmt::Debug for AsyncSeq {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "AsyncSeq seq: {} raw: {}", &self.seq(), &self.raw())
69 }
70}
71
72impl SpaResult {
73 pub fn from_c(res: i32) -> Self {
75 Self(res)
76 }
77
78 pub fn new_return_async(seq: i32) -> Self {
80 let seq = AsyncSeq::from_seq(seq);
81 Self::from_c(seq.raw())
82 }
83
84 fn is_async(&self) -> bool {
85 is_async(self.0)
86 }
87
88 pub fn into_result(self) -> Result<SpaSuccess, Error> {
90 if self.0 < 0 {
91 Err(Error::new(-self.0))
92 } else if self.is_async() {
93 Ok(SpaSuccess::Async(AsyncSeq::from_raw(self.0)))
94 } else {
95 Ok(SpaSuccess::Sync(self.0))
96 }
97 }
98
99 pub fn into_async_result(self) -> Result<AsyncSeq, Error> {
105 let res = self.into_result()?;
106
107 match res {
108 SpaSuccess::Async(res) => Ok(res),
109 SpaSuccess::Sync(_) => panic!("result is synchronous success"),
110 }
111 }
112
113 pub fn into_sync_result(self) -> Result<i32, Error> {
119 let res = self.into_result()?;
120
121 match res {
122 SpaSuccess::Sync(res) => Ok(res),
123 SpaSuccess::Async(_) => panic!("result is an asynchronous success"),
124 }
125 }
126}
127
128#[derive(Debug, Eq, PartialEq)]
130pub struct Error(Errno);
131
132impl Error {
133 fn new(e: i32) -> Self {
134 assert!(e > 0);
135
136 Self(Errno::from_raw(e))
137 }
138}
139
140impl std::error::Error for Error {}
141
142impl fmt::Display for Error {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 write!(f, "{}", self.0)
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 #[cfg_attr(miri, ignore)]
154 fn spa_result() {
156 assert!(!SpaResult::from_c(0).is_async());
157 assert!(SpaResult::new_return_async(0).is_async());
158 assert_eq!(
159 SpaResult::new_return_async(0).into_async_result(),
160 Ok(AsyncSeq::from_seq(0))
161 );
162
163 assert_eq!(SpaResult::from_c(0).into_result(), Ok(SpaSuccess::Sync(0)));
164 assert_eq!(SpaResult::from_c(1).into_result(), Ok(SpaSuccess::Sync(1)));
165 assert_eq!(SpaResult::from_c(0).into_sync_result(), Ok(0));
166
167 assert_eq!(
168 SpaResult::new_return_async(1).into_result(),
169 Ok(SpaSuccess::Async(AsyncSeq::from_seq(1)))
170 );
171
172 let err = SpaResult::from_c(-libc::EBUSY).into_result().unwrap_err();
173 assert_eq!(format!("{}", err), "EBUSY: Device or resource busy",);
174
175 let res = SpaResult::from_c(-1).into_sync_result();
176 assert!(res.is_err());
177 }
178
179 #[test]
180 fn async_seq() {
181 assert_eq!(AsyncSeq::from_seq(0).seq(), 0);
182 assert_eq!(AsyncSeq::from_seq(1).seq(), 1);
183 }
184
185 #[should_panic]
186 #[test]
187 fn async_seq_panic() {
188 AsyncSeq::from_raw(1);
190 }
191
192 #[should_panic]
193 #[test]
194 fn spa_async_result_panic() {
195 let _ = SpaResult::from_c(0).into_async_result();
196 }
197
198 #[should_panic]
199 #[test]
200 fn spa_sync_result_panic() {
201 let _ = SpaResult::new_return_async(10).into_sync_result();
202 }
203}