From 9f3e21628231f3fa91ab8ff45872a76e7e11fcc4 Mon Sep 17 00:00:00 2001 From: tslil Date: Tue, 21 Oct 2025 20:36:01 +0100 Subject: Having a time with passing functions around, really feels like i'm fighting the language --- rprt-engine/Cargo.toml | 2 +- rprt-engine/src/lib.rs | 1 + rprt-engine/src/selection.rs | 98 ++++++++++++++++++++++------------- rprt-engine/src/selection_function.rs | 43 +++++++++++++++ rprt-engine/src/state.rs | 2 +- 5 files changed, 107 insertions(+), 39 deletions(-) create mode 100644 rprt-engine/src/selection_function.rs diff --git a/rprt-engine/Cargo.toml b/rprt-engine/Cargo.toml index 179c095..e0b5d3e 100644 --- a/rprt-engine/Cargo.toml +++ b/rprt-engine/Cargo.toml @@ -6,9 +6,9 @@ license.workspace = true authors.workspace = true [dependencies] -either = "1.15.0" logos = "0.15.1" regex = "1.12.2" +thiserror = "2.0.17" [[bin]] name = "explainer" diff --git a/rprt-engine/src/lib.rs b/rprt-engine/src/lib.rs index 0ae9d2d..3eda2e4 100644 --- a/rprt-engine/src/lib.rs +++ b/rprt-engine/src/lib.rs @@ -5,5 +5,6 @@ pub mod expression; pub mod monad; pub mod parser; pub mod selection; +pub mod selection_function; pub mod state; pub mod token; diff --git a/rprt-engine/src/selection.rs b/rprt-engine/src/selection.rs index 9e59ba5..c15512d 100644 --- a/rprt-engine/src/selection.rs +++ b/rprt-engine/src/selection.rs @@ -1,8 +1,8 @@ use crate::buffer::BufferID; -use either::Either; 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 { @@ -23,21 +23,12 @@ impl Display for Rank { } } -#[derive(Debug)] +#[derive(Error, Debug)] pub enum SelectionError { + #[error("Cannnot change selection of {from} to {to}")] InvalidPromotion { from: Rank, to: Rank }, } -impl std::fmt::Display for SelectionError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - SelectionError::InvalidPromotion { from, to } => { - write!(f, "Cannot change selection of {} to {}", from, to) - } - } - } -} - #[derive(Debug, Clone)] pub struct Interval { pub start: usize, @@ -70,6 +61,29 @@ pub enum Selection { }, } +// 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 { @@ -257,32 +271,42 @@ impl Selection { } } - pub fn vectorise( - &self, - fn_rank_zero: &impl Fn(&BufferID, &usize) -> Result, - fn_rank_one: &impl Fn(&BufferID, &Interval) -> Result, - ) -> Result> { - let do_rank_one = |b: &usize, rs: &Vec| { - rs.iter() - .map(|int| fn_rank_one(b, int).map_err(Either::Left)) - .collect::>() - }; + 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 self { - Self::Position { buffer, pos } => fn_rank_zero(buffer, pos).map_err(Either::Left), - Self::Range { buffer, interval } => fn_rank_one(buffer, interval).map_err(Either::Left), - Self::Ranges { buffer, ranges } => { - let results = do_rank_one(buffer, ranges)?; - Self::union(results).map_err(Either::Right) - } - 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(Either::Right) + 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) + } } } } diff --git a/rprt-engine/src/selection_function.rs b/rprt-engine/src/selection_function.rs new file mode 100644 index 0000000..6f05650 --- /dev/null +++ b/rprt-engine/src/selection_function.rs @@ -0,0 +1,43 @@ +use crate::buffer::BufferID; +use crate::selection::{Interval, Selection, VectoriseError}; +use crate::state::EditorState; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum SFError {} + +struct SFComponents { + niladic: Box Result>, + monadic_rank0: Box Result>, + monadic_rank1: Box Result>, + dyadic: Option Result>>, +} + +pub struct SelectionFunction { + niladic: Box Result>, + monadic: Box Result>, + dyadic: Option Result>>, +} + +impl From for SelectionFunction> { + fn from(sfc: SFComponents) -> Self { + let dyadic: Option _>> = + if let Some(func) = sfc.dyadic { + Some(Box::new( + move |editor_state: &EditorState, left: &Selection, right: &Selection| { + (func)(editor_state, left, right).map_err(VectoriseError::ProcessingError) + }, + )) + } else { + None + }; + + Self { + niladic: Box::new(move |editor_state: &EditorState| { + (sfc.niladic)(editor_state).map_err(VectoriseError::ProcessingError) + }), + monadic: Box::new(Selection::vectorise(sfc.monadic_rank0, sfc.monadic_rank1)), + dyadic: dyadic, + } + } +} diff --git a/rprt-engine/src/state.rs b/rprt-engine/src/state.rs index 9487d6d..bc6fbb6 100644 --- a/rprt-engine/src/state.rs +++ b/rprt-engine/src/state.rs @@ -21,7 +21,7 @@ pub enum StateChange { }, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum GroupedChangeError { OverlappingChanges { buffer: BufferID, -- cgit v1.2.3