Add diff applying error & improve CI #32

Merged
schmelczer merged 12 commits from asch/diff-error into main 2025-12-06 21:54:08 +00:00
4 changed files with 31 additions and 31 deletions
Showing only changes of commit f04972f1e1 - Show all commits

Rename NumberOrString

Andras Schmelczer 2025-12-06 11:55:01 +00:00

View file

@ -218,8 +218,8 @@ mod utils;
pub use operation_transformation::{DiffError, EditedText, reconcile}; pub use operation_transformation::{DiffError, EditedText, reconcile};
pub use tokenizer::{BuiltinTokenizer, Tokenizer, token::Token}; pub use tokenizer::{BuiltinTokenizer, Tokenizer, token::Token};
pub use types::{ pub use types::{
cursor_position::CursorPosition, history::History, number_or_string::NumberOrString, cursor_position::CursorPosition, history::History, number_or_text::NumberOrText, side::Side,
side::Side, span_with_history::SpanWithHistory, text_with_cursors::TextWithCursors, span_with_history::SpanWithHistory, text_with_cursors::TextWithCursors,
}; };
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]

View file

@ -12,7 +12,7 @@ use crate::{
raw_operation::RawOperation, raw_operation::RawOperation,
tokenizer::Tokenizer, tokenizer::Tokenizer,
types::{ types::{
history::History, number_or_string::NumberOrString, side::Side, history::History, number_or_text::NumberOrText, side::Side,
span_with_history::SpanWithHistory, span_with_history::SpanWithHistory,
}, },
utils::string_builder::StringBuilder, utils::string_builder::StringBuilder,
@ -366,8 +366,8 @@ where
/// ///
/// Panics if there's an integer overflow in i64. /// Panics if there's an integer overflow in i64.
#[must_use] #[must_use]
pub fn to_diff(&self) -> Vec<NumberOrString> { pub fn to_diff(&self) -> Vec<NumberOrText> {
let mut result: Vec<NumberOrString> = Vec::with_capacity(self.operations.len()); let mut result: Vec<NumberOrText> = Vec::with_capacity(self.operations.len());
let mut previous_equal: Option<usize> = None; let mut previous_equal: Option<usize> = None;
for operation in &self.operations { for operation in &self.operations {
@ -382,7 +382,7 @@ where
Operation::Insert { text, .. } => { Operation::Insert { text, .. } => {
if let Some(prev_length) = previous_equal { if let Some(prev_length) = previous_equal {
result.push(NumberOrString::Number( result.push(NumberOrText::Number(
i64::try_from(prev_length).expect("prev_length must fit in i64"), i64::try_from(prev_length).expect("prev_length must fit in i64"),
)); ));
previous_equal = None; previous_equal = None;
@ -392,7 +392,7 @@ where
.iter() .iter()
.map(super::super::tokenizer::token::Token::original) .map(super::super::tokenizer::token::Token::original)
.collect(); .collect();
result.push(NumberOrString::Text(text)); result.push(NumberOrText::Text(text));
} }
Operation::Delete { Operation::Delete {
@ -400,7 +400,7 @@ where
.. ..
} => { } => {
if let Some(prev_length) = previous_equal { if let Some(prev_length) = previous_equal {
result.push(NumberOrString::Number( result.push(NumberOrText::Number(
i64::try_from(prev_length).expect("prev_length must fit in i64"), i64::try_from(prev_length).expect("prev_length must fit in i64"),
)); ));
previous_equal = None; previous_equal = None;
@ -408,13 +408,13 @@ where
let count = i64::try_from(*deleted_character_count) let count = i64::try_from(*deleted_character_count)
.expect("deleted_character_count must fit in i64"); .expect("deleted_character_count must fit in i64");
result.push(NumberOrString::Number(-count)); result.push(NumberOrText::Number(-count));
} }
} }
} }
if let Some(prev_length) = previous_equal { if let Some(prev_length) = previous_equal {
result.push(NumberOrString::Number( result.push(NumberOrText::Number(
i64::try_from(prev_length).expect("prev_length must fit in i64"), i64::try_from(prev_length).expect("prev_length must fit in i64"),
)); ));
} }
@ -434,7 +434,7 @@ where
/// Panics if there's an integer overflow in i64. /// Panics if there's an integer overflow in i64.
pub fn from_diff( pub fn from_diff(
original_text: &'a str, original_text: &'a str,
diff: Vec<NumberOrString>, diff: Vec<NumberOrText>,
tokenizer: &Tokenizer<T>, tokenizer: &Tokenizer<T>,
) -> Result<EditedText<'a, T>, DiffError> { ) -> Result<EditedText<'a, T>, DiffError> {
let mut operations: Vec<Operation<T>> = Vec::with_capacity(diff.len()); let mut operations: Vec<Operation<T>> = Vec::with_capacity(diff.len());
@ -442,7 +442,7 @@ where
for item in diff { for item in diff {
match item { match item {
NumberOrString::Number(length) => { NumberOrText::Number(length) => {
if length >= 0 { if length >= 0 {
let length = usize::try_from(length).expect("length must fit in usize"); let length = usize::try_from(length).expect("length must fit in usize");
@ -483,7 +483,7 @@ where
order += length; order += length;
} }
} }
NumberOrString::Text(text) => { NumberOrText::Text(text) => {
let tokens = tokenizer(&text); let tokens = tokenizer(&text);
operations.push(Operation::create_insert(order, tokens)); operations.push(Operation::create_insert(order, tokens));
} }

View file

@ -1,6 +1,6 @@
pub mod cursor_position; pub mod cursor_position;
pub mod history; pub mod history;
pub mod number_or_string; pub mod number_or_text;
pub mod side; pub mod side;
pub mod span_with_history; pub mod span_with_history;
pub mod text_with_cursors; pub mod text_with_cursors;

View file

@ -12,18 +12,18 @@ const INTEGRAL_LIMIT: f64 = (1u64 << 53) as f64;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(untagged))] #[cfg_attr(feature = "serde", serde(untagged))]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum NumberOrString { pub enum NumberOrText {
Number(i64), Number(i64),
Text(String), Text(String),
} }
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
impl TryFrom<JsValue> for NumberOrString { impl TryFrom<JsValue> for NumberOrText {
type Error = DeserialisationError; type Error = DeserialisationError;
fn try_from(value: JsValue) -> Result<Self, Self::Error> { fn try_from(value: JsValue) -> Result<Self, Self::Error> {
if let Ok(num) = value.clone().try_into() { if let Ok(num) = value.clone().try_into() {
return Ok(NumberOrString::Number(num)); return Ok(NumberOrText::Number(num));
} }
if let Some(num) = value.clone().as_f64() { if let Some(num) = value.clone().as_f64() {
@ -34,11 +34,11 @@ impl TryFrom<JsValue> for NumberOrString {
} }
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
return Ok(NumberOrString::Number(num.round() as i64)); return Ok(NumberOrText::Number(num.round() as i64));
} }
if let Ok(text) = value.try_into() { if let Ok(text) = value.try_into() {
return Ok(NumberOrString::Text(text)); return Ok(NumberOrText::Text(text));
} }
Err(DeserialisationError::new( Err(DeserialisationError::new(
@ -48,29 +48,29 @@ impl TryFrom<JsValue> for NumberOrString {
} }
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
impl From<NumberOrString> for JsValue { impl From<NumberOrText> for JsValue {
fn from(value: NumberOrString) -> Self { fn from(value: NumberOrText) -> Self {
match value { match value {
NumberOrString::Number(num) => JsValue::from(num), NumberOrText::Number(num) => JsValue::from(num),
NumberOrString::Text(text) => JsValue::from(text), NumberOrText::Text(text) => JsValue::from(text),
} }
} }
} }
impl From<i64> for NumberOrString { impl From<i64> for NumberOrText {
fn from(value: i64) -> Self { NumberOrString::Number(value) } fn from(value: i64) -> Self { NumberOrText::Number(value) }
} }
impl From<String> for NumberOrString { impl From<String> for NumberOrText {
fn from(value: String) -> Self { NumberOrString::Text(value) } fn from(value: String) -> Self { NumberOrText::Text(value) }
} }
impl From<&str> for NumberOrString { impl From<&str> for NumberOrText {
fn from(value: &str) -> Self { NumberOrString::Text(value.to_owned()) } fn from(value: &str) -> Self { NumberOrText::Text(value.to_owned()) }
} }
impl<'a> From<Cow<'a, str>> for NumberOrString { impl<'a> From<Cow<'a, str>> for NumberOrText {
fn from(value: Cow<'a, str>) -> Self { NumberOrString::Text(value.into_owned()) } fn from(value: Cow<'a, str>) -> Self { NumberOrText::Text(value.into_owned()) }
} }
/// Error type for deserialisation failures /// Error type for deserialisation failures