1#![deny(
44 missing_docs,
45 missing_debug_implementations,
46 missing_copy_implementations,
47 unstable_features,
48 unused_import_braces,
49 unused_qualifications
50)]
51#![warn(rustdoc::broken_intra_doc_links)]
52#![allow(clippy::useless_conversion)]
54
55use std::{
56 collections::HashMap,
57 ffi::{CStr, CString},
58 fmt,
59 os::raw::{c_char, c_int, c_uint, c_void},
60 slice,
61 str::{self, FromStr},
62};
63
64use libiio_sys::{self as ffi};
65use nix::errno::Errno;
66
67pub use crate::buffer::{AttrIterator as BufferAttrIterator, Buffer};
68pub use crate::channel::{
69 AttrIterator as ChannelAttrIterator, Channel, ChannelType, DataFormat, Direction,
70};
71pub use crate::context::{
72 AttrIterator as ContextAttrIterator, Backend, Context, DeviceIterator, InnerContext,
73};
74pub use crate::device::{AttrIterator as DeviceAttrIterator, ChannelIterator, Device};
75pub use crate::errors::{Error, Result};
76
77#[cfg(not(feature = "libiio_v0_19"))]
78pub use crate::scan_context::{ScanContext, ScanContextIterator};
79
80mod macros;
81
82pub mod buffer;
83pub mod channel;
84pub mod context;
85pub mod device;
86pub mod errors;
87
88#[cfg(not(feature = "libiio_v0_19"))]
89pub mod scan_context;
90
91const ATTR_BUF_SIZE: usize = 16384;
94
95fn cstring_opt(pstr: *const c_char) -> Option<String> {
101 unsafe {
102 pstr.as_ref().map(|_| {
103 let name = CStr::from_ptr(pstr);
104 name.to_str().unwrap_or_default().to_string()
105 })
106 }
107}
108
109pub(crate) fn sys_result<T>(ret: i32, result: T) -> Result<T> {
110 match ret {
111 ret if ret < 0 => Err(Errno::from_raw(-ret).into()),
112 _ => Ok(result),
113 }
114}
115
116pub trait ToAttribute: fmt::Display {
118 fn to_attr(&self) -> Result<String> {
124 Ok(format!("{}", self))
125 }
126}
127
128pub trait FromAttribute: FromStr {
130 fn from_attr(s: &str) -> Result<Self> {
132 let val = Self::from_str(s).map_err(|_| Error::StringConversionError)?;
133 Ok(val)
134 }
135}
136
137impl ToAttribute for bool {
143 fn to_attr(&self) -> Result<String> {
144 Ok((if *self { "1" } else { "0" }).into())
145 }
146}
147
148impl FromAttribute for bool {
149 fn from_attr(s: &str) -> Result<Self> {
150 Ok(s.trim() != "0")
151 }
152}
153
154impl ToAttribute for i32 {}
156impl ToAttribute for u32 {}
157impl ToAttribute for i64 {}
158impl ToAttribute for u64 {}
159impl ToAttribute for i128 {}
160impl ToAttribute for u128 {}
161impl ToAttribute for f64 {}
162impl ToAttribute for str {}
163impl ToAttribute for &str {}
164impl ToAttribute for String {}
165
166impl FromAttribute for i32 {}
167impl FromAttribute for u32 {}
168impl FromAttribute for i64 {}
169impl FromAttribute for u64 {}
170impl FromAttribute for i128 {}
171impl FromAttribute for u128 {}
172impl FromAttribute for f64 {}
173impl FromAttribute for String {}
174
175pub(crate) unsafe extern "C" fn attr_read_all_cb(
178 _chan: *mut ffi::iio_device,
179 attr: *const c_char,
180 val: *const c_char,
181 _len: usize,
182 pmap: *mut c_void,
183) -> c_int {
184 if attr.is_null() || val.is_null() || pmap.is_null() {
185 return -1;
186 }
187
188 let attr = CStr::from_ptr(attr).to_string_lossy().to_string();
189 let val = CStr::from_ptr(val).to_string_lossy().to_string();
191 let map: &mut HashMap<String, String> = &mut *pmap.cast();
192 map.insert(attr, val);
193 0
194}
195
196#[derive(Debug, PartialEq, Eq)]
200pub struct Version {
201 pub major: u32,
203 pub minor: u32,
205 pub git_tag: String,
207}
208
209impl fmt::Display for Version {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 write!(f, "{}.{} tag: {}", self.major, self.minor, self.git_tag)
212 }
213}
214
215pub fn library_version() -> Version {
219 let mut major: c_uint = 0;
220 let mut minor: c_uint = 0;
221
222 const BUF_SZ: usize = 8;
223 let mut buf = vec![' ' as c_char; BUF_SZ];
224 let pbuf = buf.as_mut_ptr();
225
226 unsafe { ffi::iio_library_get_version(&mut major, &mut minor, pbuf) };
227
228 let sgit = unsafe {
229 if buf.contains(&0) {
230 CStr::from_ptr(pbuf).to_owned()
231 }
232 else {
233 let slc = str::from_utf8(slice::from_raw_parts(pbuf.cast(), BUF_SZ)).unwrap();
234 CString::new(slc).unwrap()
235 }
236 };
237 Version {
238 major: major as u32,
239 minor: minor as u32,
240 git_tag: sgit.to_string_lossy().into_owned(),
241 }
242}
243
244#[cfg(test)]
247mod tests {
248 use super::*;
249 use std::ptr;
250
251 #[test]
253 fn version() {
254 let v1 = library_version();
255 let v2 = library_version();
256 assert!(v1 == v2);
257 }
258
259 #[test]
260 fn test_cstring_opt() {
261 assert_eq!(cstring_opt(ptr::null()), None);
262
263 let s: &[u8] = &[b'h', b'e', b'l', b'l', b'o', 0];
264 let p = s.as_ptr() as *const c_char;
265 assert_eq!(cstring_opt(p), Some(String::from("hello")));
266 }
267
268 #[test]
269 fn test_sys_result() {
270 assert!(sys_result(-1, "hello").is_err());
271 assert!(matches!(sys_result(1, "hello"), Ok("hello")));
272 }
273
274 #[test]
275 fn val_from_attr_str() {
276 let val: i32 = i32::from_attr("123").unwrap();
277 assert_eq!(val, 123);
278
279 let val = bool::from_attr("1").unwrap();
280 assert!(val);
281
282 let val: bool = FromAttribute::from_attr(" 0 \n").unwrap();
283 assert!(!val);
284
285 let val: String = String::from_attr("hello").unwrap();
286 assert_eq!(&val, "hello");
287 }
288
289 #[test]
290 fn val_to_attr_string() {
291 let s = i32::to_attr(&123).unwrap();
292 assert_eq!(&s, "123");
293
294 let s = bool::to_attr(&true).unwrap();
295 assert_eq!(&s, "1");
296
297 let s = bool::to_attr(&false).unwrap();
298 assert_eq!(&s, "0");
299
300 let s = ToAttribute::to_attr("hello").unwrap();
301 assert_eq!(&s, "hello");
302
303 let s = String::to_attr(&"hello".to_string()).unwrap();
304 assert_eq!(s.as_str(), "hello");
305 }
306}