1use std::{ffi::c_void, ptr};
2
3use crate::{bindings::{mpr_obj, mpr_obj_get_prop_by_idx, mpr_obj_get_type, mpr_obj_set_prop, mpr_prop, mpr_type}, device::{Device, MappableType}, graph::Map, signal::Signal};
4
5pub trait AsMprObject {
6 fn as_mpr_object(&self) -> *mut c_void;
7}
8
9impl AsMprObject for Signal {
10 fn as_mpr_object(&self) -> *mut c_void {
11 self.handle as *mut c_void
12 }
13}
14impl AsMprObject for Device<'_> {
15 fn as_mpr_object(&self) -> *mut c_void {
16 self.handle as *mut c_void
17 }
18}
19
20impl AsMprObject for Map {
21 fn as_mpr_object(&self) -> *mut c_void {
22 self.handle as *mut c_void
23 }
24}
25
26impl AsMprObject for mpr_obj {
27 fn as_mpr_object(&self) -> *mut c_void {
28 *self as *mut c_void
29 }
30}
31
32pub trait MapperObject {
33 fn get_type(&self) -> mpr_type;
35 fn set_property<T: MappableType>(&self, property: mpr_prop, value: T);
37 fn set_property_str(&self, property: mpr_prop, value: &str);
39
40 fn get_property<T: MappableType + Copy>(&self, property: mpr_prop) -> Result<T, PropertyError>;
43
44 fn get_property_str(&self, property: mpr_prop) -> Result<String, PropertyError>;
47
48 fn set_custom_property<T: MappableType>(&self, property: &str, value: T, publish: bool);
53}
54
55impl<A> MapperObject for A where A: AsMprObject {
56 fn get_type(&self) -> mpr_type {
57 unsafe {
58 mpr_obj_get_type(self.as_mpr_object())
59 }
60 }
61
62 fn set_property<T: MappableType>(&self, property: mpr_prop, value: T) {
63 unsafe {
64 mpr_obj_set_prop(self.as_mpr_object(), property, ptr::null(), 1, T::get_mpr_type(), &value as *const T as *const c_void, 1);
65 }
66 }
67
68 fn set_property_str(&self, property: mpr_prop, value: &str) {
69 let value_ptr = std::ffi::CString::new(value).expect("CString::new failed");
70 unsafe {
71 mpr_obj_set_prop(self.as_mpr_object(), property, ptr::null(), 1, mpr_type::MPR_STR, value_ptr.as_ptr() as *const c_void, 1);
72 }
73 }
74
75 fn get_property<T: MappableType + Copy>(&self, property: mpr_prop) -> Result<T, PropertyError> {
76 unsafe {
77 let mut actual_type: mpr_type = mpr_type::MPR_NULL;
78 let mut value: *const c_void = ptr::null();
79 mpr_obj_get_prop_by_idx(self.as_mpr_object(), property as i32, ptr::null_mut(), ptr::null_mut(),
80 &mut actual_type, &mut value, ptr::null_mut());
81 if value.is_null() {
82 return Err(PropertyError::PropertyNotFound)
83 }
84 if actual_type != T::get_mpr_type() {
85 return Err(PropertyError::TypeMismatch)
86 }
87 let value = value as *const T;
88 Ok(*value)
89 }
90 }
91
92 fn get_property_str(&self, property: mpr_prop) -> Result<String, PropertyError> {
93 unsafe {
94 let mut actual_type: mpr_type = mpr_type::MPR_NULL;
95 let mut value: *const c_void = ptr::null();
96 mpr_obj_get_prop_by_idx(self.as_mpr_object(), property as i32, ptr::null_mut(), ptr::null_mut(),
97 &mut actual_type, &mut value, ptr::null_mut());
98 if value.is_null() {
99 return Err(PropertyError::PropertyNotFound)
100 }
101 if actual_type != mpr_type::MPR_STR {
102 return Err(PropertyError::TypeMismatch)
103 }
104 let value = value as *const std::os::raw::c_char;
105 let value = std::ffi::CStr::from_ptr(value).to_str().unwrap().to_string();
106 Ok(value)
107 }
108 }
109
110 fn set_custom_property<T: MappableType>(&self, property: &str, value: T, publish: bool) {
111 let property = std::ffi::CString::new(property).expect("CString::new failed");
112 unsafe {
113 mpr_obj_set_prop(self.as_mpr_object(), mpr_prop::MPR_PROP_EXTRA, property.as_ptr() as *const i8,
114 1, T::get_mpr_type(), &value as *const T as *const c_void, publish.into());
115 }
116 }
117}
118
119#[derive(Debug, PartialEq)]
121pub enum PropertyError {
122 PropertyNotFound,
124 TypeMismatch
126}