use crate::{
attrs::{AttrMap, Attribute, HasAttributes},
timeseries::{HasSeries, HasTimeSeries, SeriesMap, TsMap},
};
use abi_stable::{
external_types::{parking_lot::mutex::RMutexGuard, RMutex},
std_types::{
RArc, RDuration,
ROption::{self, RNone, RSome},
RString, RVec,
},
StableAbi,
};
#[repr(C)]
#[derive(Clone, StableAbi)]
pub struct Node {
name: RString,
inner: RArc<RMutex<NodeInner>>,
}
impl std::fmt::Display for Node {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "<Node {:?}>", self.name)
}
}
impl<'a> Node {
pub fn new(index: usize, name: &str) -> Self {
Self {
name: name.to_string().into(),
inner: RArc::new(RMutex::new(NodeInner::new(index, name))),
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn lock(&'a self) -> RMutexGuard<'a, NodeInner> {
self.inner.lock()
}
pub fn try_lock(&'a self) -> Option<RMutexGuard<'a, NodeInner>> {
self.inner.try_lock().into_option()
}
pub fn try_lock_for(&'a self, dur: RDuration) -> Option<RMutexGuard<'a, NodeInner>> {
self.inner.try_lock_for(dur).into_option()
}
}
#[repr(C)]
#[derive(StableAbi, Default, Clone)]
pub struct NodeInner {
pub(crate) index: usize,
pub(crate) name: RString,
pub x_pos: f64,
pub y_pos: f64,
pub(crate) level: u64,
pub(crate) order: u64,
pub(crate) weight: u64,
pub(crate) attributes: AttrMap,
pub(crate) series: SeriesMap,
pub(crate) timeseries: TsMap,
pub(crate) input_names: RVec<RString>,
pub(crate) inputs: RVec<Node>,
pub(crate) output_names: RVec<RString>,
pub(crate) outputs: RVec<Node>,
}
impl HasAttributes for NodeInner {
fn node_name(&self) -> Option<&str> {
Some(self.name())
}
fn attr_map(&self) -> &AttrMap {
&self.attributes
}
fn attr_map_mut(&mut self) -> &mut AttrMap {
&mut self.attributes
}
}
impl HasSeries for NodeInner {
fn series_map(&self) -> &SeriesMap {
&self.series
}
fn series_map_mut(&mut self) -> &mut SeriesMap {
&mut self.series
}
}
impl HasTimeSeries for NodeInner {
fn ts_map(&self) -> &TsMap {
&self.timeseries
}
fn ts_map_mut(&mut self) -> &mut TsMap {
&mut self.timeseries
}
}
impl NodeInner {
pub fn new(index: usize, name: &str) -> Self {
let mut node = Self {
index,
name: name.into(),
..Default::default()
};
node.set_attr("NAME", Attribute::String(name.into()));
node.set_attr("INDEX", Attribute::Integer(index as i64));
node
}
pub fn name(&self) -> &str {
&self.name
}
pub fn index(&self) -> usize {
self.index
}
pub fn set_index(&mut self, index: usize) {
self.index = index;
self.set_attr("INDEX", Attribute::Integer(index as i64));
}
pub fn pos(&self) -> (f64, f64) {
(self.x_pos, self.y_pos)
}
pub fn set_pos(&mut self, pos: (f64, f64)) {
self.x_pos = pos.0;
self.y_pos = pos.1;
self.set_attr(
"POSITION",
Attribute::Array(vec![Attribute::Float(pos.0), Attribute::Float(pos.1)].into()),
);
}
pub fn level(&self) -> u64 {
self.level
}
pub fn order(&self) -> u64 {
self.order
}
pub fn weight(&self) -> u64 {
self.weight
}
pub fn set_level(&mut self, level: u64) {
self.level = level;
self.set_attr("LEVEL", Attribute::Integer(level as i64));
}
pub fn set_order(&mut self, order: u64) {
self.order = order;
self.set_attr("ORDER", Attribute::Integer(order as i64));
}
pub fn set_weight(&mut self, weight: u64) {
self.weight = weight;
self.set_attr("WEIGHT", Attribute::Integer(weight as i64));
}
pub fn input(&self) -> ROption<&Node> {
if let [inp] = self.inputs.as_slice() {
RSome(inp)
} else {
RNone
}
}
pub fn inputs(&self) -> &[Node] {
&self.inputs
}
pub(crate) fn inputs_mut(&mut self) -> &mut RVec<Node> {
&mut self.inputs
}
pub fn is_leaf(&self) -> bool {
self.inputs.is_empty()
}
pub fn input_names(&self) -> &[RString] {
self.input_names.as_slice()
}
pub fn output_names(&self) -> &[RString] {
self.output_names.as_slice()
}
pub fn refresh_input_names(&mut self) {
self.input_names = self
.inputs()
.iter()
.map(|a| a.name().to_string().into())
.collect::<Vec<RString>>()
.into();
}
pub fn refresh_output_names(&mut self) {
self.output_names = self
.outputs()
.iter()
.map(|a| a.name().to_string().into())
.collect::<Vec<RString>>()
.into();
}
pub fn add_input(&mut self, input: Node) {
self.inputs.push(input);
self.refresh_input_names();
}
pub fn unset_inputs(&mut self) -> Vec<Node> {
self.input_names = RVec::new();
self.inputs.drain(..).collect()
}
pub fn remove_input(&mut self, input: &str) {
self.inputs = self
.inputs
.drain(..)
.filter(|n| n.name() != input)
.collect::<Vec<_>>()
.into();
self.refresh_input_names();
}
pub fn order_inputs(&mut self) {
self.inputs.sort_by(|a, b| {
b.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.order
.partial_cmp(
&a.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.order,
)
.unwrap()
});
self.refresh_input_names();
}
pub fn output(&self) -> ROption<&Node> {
if let [out] = self.outputs.as_slice() {
RSome(out)
} else {
RNone
}
}
pub fn outputs(&self) -> &[Node] {
&self.outputs
}
pub(crate) fn outputs_mut(&mut self) -> &mut RVec<Node> {
&mut self.outputs
}
pub fn is_root(&self) -> bool {
self.outputs.is_empty()
}
pub fn add_output(&mut self, output: Node) {
self.outputs.push(output);
self.refresh_output_names();
}
pub fn unset_outputs(&mut self) -> Vec<Node> {
self.output_names = RVec::new();
self.outputs.drain(..).collect()
}
pub fn remove_output(&mut self, output: &str) {
self.outputs = self
.outputs
.drain(..)
.filter(|n| {
n.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.name()
!= output
})
.collect::<Vec<_>>()
.into();
self.refresh_output_names();
}
pub fn order_outputs(&mut self) {
self.outputs.sort_by(|a, b| {
b.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.order
.partial_cmp(
&a.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.order,
)
.unwrap()
});
self.refresh_output_names();
}
pub fn edge(&self) -> Option<Node> {
match self.edges().as_slice() {
[n] => Some(n.clone()),
_ => None,
}
}
pub fn edges(&self) -> Vec<Node> {
self.inputs()
.iter()
.chain(self.outputs())
.cloned()
.collect()
}
pub fn move_aside(&mut self) -> Result<(), &'static str> {
match self.outputs.as_slice() {
[] => self.inputs().iter().for_each(|i| {
i.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.unset_outputs();
}),
[o] => self.inputs().iter().for_each(|i| {
o.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.add_input(i.clone());
i.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.unset_outputs();
i.try_lock()
.expect(&format!("mutex error: {:?} {}", file!(), line!()))
.add_output(o.clone());
}),
_outs => {
return Err("move aside with multiple output nodes is not implemented");
}
}
self.unset_inputs();
Ok(())
}
}