use std::fmt;
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum Segmentation {
#[default]
Char,
#[cfg(feature = "grapheme")]
Grapheme,
}
pub struct Dmp {
pub diff_timeout: Option<f32>,
pub edit_cost: i32,
pub match_distance: i32,
pub patch_margin: i32,
pub match_maxbits: i32,
pub match_threshold: f32,
pub patch_delete_threshold: f32,
pub segmentation: Segmentation,
pub word_mode: bool,
}
pub struct Diff {
pub operation: i32,
pub text: String,
}
pub struct Patch {
pub diffs: Vec<Diff>,
pub start1: i32,
pub start2: i32,
pub length1: i32,
pub length2: i32,
}
impl Diff {
pub fn new(operation: i32, text: String) -> Diff {
Diff { operation, text }
}
}
impl PartialEq for Diff {
fn eq(&self, other: &Self) -> bool {
(self.operation == other.operation) & (self.text == other.text)
}
}
impl PartialEq for Patch {
fn eq(&self, other: &Self) -> bool {
(self.diffs == other.diffs)
& (self.start1 == other.start1)
& (self.start2 == other.start2)
& (self.length1 == other.length1)
& (self.length2 == other.length2)
}
}
impl Patch {
pub fn new(diffs: Vec<Diff>, start1: i32, start2: i32, length1: i32, length2: i32) -> Patch {
Patch {
diffs,
start1,
start2,
length1,
length2,
}
}
}
pub(crate) fn min(x: i32, y: i32) -> i32 {
if x > y {
return y;
}
x
}
pub(crate) fn min1(x: f32, y: f32) -> f32 {
if x > y {
return y;
}
x
}
pub(crate) fn max(x: i32, y: i32) -> i32 {
if x > y {
return x;
}
y
}
pub(crate) fn find_char(cha: char, text: &[char], start: usize) -> i32 {
match crate::engine::skip_to(text, start, &cha) {
Some(i) => i as i32,
None => -1,
}
}
pub(crate) trait DiffToken: Copy + Eq {
const NEWLINE: Self;
fn to_tokens(tokens: &[Self]) -> Vec<char>;
fn append_to_arena(tokens: &[Self], arena: &mut String);
fn is_word_sep(self) -> bool;
}
impl DiffToken for char {
const NEWLINE: Self = '\n';
fn to_tokens(tokens: &[char]) -> Vec<char> {
tokens.to_vec()
}
fn append_to_arena(tokens: &[char], arena: &mut String) {
arena.extend(tokens.iter());
}
fn is_word_sep(self) -> bool {
self.is_whitespace()
}
}
impl DiffToken for u8 {
const NEWLINE: Self = b'\n';
fn to_tokens(tokens: &[u8]) -> Vec<char> {
tokens.iter().map(|&b| b as char).collect()
}
fn append_to_arena(tokens: &[u8], arena: &mut String) {
arena.push_str(std::str::from_utf8(tokens).expect("ascii fast path"));
}
fn is_word_sep(self) -> bool {
matches!(self, b'\t' | b'\n' | 0x0B | 0x0C | b'\r' | b' ')
}
}
pub(crate) struct TDiff {
pub operation: i32,
pub data: Vec<char>,
}
impl TDiff {
pub(crate) fn new(operation: i32, data: Vec<char>) -> TDiff {
TDiff { operation, data }
}
pub(crate) fn into_diff(self) -> Diff {
Diff::new(self.operation, self.data.iter().collect())
}
}
impl fmt::Debug for Diff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\n {{ {}: {} }}", self.operation, self.text)
}
}
impl fmt::Debug for Patch {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{{diffs:\n {:?},\n start1: {},\n start2: {},\n length1: {},\n length2: {} }}",
self.diffs, self.start1, self.start2, self.length1, self.length2
)
}
}
impl Clone for Diff {
fn clone(&self) -> Self {
Diff {
operation: self.operation,
text: self.text.clone(),
}
}
}
impl Clone for Patch {
fn clone(&self) -> Self {
Patch {
diffs: self.diffs.clone(),
start1: self.start1,
start2: self.start2,
length1: self.length1,
length2: self.length2,
}
}
}
impl Default for Dmp {
fn default() -> Self {
Self::new()
}
}
impl Dmp {
pub fn new() -> Self {
Dmp {
diff_timeout: None,
patch_delete_threshold: 0.5,
edit_cost: 0,
match_distance: 1000,
patch_margin: 4,
match_maxbits: 32,
match_threshold: 0.5,
segmentation: Segmentation::default(),
word_mode: false,
}
}
}