notation_model 0.6.0

Fun notation - runtime models
Documentation
use std::fmt::Display;
use std::sync::{Arc, Weak};

use notation_proto::prelude::Units;

use crate::prelude::{LaneEntry, LaneKind, Slice, Tab, TabBar, TabBarProps, Track, TrackProps, LaneEntryProps};

#[derive(Copy, Clone, Debug, Default)]
pub struct BarLaneProps {
    pub index: usize,
    pub track: TrackProps,
}

#[derive(Clone, Debug)]
pub struct BarLane {
    pub bar: Weak<TabBar>,
    pub kind: LaneKind,
    pub track: Arc<Track>,
    pub entries: Vec<Arc<LaneEntry>>,
    pub props: BarLaneProps,
}
impl Display for BarLane {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "<BarLane>({} E:{})",
            self.id(),
            self.entries.len()
        )
    }
}

impl BarLane {
    pub fn id(&self) -> String {
        self.kind_id(self.kind)
    }
    pub fn kind_id(&self, kind: LaneKind) -> String {
        format!("{}:{}", self.track.id, kind)
    }
    pub fn order(&self) -> (usize, LaneKind) {
        (self.track.props.index, self.kind)
    }
    pub fn try_new_arc(
        bar: Weak<TabBar>,
        index: usize,
        track: &Arc<Track>,
        slice: Slice,
    ) -> Option<Arc<Self>> {
        let model_entries = track.get_entries(&slice.begin, &slice.end);
        let kind = LaneKind::of_entries(&track.kind, &model_entries);
        if !kind.is_none() {
            Some(Arc::<Self>::new_cyclic(|weak_self| {
                let props = BarLaneProps {
                    index,
                    track: track.props,
                };
                let entries = LaneEntry::new_entries(model_entries, weak_self, slice);
                Self {
                    bar,
                    kind,
                    track: track.clone(),
                    entries,
                    props,
                }
            }))
        } else {
            None
        }
    }
    pub fn merge_lane(&self, lane: &BarLane) -> Arc<Self> {
        Arc::<Self>::new_cyclic(|weak_self| {
            let mut entries = Vec::new();
            for entry in self.entries.iter() {
                entries.push(entry.clone());
            }
            for entry in lane.entries.iter() {
                entries.push(entry.clone());
            }
            entries.sort_by(|a, b| {
                a.props.in_bar_pos.cmp(&b.props.in_bar_pos)
            });
            let entries = entries.iter().enumerate().map(|(index, entry)| {
                let merged_entry = LaneEntry {
                    props: LaneEntryProps {
                        slice: entry.props.slice.clone(),
                        index,
                        ..entry.props
                    },
                    lane: weak_self.clone(),
                    model: entry.model.clone(),
                };
                Arc::new(merged_entry)
            }).collect();
            Self {
                bar: self.bar.clone(),
                kind: self.kind,
                track: self.track.clone(),
                entries,
                props: self.props,
            }
        })
    }
    pub fn bar(&self) -> Option<Arc<TabBar>> {
        self.bar.upgrade().map(|x| x.clone())
    }
    pub fn tab(&self) -> Option<Arc<Tab>> {
        self.bar().and_then(|x| x.tab())
    }
    pub fn bar_props(&self) -> TabBarProps {
        self.bar().map(|x| x.props).unwrap_or_default()
    }
    pub fn get_entry_at<T, F: Fn(&LaneEntry) -> Option<T>>(
        &self,
        in_bar_pos: Units,
        predicate: &F,
    ) -> Option<T> {
        for entry in self.entries.iter() {
            if in_bar_pos < entry.props.in_bar_pos {
                break;
            } else {
                if in_bar_pos < entry.props.in_bar_pos + entry.model().props.tied_units {
                    if let Some(result) = predicate(entry.as_ref()) {
                        return Some(result);
                    }
                }
            }
        }
        None
    }
    pub fn get_next_entry<T, F: Fn(&LaneEntry) -> Option<T>>(
        &self,
        in_bar_pos: Units,
        predicate: &F,
    ) -> Option<T> {
        self.get_entry(&|x: &LaneEntry| {
            if x.props.in_bar_pos.is_bigger_than(&in_bar_pos) {
                predicate(x)
            } else {
                None
            }
        })
    }
}