tango_client/
dbase.rs

1//! Binding to the Tango Database API.
2
3use std::ffi::CString;
4use std::mem;
5use std::ptr;
6use libc::{c_char, c_void};
7
8use crate::c;
9use crate::error::{TangoResult, TangoError};
10use crate::types::*;
11
12
13/// A client to the Tango database.
14pub struct DatabaseProxy {
15    ptr: *mut c_void,
16}
17
18impl Drop for DatabaseProxy {
19    fn drop(&mut self) {
20        let error_stack = unsafe { c::tango_delete_database_proxy(self.ptr) };
21        if !error_stack.is_null() {
22            // we need to construct the error to deallocate the stack
23            drop(TangoError::from_stack(error_stack));
24        }
25    }
26}
27
28impl DatabaseProxy {
29    /// Connect to the database.
30    ///
31    /// Note: this always uses the database referenced by the `TANGO_HOST`
32    /// environment variable.
33    pub fn new() -> TangoResult<DatabaseProxy> {
34        let mut dev = ptr::null_mut();
35        tango_call!(tango_create_database_proxy,
36                    DatabaseProxy { ptr: dev },
37                    &mut dev)
38    }
39
40    /// Return a list of exported devices, filtered by the given name,
41    /// which can include `*` as wildcard.
42    ///
43    /// The return value will be a `DbDatum` containing either
44    /// `PropertyValue::Empty` or `PropertyValue::StringArray` with the
45    /// device names.
46    pub fn get_device_exported(&self, name_filter: &str) -> TangoResult<DbDatum> {
47        let c_filter = CString::new(name_filter).unwrap();
48        let mut db_datum = unsafe { mem::zeroed() };
49        tango_call!(tango_get_device_exported,
50                    unsafe { DbDatum::from_c(db_datum, true) },
51                    self.ptr, c_filter.as_ptr() as *mut c_char, &mut db_datum)
52    }
53
54    /// Return a list of exported devices, for the given class.
55    ///
56    /// The return value will be a `DbDatum` containing either
57    /// `PropertyValue::Empty` or `PropertyValue::StringArray` with the
58    /// device names.
59    pub fn get_device_exported_for_class(&self, class_name: &str) -> TangoResult<DbDatum> {
60        let c_class = CString::new(class_name).unwrap();
61        let mut db_datum = unsafe { mem::zeroed() };
62        tango_call!(tango_get_device_exported_for_class,
63                    unsafe { DbDatum::from_c(db_datum, true) },
64                    self.ptr, c_class.as_ptr() as *mut c_char, &mut db_datum)
65    }
66
67    /// Return a list of objects for which free properties are defined,
68    /// considering the given name filter, which can include `*` as a wildcard.
69    ///
70    /// The return value will be a `DbDatum` containing either
71    /// `PropertyValue::Empty` or `PropertyValue::StringArray` with the object
72    /// names.
73    pub fn get_object_list(&self, name_filter: &str) -> TangoResult<DbDatum> {
74        let c_filter = CString::new(name_filter).unwrap();
75        let mut db_datum = unsafe { mem::zeroed() };
76        tango_call!(tango_get_object_list,
77                    unsafe { DbDatum::from_c(db_datum, true) },
78                    self.ptr, c_filter.as_ptr() as *mut c_char, &mut db_datum)
79    }
80
81    /// Return a list of free properties for the given object, considering the
82    /// given name filter, which can include `*` as a wildcard.
83    ///
84    /// The return value will be a `DbDatum` containing either
85    /// `PropertyValue::Empty` or `PropertyValue::StringArray` with the property
86    /// names.
87    pub fn get_object_property_list(&self, obj_name: &str, name_filter: &str) -> TangoResult<DbDatum> {
88        let c_name = CString::new(obj_name).unwrap();
89        let c_filter = CString::new(name_filter).unwrap();
90        let mut db_datum = unsafe { mem::zeroed() };
91        tango_call!(tango_get_object_property_list,
92                    unsafe { DbDatum::from_c(db_datum, true) },
93                    self.ptr, c_name.as_ptr() as *mut c_char,
94                    c_filter.as_ptr() as *mut c_char, &mut db_datum)
95    }
96
97    /// Query the database for one or more free properties of the named object.
98    ///
99    /// The value of the input `DbDatum`s is ignored; in the output they contain
100    /// the property values.
101    pub fn get_property(&self, obj_name: &str, prop_list: Vec<DbDatum>) -> TangoResult<Vec<DbDatum>> {
102        let c_name = CString::new(obj_name).unwrap();
103        let mut db_data = unsafe { mem::zeroed::<c::DbData>() };
104        let mut ptr_vec = Vec::with_capacity(prop_list.len());
105        let mut cstr_vec = Vec::with_capacity(prop_list.len());
106        db_data.length = prop_list.len() as u32;
107        for datum in prop_list {
108            let (datum, cstr) = unsafe { datum.into_c() };
109            ptr_vec.push(datum);
110            cstr_vec.push(cstr);
111        }
112        db_data.sequence = ptr_vec.as_mut_ptr();
113        tango_call!(tango_get_property, (), self.ptr,
114                    c_name.as_ptr() as *mut c_char, &mut db_data)?;
115        let mut res = Vec::with_capacity(db_data.length as usize);
116        unsafe {
117            for i in 0..db_data.length {
118                let db_datum = ptr::read(db_data.sequence.offset(i as isize));
119                res.push(DbDatum::from_c(db_datum, false));
120            }
121            c::tango_free_DbData(&mut db_data);
122        }
123        Ok(res)
124    }
125
126    /// Update one or more free properties of the named object.
127    pub fn put_property(&mut self, obj_name: &str, prop_list: Vec<DbDatum>) -> TangoResult<()> {
128        let c_name = CString::new(obj_name).unwrap();
129        let mut db_data = unsafe { mem::zeroed::<c::DbData>() };
130        let mut ptr_vec = Vec::with_capacity(prop_list.len());
131        let mut cstr_vec = Vec::with_capacity(prop_list.len());
132        db_data.length = prop_list.len() as u32;
133        for datum in prop_list {
134            let (datum, cstr) = unsafe { datum.into_c() };
135            ptr_vec.push(datum);
136            cstr_vec.push(cstr);
137        }
138        db_data.sequence = ptr_vec.as_mut_ptr();
139        let res = tango_call!(tango_put_property, (),
140                              self.ptr, c_name.as_ptr() as *mut c_char, &mut db_data);
141        unsafe {
142            for ptr in ptr_vec {
143                DbDatum::free_c_data(ptr);
144            }
145        }
146        res
147    }
148
149    /// Delete one or more free properties of the named object.
150    pub fn delete_property(&mut self, obj_name: &str, prop_list: &[&str]) -> TangoResult<()> {
151        let c_name = CString::new(obj_name).unwrap();
152        let mut db_data = unsafe { mem::zeroed::<c::DbData>() };
153        let mut ptr_vec = Vec::with_capacity(prop_list.len());
154        let mut cstr_vec = Vec::with_capacity(prop_list.len());
155        db_data.length = prop_list.len() as u32;
156        for prop in prop_list {
157            let datum = DbDatum::name_only(prop);
158            let (datum, cstr) = unsafe { datum.into_c() };
159            ptr_vec.push(datum);
160            cstr_vec.push(cstr);
161        }
162        db_data.sequence = ptr_vec.as_mut_ptr();
163        let res = tango_call!(tango_delete_property, (),
164                              self.ptr, c_name.as_ptr() as *mut c_char, &mut db_data);
165        unsafe {
166            for ptr in ptr_vec {
167                DbDatum::free_c_data(ptr);
168            }
169        }
170        res
171    }
172}