1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

use std::ffi::c_void;

use crate::{bindings::{mpr_sig, mpr_sig_free, mpr_sig_get_inst_status, mpr_sig_get_value, mpr_status, mpr_sig_set_value, mpr_type}, device::MappableType};

pub struct Signal {
    pub(crate) handle: mpr_sig,
    pub(crate) owned: bool,
    pub(crate) data_type: mpr_type,
    pub(crate) vector_length: u32
}

unsafe impl Send for Signal {}
unsafe impl Sync for Signal {}

impl Drop for Signal {
    fn drop(&mut self) {
        if self.owned {
            unsafe {
                mpr_sig_free(self.handle);
            }
        }
    }
}

/// An error that can occur when getting or setting the value of a signal.
#[derive(Debug)]
pub enum SignalError {
    #[doc = "The data type of the signal does not match the type of the passed generic type."]
    WrongType,
    #[doc = "The signal does not have a value set yet."]
    NoValue,
    #[doc = "The length of the passed slice does not match the vector length of the signal."]
    WrongLengthArg
}

impl Signal {
    /// Get the status of the signal instance.
    /// Calling this function will reset the flags `was_set_remote` and `was_set_local` and return their pre-reset values.
    /// 
    /// # Examples
    /// Use this function to check if you should push or read data from the signal:
    /// ```
    /// use libmapper_rs::device::Device;
    /// use libmapper_rs::signal::Signal;
    /// use std::time::Duration;
    /// fn main_loop(dev: &Device, sig: &mut Signal, value: &mut f64) {
    ///     loop {
    ///        dev.poll_and_block(Duration::from_millis(10));
    /// 
    ///        if sig.get_status().was_set_remote() { // check if there's a new value waiting for us
    ///          let (new_value, _) = sig.get_value_single::<f64>().unwrap();
    ///          *value = new_value;
    ///        } else {
    ///          sig.set_value_single(value);
    ///        }
    ///     }
    /// }
    /// ```
    pub fn get_status(&self) -> SignalStatus {
        SignalStatus(unsafe {
            mpr_sig_get_inst_status(self.handle, 0)
        })
    }

    /// Get the type of data this signal is storing.
    pub fn get_data_type(&self) -> mpr_type {
        self.data_type
    }

    /// Get the length of the vector this signal is storing.
    /// This will be how long the slice returned from Signal::get_value is.
    /// 
    /// If this is 1, you should use Signal::get_value_single instead.
    pub fn get_vector_length(&self) -> u32 {
        self.vector_length
    }
}

/// A struct that represents the status of a signal instance.
/// When this struct is created by Signal::get_status(), the flags `was_set_remote` and `was_set_local` will be reset.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SignalStatus(i32);

impl SignalStatus {
    /// Returns true if the signal was set remotely since the last time the status was queried.
    pub fn was_set_remote(&self) -> bool {
        self.0 & mpr_status::MPR_STATUS_UPDATE_REM as i32 != 0
    }
    /// Returns true if the signal was set locally since the last time the status was queried.
    pub fn was_set_local(&self) -> bool {
        self.0 & mpr_status::MPR_STATUS_UPDATE_LOC as i32 != 0
    }
    /// Returns true if the signal has a value (i.e. Signal::get_value* will return Some).
    pub fn has_value(&self) -> bool {
        self.0 & mpr_status::MPR_STATUS_HAS_VALUE as i32 != 0
    }
    /// If the signal is active
    pub fn is_active(&self) -> bool {
        self.0 & mpr_status::MPR_STATUS_ACTIVE as i32 != 0
    }
    /// If the actual numerical value of the signal has changed since the last time the status was queried.
    pub fn value_updated(&self) -> bool {
        self.0 & mpr_status::MPR_STATUS_NEW_VALUE as i32 != 0
    }
}

impl Signal {
    /// Set the value of the signal.
    /// This function will return [`SignalError::WrongType`](SignalError:WrongType) if the passed generic type doesn't match the signal's type.
    /// 
    /// If this signal is a vector, only the first element of the vector will be set.
    pub fn set_value_single<T: MappableType + Copy>(&mut self, value: &T) -> Result<(), SignalError> {
        if T::get_mpr_type() != self.data_type {
            return Err(SignalError::WrongType);
        }
        unsafe {
            mpr_sig_set_value(self.handle, 0, 1,  self.data_type, value as *const T as *const c_void);
        }
        Ok(())
    }

    /// Get the value of the signal.
    /// This function will return [`SignalError::WrongType`](SignalError:WrongType) if the passed generic type doesn't match the signal's type.
    /// 
    /// If this signal is a vector, only the first element of the vector will be returned.
    pub fn get_value_single<T: MappableType + Copy>(&self) -> Result<(T, u64), SignalError> {
        let mut time = 0;
        if T::get_mpr_type() != self.data_type {
            return Err(SignalError::WrongType);
        }
        unsafe {
            let ptr = mpr_sig_get_value(self.handle, 0, &mut time);
            if ptr.is_null() {
                return Err(SignalError::NoValue);
            }
            let value = *(ptr as *const T);
            Ok((value, time))
        }
    }

    /// Get the value of the signal.
    /// This function will return [`SignalError::WrongType`](SignalError:WrongType) if the passed generic type doesn't match the signal's type.
    /// 
    /// The length of the returned slice will be equal to the value returned by [get_vector_length](Signal::get_vector_length).
    pub fn get_value<T: MappableType + Copy>(&self) -> Result<(Vec<T>, u64), SignalError> {
        let mut time = 0;
        if T::get_mpr_type() != self.data_type {
            return Err(SignalError::WrongType);
        }
        unsafe {
            let ptr = mpr_sig_get_value(self.handle, 0, &mut time);
            if ptr.is_null() {
                return Err(SignalError::NoValue);
            }
            let slice = std::slice::from_raw_parts(ptr as *const T, self.vector_length as usize);
            Ok((slice.to_vec(), time))
        }
    }

    /// Set the value of the signal.
    /// This function will return [`SignalError::WrongType`](SignalError:WrongType) if the passed generic type doesn't match the signal's type.
    /// 
    /// The length of the slice must be equal to the value returned by [get_vector_length](Signal::get_vector_length).
    /// If the lengths are not equal this function return an `Err` of `SignalError::WrongLengthArg`.
    pub fn set_value<T: MappableType + Copy>(&mut self, values: &[T]) -> Result<(), SignalError> {
        if T::get_mpr_type() != self.data_type {
            return Err(SignalError::WrongType);
        }
        if values.len() != self.vector_length as usize {
            return Err(SignalError::WrongLengthArg);
        }
        unsafe {
            mpr_sig_set_value(self.handle, 0, self.vector_length as i32, self.data_type, values.as_ptr() as *const c_void);
        }
        Ok(())
    }
}