1use soapysdr_sys::*;
2use std::collections::HashMap;
3use std::ffi::{CStr, CString};
4use std::fmt;
5use std::iter::{FromIterator, IntoIterator};
6use std::os::raw::c_char;
7use std::ptr;
8use std::slice;
9
10pub struct Args(SoapySDRKwargs);
12
13impl Drop for Args {
14 fn drop(&mut self) {
15 unsafe { SoapySDRKwargs_clear(self.as_raw()) }
16 }
17}
18
19impl Default for Args {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl Args {
26 pub fn new() -> Args {
28 Args(SoapySDRKwargs {
29 size: 0,
30 keys: ptr::null_mut(),
31 vals: ptr::null_mut(),
32 })
33 }
34
35 pub unsafe fn from_raw(a: SoapySDRKwargs) -> Args {
42 Args(a)
43 }
44
45 pub fn as_raw(&mut self) -> *mut SoapySDRKwargs {
46 &mut self.0 as *mut _
47 }
48
49 pub fn as_raw_const(&self) -> *const SoapySDRKwargs {
50 &self.0 as *const _
51 }
52
53 fn keys(&self) -> &[*mut c_char] {
54 unsafe { slice::from_raw_parts(self.0.keys, self.0.size) }
55 }
56
57 fn key(&self, idx: usize) -> &CStr {
58 unsafe { CStr::from_ptr(self.keys()[idx]) }
59 }
60
61 fn values(&self) -> &[*mut c_char] {
62 unsafe { slice::from_raw_parts(self.0.vals, self.0.size) }
63 }
64
65 fn value(&self, idx: usize) -> &CStr {
66 unsafe { CStr::from_ptr(self.values()[idx]) }
67 }
68
69 pub fn set<K: Into<Vec<u8>>, V: Into<Vec<u8>>>(&mut self, key: K, value: V) {
81 unsafe {
82 let k = CString::new(key).expect("SoapySDR key can't contain null bytes");
83 let v = CString::new(value).expect("SoapySDR value can't contain null bytes");
84 SoapySDRKwargs_set(self.as_raw(), k.as_ptr(), v.as_ptr());
85 }
86 }
87
88 pub fn get<'a>(&'a self, key: &str) -> Option<&'a str> {
97 for i in 0..(self.0.size) {
98 if self.key(i).to_bytes() == key.as_bytes() {
99 return self.value(i).to_str().ok();
100 }
101 }
102 None
103 }
104
105 pub fn iter(&self) -> ArgsIterator<'_> {
117 ArgsIterator { args: self, pos: 0 }
118 }
119}
120
121impl<K: Into<Vec<u8>>, V: Into<Vec<u8>>> FromIterator<(K, V)> for Args {
122 fn from_iter<T>(i: T) -> Self
123 where
124 T: IntoIterator<Item = (K, V)>,
125 {
126 let mut args = Args::new();
127 for (k, v) in i {
128 args.set(k, v);
129 }
130 args
131 }
132}
133
134impl<'a> IntoIterator for &'a Args {
135 type Item = (&'a str, &'a str);
136 type IntoIter = ArgsIterator<'a>;
137
138 fn into_iter(self) -> Self::IntoIter {
139 self.iter()
140 }
141}
142
143impl<'a> From<&'a str> for Args {
144 fn from(s: &'a str) -> Args {
145 let mut args = Args::new();
146 for i in s.split(',') {
147 if let Some(pos) = i.find('=') {
148 args.set(i[..pos].trim(), i[pos + 1..].trim());
149 }
150 }
151 args
152 }
153}
154
155impl<'a, K: ::std::cmp::Eq + ::std::hash::Hash, V> From<&'a HashMap<K, V>> for Args
156where
157 &'a K: Into<Vec<u8>>,
158 &'a V: Into<Vec<u8>>,
159{
160 fn from(m: &'a HashMap<K, V>) -> Args {
161 let mut args = Args::new();
162 for (k, v) in m {
163 args.set(k, v);
164 }
165 args
166 }
167}
168
169impl<'a, K, V> From<&'a [(K, V)]> for Args
170where
171 &'a K: Into<Vec<u8>>,
172 &'a V: Into<Vec<u8>>,
173{
174 fn from(m: &'a [(K, V)]) -> Args {
175 let mut args = Args::new();
176 for (k, v) in m {
177 args.set(k, v);
178 }
179 args
180 }
181}
182
183impl From<()> for Args {
184 fn from(_: ()) -> Args {
185 Args::new()
186 }
187}
188
189impl<'a> From<&'a Args> for String {
190 fn from(a: &'a Args) -> String {
191 format!("{}", a)
192 }
193}
194
195impl<'a> From<&'a Args> for HashMap<String, String> {
196 fn from(a: &'a Args) -> HashMap<String, String> {
197 a.into_iter()
198 .map(|(k, v)| (k.to_owned(), v.to_owned()))
199 .collect()
200 }
201}
202
203impl fmt::Display for Args {
204 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
205 let mut i = self.iter();
206 if let Some((k, v)) = i.next() {
207 write!(fmt, "{}={}", k, v)?;
208 for (k, v) in i {
209 write!(fmt, ", {}={}", k, v)?;
210 }
211 }
212 Ok(())
213 }
214}
215
216pub struct ArgsIterator<'a> {
218 args: &'a Args,
219 pos: usize,
220}
221
222impl<'a> Iterator for ArgsIterator<'a> {
223 type Item = (&'a str, &'a str);
224 fn next(&mut self) -> Option<Self::Item> {
225 if self.pos < self.args.0.size {
226 let k = self.args.key(self.pos).to_str().unwrap_or("(invalid utf8)");
227 let v = self
228 .args
229 .value(self.pos)
230 .to_str()
231 .unwrap_or("(invalid utf8)");
232 self.pos += 1;
233 Some((k, v))
234 } else {
235 None
236 }
237 }
238}