use std::ffi::CString;
use std::os::raw::c_uint;
use std::ptr;
use std::rc::Rc;
use std::time::Duration;
use nix::errno::Errno;
use super::*;
use crate::ffi;
#[derive(Debug, Clone)]
pub struct Context {
inner: Rc<InnerContext>,
}
#[derive(Debug)]
struct InnerContext {
pub(crate) ctx: *mut ffi::iio_context,
}
impl Drop for InnerContext {
fn drop(&mut self) {
unsafe { ffi::iio_context_destroy(self.ctx) };
}
}
impl Context {
pub fn new() -> Result<Context> {
let ctx = unsafe { ffi::iio_create_default_context() };
if ctx.is_null() {
return Err(Errno::last().into());
}
Ok(Context {
inner: Rc::new(InnerContext { ctx }),
})
}
pub fn create_from_uri(uri: &str) -> Result<Context> {
let uri = CString::new(uri)?;
let ctx = unsafe { ffi::iio_create_context_from_uri(uri.as_ptr()) };
if ctx.is_null() {
return Err(Errno::last().into());
}
Ok(Context {
inner: Rc::new(InnerContext { ctx }),
})
}
#[cfg(target_os = "linux")]
pub fn create_local() -> Result<Context> {
let ctx = unsafe { ffi::iio_create_local_context() };
if ctx.is_null() {
return Err(Errno::last().into());
}
Ok(Context {
inner: Rc::new(InnerContext { ctx }),
})
}
pub fn create_network(host: &str) -> Result<Context> {
let host = CString::new(host)?;
let ctx = unsafe { ffi::iio_create_network_context(host.as_ptr()) };
if ctx.is_null() {
return Err(Errno::last().into());
}
Ok(Context {
inner: Rc::new(InnerContext { ctx }),
})
}
pub fn create_xml(xml_file: &str) -> Result<Context> {
let xml_file = CString::new(xml_file)?;
let ctx = unsafe { ffi::iio_create_xml_context(xml_file.as_ptr()) };
if ctx.is_null() {
return Err(Errno::last().into());
}
Ok(Context {
inner: Rc::new(InnerContext { ctx }),
})
}
pub fn create_xml_mem(xml: &str) -> Result<Context> {
let n = xml.len();
let xml = CString::new(xml)?;
let ctx = unsafe { ffi::iio_create_xml_context_mem(xml.as_ptr(), n) };
if ctx.is_null() {
return Err(Errno::last().into());
}
Ok(Context {
inner: Rc::new(InnerContext { ctx }),
})
}
pub fn name(&self) -> String {
let pstr = unsafe { ffi::iio_context_get_name(self.inner.ctx) };
cstring_opt(pstr).unwrap_or_default()
}
pub fn description(&self) -> String {
let pstr = unsafe { ffi::iio_context_get_description(self.inner.ctx) };
cstring_opt(pstr).unwrap_or_default()
}
pub fn xml(&self) -> String {
let pstr = unsafe { ffi::iio_context_get_xml(self.inner.ctx) };
cstring_opt(pstr).unwrap_or_default()
}
pub fn num_attrs(&self) -> usize {
let n = unsafe { ffi::iio_context_get_attrs_count(self.inner.ctx) };
n as usize
}
pub fn get_attr(&self, idx: usize) -> Result<(String, String)> {
let mut pname: *const c_char = ptr::null();
let mut pval: *const c_char = ptr::null();
let ret = unsafe {
ffi::iio_context_get_attr(self.inner.ctx, idx as c_uint, &mut pname, &mut pval)
};
if ret < 0 {
return Err(errno::from_i32(ret).into());
}
let name = cstring_opt(pname);
let val = cstring_opt(pval);
if name.is_none() || val.is_none() {
return Err(Error::General("String conversion error".into()));
}
Ok((name.unwrap(), val.unwrap()))
}
pub fn attributes(&self) -> AttrIterator {
AttrIterator { ctx: self, idx: 0 }
}
pub fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
let ms: u64 = 1000 * timeout.as_secs() + u64::from(timeout.subsec_millis());
self.set_timeout_ms(ms)
}
pub fn set_timeout_ms(&mut self, ms: u64) -> Result<()> {
let ret = unsafe { ffi::iio_context_set_timeout(self.inner.ctx, ms as c_uint) };
sys_result(ret, ())
}
pub fn num_devices(&self) -> usize {
unsafe { ffi::iio_context_get_devices_count(self.inner.ctx) as usize }
}
pub fn get_device(&self, idx: usize) -> Result<Device> {
let dev = unsafe { ffi::iio_context_get_device(self.inner.ctx, idx as c_uint) };
if dev.is_null() {
return Err(Error::InvalidIndex);
}
Ok(Device {
dev,
ctx: self.clone(),
})
}
pub fn find_device(&self, name: &str) -> Option<Device> {
let name = CString::new(name).unwrap();
let dev = unsafe { ffi::iio_context_find_device(self.inner.ctx, name.as_ptr()) };
if dev.is_null() {
None
}
else {
Some(Device {
dev,
ctx: self.clone(),
})
}
}
pub fn devices(&self) -> DeviceIterator {
DeviceIterator { ctx: self, idx: 0 }
}
pub fn destroy(self) {}
}
impl PartialEq for Context {
fn eq(&self, other: &Context) -> bool {
self.inner.ctx == other.inner.ctx
}
}
pub struct DeviceIterator<'a> {
ctx: &'a Context,
idx: usize,
}
impl<'a> Iterator for DeviceIterator<'a> {
type Item = Device;
fn next(&mut self) -> Option<Self::Item> {
match self.ctx.get_device(self.idx) {
Ok(dev) => {
self.idx += 1;
Some(dev)
}
Err(_) => None,
}
}
}
pub struct AttrIterator<'a> {
ctx: &'a Context,
idx: usize,
}
impl<'a> Iterator for AttrIterator<'a> {
type Item = (String, String);
fn next(&mut self) -> Option<Self::Item> {
match self.ctx.get_attr(self.idx) {
Ok(name_val) => {
self.idx += 1;
Some(name_val)
}
Err(_) => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_context() {
let ctx = Context::new();
assert!(ctx.is_ok());
}
#[test]
fn clone_context() {
let ctx = Context::new();
assert!(ctx.is_ok());
let ctx = ctx.unwrap();
let ctx2 = ctx.clone();
assert!(ctx == ctx2);
}
#[test]
fn dev_iterator_count() {
let ctx = Context::new().unwrap();
let ndev = ctx.num_devices();
assert!(ndev != 0);
assert!(ctx.devices().count() == ndev);
}
#[test]
fn name() {
let ctx = Context::new().unwrap();
let name = ctx.name();
println!("Context name: {}", name);
assert!(name == "local" || name == "network");
}
#[test]
fn description() {
let ctx = Context::new().unwrap();
let desc = ctx.description();
println!("Context description: {}", desc);
assert!(!desc.is_empty());
}
}