diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 04d6216..a5812fc 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -2,7 +2,7 @@ resolver = "2" members = [ "reconcile", - "sync_server", + "sync_server", "sync_lib" ] @@ -14,9 +14,9 @@ license = "MIT" repository = "https://github.com/schmelczer/vault-link" version = "0.3.6" -[workspace.dependencies] +[workspace.dependencies] serde = { version = "1.0.219", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.66", default-features = false } +thiserror = { version = "1.0.66", default-features = false } [profile.release] codegen-units = 1 @@ -58,6 +58,7 @@ unnested_or_patterns = "warn" unused_self = "warn" verbose_file_reads = "warn" +large_stack_arrays = { level = "allow", priority = 1 } # https://github.com/rust-lang/rust-clippy/issues/13774 cast_possible_truncation = { level = "allow", priority = 1 } doc_link_with_quotes = { level = "allow", priority = 1 } cast_sign_loss = { level = "allow", priority = 1 } diff --git a/backend/reconcile/src/diffs/myers.rs b/backend/reconcile/src/diffs/myers.rs index b7a7c5e..c0be1d7 100644 --- a/backend/reconcile/src/diffs/myers.rs +++ b/backend/reconcile/src/diffs/myers.rs @@ -35,7 +35,7 @@ use crate::{ /// Diff `old`, between indices `old_range` and `new` between indices /// `new_range`. /// -/// The returned RawOperations all have a token count of 1. +/// The returned `RawOperations` all have a token count of 1. pub fn diff(old: &[Token], new: &[Token]) -> Vec> where T: PartialEq + Clone + std::fmt::Debug, @@ -245,7 +245,7 @@ fn conquer( old[old_range.start..old_range.start + common_prefix_len] .iter() .map(|token| RawOperation::Equal(vec![token.clone()])), - ) + ); } old_range.start += common_prefix_len; new_range.start += common_prefix_len; @@ -266,13 +266,13 @@ fn conquer( old[old_range.start..old_range.start + old_range.len()] .iter() .map(|token| RawOperation::Delete(vec![token.clone()])), - ) + ); } else if old_range.is_empty() { result.extend( new[new_range.start..new_range.start + new_range.len()] .iter() .map(|token| RawOperation::Insert(vec![token.clone()])), - ) + ); } else if let Some((x_start, y_start)) = find_middle_snake(old, old_range.clone(), new, new_range.clone(), vf, vb) { diff --git a/backend/reconcile/src/diffs/raw_operation.rs b/backend/reconcile/src/diffs/raw_operation.rs index f95a034..7630ff7 100644 --- a/backend/reconcile/src/diffs/raw_operation.rs +++ b/backend/reconcile/src/diffs/raw_operation.rs @@ -30,18 +30,18 @@ where pub fn is_left_joinable(&self) -> bool { let first_token = self.tokens().first(); - first_token.map_or(true, |t| t.get_is_left_joinable()) + first_token.is_none_or(super::super::tokenizer::token::Token::get_is_left_joinable) } pub fn is_right_joinable(&self) -> bool { let last_token = self.tokens().last(); - last_token.map_or(true, |t| t.get_is_right_joinable()) + last_token.is_none_or(super::super::tokenizer::token::Token::get_is_right_joinable) } - /// Extends the operation with another operation when it returns Some - /// operation. Only operations of the same type as self can be used to - /// extend self. If the operations are of different types, returns None. - pub fn extend(self, other: RawOperation) -> Option> { + /// Extends the operation with another operation. Only operations of the + /// same type as self can be used to extend self, otherwise the function + /// will panic. + pub fn extend(self, other: RawOperation) -> RawOperation { debug_assert!( std::mem::discriminant(&self) == std::mem::discriminant(&other), "Cannot extend operations of different types. This should have been handled before \ @@ -49,15 +49,15 @@ where ); match (self, other) { - (RawOperation::Insert(tokens1), RawOperation::Insert(tokens2)) => Some( - RawOperation::Insert(tokens1.into_iter().chain(tokens2).collect()), - ), - (RawOperation::Delete(tokens1), RawOperation::Delete(tokens2)) => Some( - RawOperation::Delete(tokens1.into_iter().chain(tokens2).collect()), - ), - (RawOperation::Equal(tokens1), RawOperation::Equal(tokens2)) => Some( - RawOperation::Equal(tokens1.into_iter().chain(tokens2).collect()), - ), + (RawOperation::Insert(tokens1), RawOperation::Insert(tokens2)) => { + RawOperation::Insert(tokens1.into_iter().chain(tokens2).collect()) + } + (RawOperation::Delete(tokens1), RawOperation::Delete(tokens2)) => { + RawOperation::Delete(tokens1.into_iter().chain(tokens2).collect()) + } + (RawOperation::Equal(tokens1), RawOperation::Equal(tokens2)) => { + RawOperation::Equal(tokens1.into_iter().chain(tokens2).collect()) + } _ => unreachable!("Only operations of the same type can be extended"), } } diff --git a/backend/reconcile/src/operation_transformation/cursor.rs b/backend/reconcile/src/operation_transformation/cursor.rs index a8e74da..c7fbaf5 100644 --- a/backend/reconcile/src/operation_transformation/cursor.rs +++ b/backend/reconcile/src/operation_transformation/cursor.rs @@ -3,9 +3,6 @@ use std::borrow::Cow; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use super::merge_context::MergeContext; -use crate::operation_transformation::Operation; - // CursorPosition represents the position of an identifiable cursor in a text // document based on its (UTF-8) character index. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -16,6 +13,7 @@ pub struct CursorPosition { } impl CursorPosition { + #[must_use] pub fn with_index(self, index: usize) -> Self { CursorPosition { id: self.id, diff --git a/backend/reconcile/src/operation_transformation/edited_text.rs b/backend/reconcile/src/operation_transformation/edited_text.rs index f195a9f..66cda8b 100644 --- a/backend/reconcile/src/operation_transformation/edited_text.rs +++ b/backend/reconcile/src/operation_transformation/edited_text.rs @@ -3,11 +3,11 @@ use core::iter; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use super::{ordered_operation::OrderedOperation, CursorPosition, Operation, TextWithCursors}; +use super::{CursorPosition, Operation, TextWithCursors, ordered_operation::OrderedOperation}; use crate::{ diffs::{myers::diff, raw_operation::RawOperation}, - operation_transformation::{merge_context::MergeContext, operation}, - tokenizer::{word_tokenizer::word_tokenizer, Tokenizer}, + operation_transformation::merge_context::MergeContext, + tokenizer::{Tokenizer, word_tokenizer::word_tokenizer}, utils::{merge_iters::MergeSorted as _, side::Side, string_builder::StringBuilder}, }; @@ -84,7 +84,7 @@ where .flat_map(|next| match next { RawOperation::Insert(..) => match maybe_previous_insert.take() { Some(prev) if prev.is_right_joinable() && next.is_left_joinable() => { - maybe_previous_insert = prev.extend(next); + maybe_previous_insert = Some(prev.extend(next)); Box::new(iter::empty()) as Box>> } prev => { @@ -94,7 +94,7 @@ where }, RawOperation::Delete(..) => match maybe_previous_delete.take() { Some(prev) if prev.is_right_joinable() && next.is_left_joinable() => { - maybe_previous_delete = prev.extend(next); + maybe_previous_delete = Some(prev.extend(next)); Box::new(iter::empty()) as Box>> } prev => { @@ -133,7 +133,7 @@ where let mut new_index = 0; // this is the start index of the operation on the new text let mut order = 0; // this is the start index of the operation on the original text - raw_operations.into_iter().flat_map(move |raw_operation| { + raw_operations.into_iter().filter_map(move |raw_operation| { let length = raw_operation.original_text_length(); match raw_operation { @@ -261,8 +261,8 @@ where &mut left_merge_context, ); - if let Some(ref op @ Operation::Insert { .. }) - | Some(ref op @ Operation::Equal { .. }) = result + if let Some(ref op @ (Operation::Insert { .. } | Operation::Equal { .. })) = + result { while let Some(mut cursor) = left_cursors.next_if(|cursor| cursor.char_index <= original_end + 1) @@ -284,8 +284,8 @@ where &mut right_merge_context, ); - if let Some(ref op @ Operation::Insert { .. }) - | Some(ref op @ Operation::Equal { .. }) = result + if let Some(ref op @ (Operation::Insert { .. } | Operation::Equal { .. })) = + result { while let Some(mut cursor) = right_cursors .next_if(|cursor| cursor.char_index <= original_end + 1) @@ -310,8 +310,7 @@ where let last_index = merged_operations .iter() .last() - .map(|op| op.operation.end_index()) - .unwrap_or(0); + .map_or(0, |op| op.operation.end_index()); for cursor in left_cursors.chain(right_cursors) { merged_cursors.push(cursor.with_index(last_index)); diff --git a/backend/reconcile/src/operation_transformation/operation.rs b/backend/reconcile/src/operation_transformation/operation.rs index 313d368..73ae058 100644 --- a/backend/reconcile/src/operation_transformation/operation.rs +++ b/backend/reconcile/src/operation_transformation/operation.rs @@ -251,6 +251,7 @@ where /// and updating the context. This implements a comples FSM that handles /// the merging of operations in a way that is consistent with the text. /// The contexts are updated in-place. + #[allow(clippy::too_many_lines)] pub fn merge_operations_with_context( self, affecting_context: &mut MergeContext, @@ -298,7 +299,7 @@ where ( operation @ Operation::Delete { .. }, - None | Some(Operation::Insert { .. }) | Some(Operation::Equal { .. }), + None | Some(Operation::Insert { .. } | Operation::Equal { .. }), ) => { produced_context.consume_and_replace_last_operation(Some(operation.clone())); Some(operation) diff --git a/backend/reconcile/src/tokenizer/word_tokenizer.rs b/backend/reconcile/src/tokenizer/word_tokenizer.rs index 8ebff6a..dd22b7e 100644 --- a/backend/reconcile/src/tokenizer/word_tokenizer.rs +++ b/backend/reconcile/src/tokenizer/word_tokenizer.rs @@ -10,7 +10,7 @@ pub fn word_tokenizer(text: &str) -> Vec> { let mut result: Vec> = Vec::new(); let mut previous_boundary_index = 0; - let mut previous_char_is_whitespace = text.chars().next().map_or(true, |c| c.is_whitespace()); + let mut previous_char_is_whitespace = text.chars().next().is_none_or(char::is_whitespace); for (i, c) in text.char_indices() { let is_current_char_whitespace = c.is_whitespace(); @@ -31,8 +31,8 @@ pub fn word_tokenizer(text: &str) -> Vec> { } for i in 0..result.len() - 1 { - if result[i].original().chars().all(|c| c.is_whitespace()) { - result[i].normalised = result[i].normalised().to_owned() + result[i + 1].original() + if result[i].original().chars().all(char::is_whitespace) { + result[i].normalised = result[i].normalised().to_owned() + result[i + 1].original(); } } diff --git a/backend/reconcile/tests/example_document.rs b/backend/reconcile/tests/example_document.rs index 3d866c1..66a56f6 100644 --- a/backend/reconcile/tests/example_document.rs +++ b/backend/reconcile/tests/example_document.rs @@ -66,11 +66,9 @@ impl ExampleDocument { result.insert( result .char_indices() - .skip(cursor.char_index + i) - .next() - .map(|(byte_index, _)| byte_index) - .unwrap_or_else(|| result.len()), /* find the utf8 char index of the insert - * in byte index */ + .nth(cursor.char_index + i) + .map_or_else(|| result.len(), |(byte_index, _)| byte_index), /* find the utf8 char index of the insert + * in byte index */ '|', ); } diff --git a/backend/reconcile/tests/test.rs b/backend/reconcile/tests/test.rs index 5a749f1..088a93e 100644 --- a/backend/reconcile/tests/test.rs +++ b/backend/reconcile/tests/test.rs @@ -8,46 +8,46 @@ use serde::Deserialize; #[test] fn test_document_one_way_without_cursors() { - get_all_documents().iter().for_each(|doc| { + for doc in &get_all_documents() { doc.assert_eq_without_cursors(&reconcile( &doc.parent(), &doc.left().text, &doc.right().text, - )) - }); + )); + } } #[test] fn test_document_one_way_with_cursors() { - get_all_documents().iter().for_each(|doc| { + for doc in &get_all_documents() { doc.assert_eq(&reconcile_with_cursors( &doc.parent(), doc.left(), doc.right(), - )) - }); + )); + } } #[test] fn test_document_inverse_way_without_cursors() { - get_all_documents().iter().for_each(|doc| { + for doc in &get_all_documents() { doc.assert_eq_without_cursors(&reconcile( &doc.parent(), &doc.right().text, &doc.left().text, )); - }); + } } #[test] fn test_document_inverse_way_with_cursors() { - get_all_documents().iter().for_each(|doc| { + for doc in &get_all_documents() { doc.assert_eq(&reconcile_with_cursors( &doc.parent(), doc.right(), doc.left(), - )) - }); + )); + } } fn get_all_documents() -> Vec {