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
//! Graph and Map types for working with libmapper's distributed graph.
//!
//! The [Map] type is used to create a connection between two [Signal] instances.
//!
//! The [Graph] type can be shared between devices to improve performance and memory usage.
use std::{ffi::c_int, time::Duration};
use crate::{bindings::*, signal::Signal, object::MapperObject};
/// A graph is a lightweight connection to libmapper's distributed graph.
/// You can use a graph to create maps and query the state of the graph.
pub struct Graph {
pub(crate) handle: mpr_graph,
owned: bool
}
unsafe impl Send for Graph {}
unsafe impl Sync for Graph {}
impl Graph {
pub fn create() -> Graph {
Graph {
owned: true,
handle: unsafe { mpr_graph_new(0) }
}
}
}
impl Drop for Graph {
fn drop(&mut self) {
if self.owned {
unsafe {
mpr_graph_free(self.handle);
}
}
}
}
impl Graph {
/// Poll the graph without blocking
pub fn poll(&self) {
unsafe {
mpr_graph_poll(self.handle, 0);
}
}
/// Poll the graph and block for the specified amount of time
///
/// Use this instead of sleeping in a loop
pub fn poll_and_block(&self, time: Duration) {
unsafe {
mpr_graph_poll(self.handle, time.as_millis() as c_int);
}
}
}
/// A directional connection between multiple signals. Changes to input signals will affect output signals.
///
/// # Examples
/// Create a map between two signals:
/// ```
/// use std::thread;
/// use std::time::Duration;
/// use libmapper_rs::graph::Map;
/// use libmapper_rs::signal::Signal;
/// fn create_map(sig_a: &Signal, sig_b: &Signal) -> Map {
/// let map = Map::create(sig_a, sig_b);
/// loop {
/// if map.is_ready() {
/// break;
/// }
/// thread::sleep(Duration::from_millis(10));
/// }
/// map
/// }
/// ```
pub struct Map {
pub(crate) handle: mpr_map
}
impl Map {
/// Create a new map between two signals.
/// This does not actually create the map in the graph, [push](Map::push) must be called to let the rest of the graph know about the map.
pub fn create(src: &Signal, dst: &Signal) -> Map {
Map {
handle: unsafe { mpr_map_new(1, &src.handle, 1, &dst.handle) }
}
}
/// Publish this map to the distributed graph.
/// After calling this function and once [is_ready](Map::is_ready) returns `true`, the map is active.
pub fn push(&self) {
unsafe {
mpr_obj_push(self.handle);
}
}
/// Returns `true` once the map has been published and is active.
/// Otherwise, returns false.
pub fn is_ready(&self) -> bool {
unsafe {
mpr_map_get_is_ready(self.handle) != 0
}
}
/// Destroy the map, severing the connection between the signals.
pub fn release(self) {
unsafe {
mpr_map_release(self.handle)
}
}
/// Set the expression used to map the values from the source(s) to the destination.
///
/// This is a helper function wrapping [`MapperObject::set_property_str`]
pub fn set_expr(&self, expression: &str) {
self.set_property_str(mpr_prop::MPR_PROP_EXPR, expression);
}
}