use crate::buffer::BufferID; use std::collections::HashMap; use std::collections::HashSet; use std::fmt::Display; use thiserror::Error; #[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] pub enum Rank { Zero, One, Two, Three, } impl Display for Rank { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Rank::Zero => write!(f, "Rank 0"), Rank::One => write!(f, "Rank 1"), Rank::Two => write!(f, "Rank 2"), Rank::Three => write!(f, "Rank 3"), } } } #[derive(Error, Debug)] pub enum SelectionError { #[error("Cannnot change selection of {from} to {to}")] InvalidPromotion { from: Rank, to: Rank }, } #[derive(Debug, Clone)] pub struct Interval { pub start: usize, pub end: usize, capture_groups: Vec<(usize, usize)>, } impl Interval { pub fn is_disjoint(&self, other: &Interval) -> bool { self.start >= other.end || self.end <= other.start } } #[derive(Debug, Clone)] pub enum Selection { Position { pos: usize, buffer: BufferID, }, Range { buffer: BufferID, interval: Interval, }, Ranges { buffer: BufferID, ranges: Vec, }, MultiRanges { multi_ranges: HashMap>, }, } // rust is stupid and i have to make a wrapper class and worse still _other // people_ have to deal with my wrapper class! #[derive(Error, Debug)] pub enum VectoriseError where E: std::error::Error + 'static, { #[error("An error occurred during processing: {0}")] ProcessingError(E), #[error("A selection error occurred: {0}")] SelectionError(SelectionError), } impl From for VectoriseError where E: std::error::Error + 'static, { fn from(e: E) -> Self { VectoriseError::ProcessingError(e) } } impl Selection { pub fn empty() -> Self { Self::MultiRanges { multi_ranges: HashMap::new(), } } pub fn ranges_disjoint(ranges: &[Interval]) -> bool { if ranges.len() < 1 { return true; } let mut sorted_by_start: Vec<&Interval> = ranges.iter().collect::>(); sorted_by_start.sort_by_key(|i| i.start); sorted_by_start.windows(2).all(|w| w[0].is_disjoint(&w[1])) } pub fn is_disjoint(&self) -> bool { match self { Self::Position { .. } => true, Self::Range { .. } => true, Self::Ranges { ranges, .. } => Self::ranges_disjoint(ranges), Self::MultiRanges { multi_ranges } => { for (_, intervals) in multi_ranges { if !Self::ranges_disjoint(intervals) { return false; } } true } } } pub fn rank(&self) -> Rank { match self { Self::Position { .. } => Rank::Zero, Self::Range { .. } => Rank::One, Self::Ranges { .. } => Rank::Two, Self::MultiRanges { .. } => Rank::Three, } } pub fn promote(&self, to_rank: Rank) -> Result { use Rank::*; match (self, to_rank) { (Self::Position { .. }, Zero) => Ok(self.clone()), (Self::Range { .. }, One) => Ok(self.clone()), (Self::Ranges { .. }, Two) => Ok(self.clone()), (Self::MultiRanges { .. }, Three) => Ok(self.clone()), // Position (Self::Position { pos, buffer }, One) => Ok(Self::Range { interval: Interval { start: pos + 0, end: pos + 1, capture_groups: Vec::new(), }, buffer: *buffer, }), (Self::Position { pos, buffer }, Two) => Ok(Self::Ranges { ranges: vec![Interval { start: pos + 0, end: pos + 1, capture_groups: Vec::new(), }], buffer: *buffer, }), (Self::Position { pos, buffer }, Three) => { let mut map = HashMap::new(); map.insert( *buffer, vec![Interval { start: pos + 0, end: pos + 1, capture_groups: Vec::new(), }], ); Ok(Self::MultiRanges { multi_ranges: map }) } // Range promotions (Self::Range { interval, buffer }, Two) => Ok(Self::Ranges { ranges: vec![interval.clone()], buffer: *buffer, }), (Self::Range { interval, buffer }, Three) => { let mut map = HashMap::new(); map.insert(*buffer, vec![interval.clone()]); Ok(Self::MultiRanges { multi_ranges: map }) } // Ranges promotion (Self::Ranges { ranges, buffer }, Three) => { let mut map = HashMap::new(); map.insert(*buffer, ranges.clone()); Ok(Self::MultiRanges { multi_ranges: map }) } // all other cases (sel, target) => Err(SelectionError::InvalidPromotion { from: sel.rank(), to: target, }), } } pub fn buffers(&self) -> Vec { match self { Self::Position { buffer, .. } => vec![*buffer], Self::Range { buffer, .. } => vec![*buffer], Self::Ranges { buffer, .. } => vec![*buffer], Self::MultiRanges { multi_ranges } => multi_ranges.keys().copied().collect(), } } pub fn union(selections: Vec) -> Result { if selections.is_empty() { return Ok(Self::empty()); } let all_buffers: HashSet = selections.iter().flat_map(|s| s.buffers()).collect(); if all_buffers.is_empty() { return Ok(Self::empty()); } let max_rank = if all_buffers.len() > 1 { Rank::Three } else { selections .iter() .map(|s| s.rank()) .max() .unwrap_or(Rank::Two) .max(Rank::Two) // At least rank 2 }; let promoted: Result, SelectionError> = selections.iter().map(|s| s.promote(max_rank)).collect(); let promoted = promoted?; match max_rank { Rank::Two => { let mut all_intervals = Vec::new(); let buffer = *all_buffers.iter().next().unwrap(); for sel in &promoted { match sel { Self::Ranges { ranges, .. } => all_intervals.extend(ranges.clone()), _ => unreachable!("promote() to Rank::Two should always produce Ranges"), } } Ok(Self::Ranges { ranges: all_intervals, buffer, }) } Rank::Three => { let mut buffer_intervals: HashMap> = all_buffers.iter().map(|&b| (b, Vec::new())).collect(); for sel in &promoted { match sel { Self::MultiRanges { multi_ranges } => { for (&buffer, intervals) in multi_ranges { buffer_intervals .entry(buffer) .or_insert_with(Vec::new) .extend(intervals.clone()); } } _ => unreachable!( "promote() to Rank::Three should always produce MultiRanges" ), } } Ok(Self::MultiRanges { multi_ranges: buffer_intervals, }) } _ => unreachable!(), } } pub fn vectorise( fn_rank_zero: impl Fn(&S, &BufferID, usize) -> Result + 'static, fn_rank_one: impl Fn(&S, &BufferID, &Interval) -> Result + 'static, ) -> impl Fn(&S, &Selection) -> Result> where E: std::error::Error + 'static, { // look at this mess! use VectoriseError::{ProcessingError, SelectionError}; move |state: &S, selection: &Selection| { let do_rank_one = |b: &usize, rs: &Vec| { rs.iter() .map(|int| fn_rank_one(state, b, int).map_err(ProcessingError)) .collect::>() }; match selection { Self::Position { buffer, pos } => { fn_rank_zero(state, buffer, *pos).map_err(ProcessingError) } Self::Range { buffer, interval } => { fn_rank_one(state, buffer, interval).map_err(VectoriseError::ProcessingError) } Self::Ranges { buffer, ranges } => { let results = do_rank_one(buffer, ranges)?; Self::union(results).map_err(SelectionError) } Self::MultiRanges { multi_ranges } => { let all_ok: Vec> = multi_ranges .iter() .map(|(buffer, ranges)| do_rank_one(buffer, ranges)) .collect::>()?; // It would seem that Rust has no built in monadic flatten, or in general cannot lift things to operate on Result... :( let results: Vec = all_ok.into_iter().flatten().collect(); Self::union(results).map_err(SelectionError) } } } } }