loro-internal 0.4.0

Loro internal library. Do not use it directly as it's not stable.
Documentation
use std::{fmt::Debug, time::Instant};

pub mod recursive_refactored;
pub mod richtext;
pub mod tree;

use crate::{
    array_mut_ref,
    delta::{Delta, DeltaItem, StyleMeta},
    event::Diff,
    handler::HandlerTrait,
    loro::LoroDoc,
    state::ContainerState,
    utils::string_slice::StringSlice,
};
use enum_as_inner::EnumAsInner;
use loro_common::ContainerID;
use std::sync::{Arc, Mutex};
use tabled::Tabled;

const STYLES_NAME: [&str; 4] = ["bold", "comment", "link", "highlight"];
#[derive(arbitrary::Arbitrary, EnumAsInner, Clone, PartialEq, Eq, Debug)]
pub enum Action {
    Ins {
        content: u16,
        pos: usize,
        site: u8,
    },
    Del {
        pos: usize,
        len: usize,
        site: u8,
    },
    Mark {
        pos: usize,
        len: usize,
        site: u8,
        style_key: u8,
    },
    Sync {
        from: u8,
        to: u8,
    },
    SyncAll,
}

impl Tabled for Action {
    const LENGTH: usize = 5;

    fn fields(&self) -> Vec<std::borrow::Cow<'_, str>> {
        match self {
            Action::Ins { content, pos, site } => vec![
                "ins".into(),
                site.to_string().into(),
                pos.to_string().into(),
                content.to_string().len().to_string().into(),
                content.to_string().into(),
            ],
            Action::Del { pos, len, site } => vec![
                "del".into(),
                site.to_string().into(),
                pos.to_string().into(),
                len.to_string().into(),
                "".into(),
            ],
            Action::Sync { from, to } => vec![
                "sync".into(),
                format!("{} to {}", from, to).into(),
                "".into(),
                "".into(),
                "".into(),
            ],
            Action::SyncAll => vec![
                "sync all".into(),
                "".into(),
                "".into(),
                "".into(),
                "".into(),
            ],
            Action::Mark {
                pos,
                len,
                site,
                style_key,
            } => vec![
                "mark".into(),
                site.to_string().into(),
                pos.to_string().into(),
                len.to_string().into(),
                format!("style {}", style_key).into(),
            ],
        }
    }

    fn headers() -> Vec<std::borrow::Cow<'static, str>> {
        vec![
            "type".into(),
            "site".into(),
            "pos".into(),
            "len".into(),
            "content".into(),
        ]
    }
}

trait Actionable {
    fn apply_action(&mut self, action: &Action);
    fn preprocess(&mut self, action: &mut Action);
}

impl Action {
    pub fn preprocess(&mut self, max_len: usize, max_users: u8) {
        match self {
            Action::Ins { pos, site, .. } => {
                *pos %= max_len + 1;
                *site %= max_users;
            }
            Action::Del { pos, len, site } => {
                if max_len == 0 {
                    *pos = 0;
                    *len = 0;
                } else {
                    *pos %= max_len;
                    *len = (*len).min(max_len - (*pos));
                }
                *site %= max_users;
            }
            Action::Sync { from, to } => {
                *from %= max_users;
                *to %= max_users;
            }
            Action::SyncAll => {}
            Action::Mark {
                pos,
                len,
                site,
                style_key,
            } => {
                if max_len == 0 {
                    *pos = 0;
                    *len = 0;
                } else {
                    *pos %= max_len;
                    *len = (*len).min(max_len - (*pos));
                }

                *site %= max_users;
                *style_key %= 8;
            }
        }
    }
}

impl Actionable for String {
    fn apply_action(&mut self, action: &Action) {
        match action {
            Action::Ins { content, pos, .. } => {
                self.insert_str(*pos, &content.to_string());
            }
            &Action::Del { pos, len, .. } => {
                if self.is_empty() {
                    return;
                }

                self.drain(pos..pos + len);
            }
            _ => {}
        }
    }

    fn preprocess(&mut self, action: &mut Action) {
        action.preprocess(self.len(), 1);
        match action {
            Action::Ins { pos, .. } => {
                while !self.is_char_boundary(*pos) {
                    *pos = (*pos + 1) % (self.len() + 1)
                }
            }
            Action::Del { pos, len, .. } => {
                if self.is_empty() {
                    *len = 0;
                    *pos = 0;
                    return;
                }

                while !self.is_char_boundary(*pos) {
                    *pos = (*pos + 1) % self.len();
                }

                *len = (*len).min(self.len() - (*pos));
                while !self.is_char_boundary(*pos + *len) {
                    *len += 1;
                }
            }
            _ => {}
        }
    }
}

impl Actionable for Vec<LoroDoc> {
    fn apply_action(&mut self, action: &Action) {
        match action {
            Action::Ins { content, pos, site } => {
                let site = &mut self[*site as usize];
                let mut txn = site.txn().unwrap();
                let text = txn.get_text("text");
                text.insert_with_txn(&mut txn, *pos, &format!("[{}]", content))
                    .unwrap();
            }
            Action::Del { pos, len, site } => {
                let site = &mut self[*site as usize];
                let mut txn = site.txn().unwrap();
                let text = txn.get_text("text");
                text.delete_with_txn(&mut txn, *pos, *len).unwrap();
            }
            Action::Sync { from, to } => {
                if from != to {
                    let (from, to) = arref::array_mut_ref!(self, [*from as usize, *to as usize]);
                    let to_vv = to.oplog_vv();
                    to.import(&from.export_from(&to_vv)).unwrap();
                }
            }
            Action::SyncAll => {
                for i in 1..self.len() {
                    let (a, b) = array_mut_ref!(self, [0, i]);
                    a.import(&b.export_from(&a.oplog_vv())).unwrap();
                }
                for i in 1..self.len() {
                    let (a, b) = array_mut_ref!(self, [0, i]);
                    b.import(&a.export_from(&b.oplog_vv())).unwrap();
                }
            }
            Action::Mark {
                pos,
                len,
                site,
                style_key,
            } => {
                if *len == 0 {
                    return;
                }

                let site = &mut self[*site as usize];
                let mut txn = site.txn().unwrap();
                let text = txn.get_text("text");
                text.mark_with_txn(
                    &mut txn,
                    *pos,
                    *pos + *len,
                    STYLES_NAME[*style_key as usize % STYLES_NAME.len()],
                    (*pos as i32).into(),
                    false,
                )
                .unwrap();
            }
        }
    }

    fn preprocess(&mut self, action: &mut Action) {
        match action {
            Action::Ins { pos, site, .. } => {
                *site %= self.len() as u8;
                *pos %= self[*site as usize]
                    .app_state()
                    .lock()
                    .unwrap()
                    .get_text("text")
                    .unwrap()
                    .len_unicode()
                    + 1;
            }
            Action::Del { pos, len, site } => {
                *site %= self.len() as u8;
                let app_state = &mut self[*site as usize].app_state().lock().unwrap();
                let text = app_state.get_text("text").unwrap();
                if text.len_unicode() == 0 {
                    *len = 0;
                    *pos = 0;
                } else {
                    *pos %= text.len_unicode();
                    *len = (*len).min(text.len_unicode() - (*pos));
                }
            }
            Action::Sync { from, to } => {
                *from %= self.len() as u8;
                *to %= self.len() as u8;
            }
            Action::SyncAll => {}
            Action::Mark {
                pos,
                len,
                site,
                style_key,
            } => {
                *site %= self.len() as u8;
                let app_state = &mut self[*site as usize].app_state().lock().unwrap();
                let text = app_state.get_text("text").unwrap();
                if text.len_unicode() == 0 {
                    *len = 0;
                    *pos = 0;
                } else {
                    *pos %= text.len_unicode();
                    *len = (*len).min(text.len_unicode() - (*pos));
                }

                *style_key %= 8;
            }
        }
    }
}

pub fn change_delete_to_char_boundary(pos: &mut usize, len: &mut usize, str_len: usize) {
    *pos %= str_len + 1;
    *len = (*len).min(str_len - (*pos));
}

pub fn change_pos_to_char_boundary(pos: &mut usize, len: usize) {
    *pos %= len + 1;
}

fn check_synced(sites: &mut [LoroDoc], _: &[Arc<Mutex<Delta<StringSlice, StyleMeta>>>]) {
    for i in 0..sites.len() - 1 {
        for j in i + 1..sites.len() {
            let s = tracing::span!(tracing::Level::INFO, "checking {} with {}", i, j);
            let _e = s.enter();
            let (a, b) = array_mut_ref!(sites, [i, j]);
            {
                if (i + j) % 2 == 1 {
                    let s =
                        tracing::span!(tracing::Level::INFO, "Import {}'s Snapshot to {}", j, i);
                    let _e = s.enter();
                    a.import(&b.export_snapshot()).unwrap();
                } else {
                    let s = tracing::span!(tracing::Level::INFO, "Import {} to {}", j, i);
                    let _e = s.enter();
                    a.import(&b.export_from(&a.oplog_vv())).unwrap();
                }
            }
            {
                let s = tracing::span!(tracing::Level::INFO, "Import {} to {}", i, j);
                let _e = s.enter();
                b.import(&a.export_from(&b.oplog_vv())).unwrap();
            }
            check_eq(a, b);

            // for (x, (site, text)) in sites.iter().zip(texts.iter()).enumerate() {
            //     if x != i && x != j {
            //         continue;
            //     }

            //     tracing::span!(tracing::Level::INFO, "Check {}", x);
            //     let diff = site.get_text("text").with_state_mut(|s| s.to_diff());
            //     let mut diff = diff.into_text().unwrap();
            //     compact(&mut diff);
            //     let mut text = text.lock().unwrap();
            //     compact(&mut text);
            //     assert_eq!(
            //         &diff, &*text,
            //         "site:{}\nEXPECTED {:#?}\nACTUAL {:#?}",
            //         x, diff, text
            //     );
            //
            // }
        }
    }
}

fn check_eq(site_a: &mut LoroDoc, site_b: &mut LoroDoc) {
    let a = site_a.txn().unwrap();
    let text_a = a.get_text("text");
    let b = site_b.txn().unwrap();
    let text_b = b.get_text("text");
    let value_a = text_a.get_richtext_value();
    let value_b = text_b.get_richtext_value();
    if value_a != value_b {
        {
            // compare plain text value
            let value_a = text_a.get_value();
            let value_b = text_b.get_value();
            assert_eq!(
                value_a,
                value_b,
                "Plain Text not equal. peer{}={:?}, peer{}={:?}",
                site_a.peer_id(),
                value_a,
                site_b.peer_id(),
                value_b
            );
        }

        assert_eq!(
            value_a,
            value_b,
            "Richtext Style not equal. peer{}={:?}, peer{}={:?}, \n",
            site_a.peer_id(),
            value_a,
            site_b.peer_id(),
            value_b
        );
    }
}

pub fn minify_error<T, F, N>(site_num: u8, actions: Vec<T>, f: F, normalize: N)
where
    F: Fn(u8, &mut [T]),
    N: Fn(u8, &mut [T]) -> Vec<T>,
    T: Clone + Debug,
{
    std::panic::set_hook(Box::new(|_info| {
        // ignore panic output
        // println!("{:?}", _info);
    }));

    let f_ref: *const _ = &f;
    let f_ref: usize = f_ref as usize;
    #[allow(clippy::redundant_clone)]
    let mut actions_clone = actions.clone();
    let action_ref: usize = (&mut actions_clone) as *mut _ as usize;
    #[allow(clippy::blocks_in_conditions)]
    if std::panic::catch_unwind(|| {
        // SAFETY: test
        let f = unsafe { &*(f_ref as *const F) };
        // SAFETY: test
        let actions_ref = unsafe { &mut *(action_ref as *mut Vec<T>) };
        f(site_num, actions_ref);
    })
    .is_ok()
    {
        println!("No Error Found");
        return;
    }

    let mut minified = actions.clone();
    let mut candidates = Vec::new();
    for i in 0..actions.len() {
        let mut new = actions.clone();
        new.remove(i);
        candidates.push(new);
    }

    println!("Minifying...");
    let start = Instant::now();
    while let Some(candidate) = candidates.pop() {
        let f_ref: *const _ = &f;
        let f_ref: usize = f_ref as usize;
        let mut actions_clone = candidate.clone();
        let action_ref: usize = (&mut actions_clone) as *mut _ as usize;
        #[allow(clippy::blocks_in_conditions)]
        if std::panic::catch_unwind(|| {
            // SAFETY: test
            let f = unsafe { &*(f_ref as *const F) };
            // SAFETY: test
            let actions_ref = unsafe { &mut *(action_ref as *mut Vec<T>) };
            f(site_num, actions_ref);
        })
        .is_err()
        {
            for i in 0..candidate.len() {
                let mut new = candidate.clone();
                new.remove(i);
                candidates.push(new);
            }
            if candidate.len() < minified.len() {
                minified = candidate;
                println!("New min len={}", minified.len());
            }
            if candidates.len() > 40 {
                candidates.drain(0..30);
            }
        }
        if start.elapsed().as_secs() > 10 && minified.len() <= 4 {
            break;
        }
        if start.elapsed().as_secs() > 60 {
            break;
        }
    }

    let minified = normalize(site_num, &mut minified);
    println!(
        "Old Length {}, New Length {}",
        actions.len(),
        minified.len()
    );
    dbg!(&minified);
    if actions.len() > minified.len() {
        minify_error(site_num, minified, f, normalize);
    }
}

pub fn test_multi_sites(site_num: u8, actions: &mut [Action]) {
    let mut sites = Vec::new();
    let mut texts = Vec::new();
    for i in 0..site_num {
        let loro = LoroDoc::new();
        let text: Arc<Mutex<Delta<StringSlice, StyleMeta>>> = Arc::new(Mutex::new(Delta::new()));
        let text_clone = text.clone();
        loro.set_peer_id(i as u64).unwrap();
        loro.subscribe(
            &ContainerID::new_root("text", loro_common::ContainerType::Text),
            Arc::new(move |event| {
                for container_diff in event.events {
                    if let Diff::Text(t) = &container_diff.diff {
                        let mut text = text_clone.lock().unwrap();
                        tracing::info!("RECEIVE site:{} event:{:#?}\nCURRENT: {:#?}", i, t, &text);
                        *text = text.clone().compose(t.clone());
                        tracing::info!("new:{:#?}", &text);
                    }
                }
            }),
        );
        texts.push(text);
        sites.push(loro);
    }

    let mut applied = Vec::new();
    for action in actions.iter_mut() {
        sites.preprocess(action);
        applied.push(action.clone());
        tracing::span!(tracing::Level::INFO, "ApplyAction", ?action);
        sites.apply_action(action);

        // for (i, (site, text)) in sites.iter().zip(texts.iter()).enumerate() {
        //     tracing::span!(tracing::Level::INFO, "Check {}", i);
        //     let diff = site.get_text("text").with_state_mut(|s| s.to_diff());
        //     let mut diff = diff.into_text().unwrap();
        //     compact(&mut diff);
        //     let mut text = text.lock().unwrap();
        //     compact(&mut text);
        //     assert_eq!(
        //         &diff, &*text,
        //         "site:{}\nEXPECTED{:#?}\nACTUAL{:#?}",
        //         i, diff, text
        //     );
        //
        // }
    }

    let s = tracing::span!(tracing::Level::INFO, "CheckSynced");
    let _e = s.enter();
    // println!("{}", actions.table());
    check_synced(&mut sites, &texts);

    let s = tracing::span!(tracing::Level::INFO, "CheckTextEvent");
    let _e = s.enter();
    for (i, (site, text)) in sites.iter().zip(texts.iter()).enumerate() {
        let s = tracing::span!(tracing::Level::INFO, "Check {}", i);
        let _e = s.enter();
        let diff = site
            .get_text("text")
            .with_state(|s| Ok(s.to_diff(site.arena(), &site.get_global_txn(), &site.weak_state())))
            .unwrap();
        let mut diff = diff.into_text().unwrap();
        compact(&mut diff);
        let mut text = text.lock().unwrap();
        compact(&mut text);
        assert_eq!(
            &diff, &*text,
            "site:{}\nEXPECTED{:#?}\nACTUAL{:#?}",
            i, diff, text
        );
    }
}

pub fn compact(delta: &mut Delta<StringSlice, StyleMeta>) {
    let mut ops: Vec<DeltaItem<StringSlice, StyleMeta>> = vec![];
    for op in delta.vec.drain(..) {
        match (ops.last_mut(), op) {
            (
                Some(DeltaItem::Retain {
                    retain: last_retain,
                    attributes: last_attr,
                }),
                DeltaItem::Retain { retain, attributes },
            ) if &attributes == last_attr => {
                *last_retain += retain;
            }
            (
                Some(DeltaItem::Insert {
                    insert: last_insert,
                    attributes: last_attr,
                }),
                DeltaItem::Insert { insert, attributes },
            ) if last_attr == &attributes => {
                last_insert.extend(insert.as_str());
            }
            (
                Some(DeltaItem::Delete {
                    delete: last_delete,
                    attributes: _,
                }),
                DeltaItem::Delete {
                    delete,
                    attributes: _,
                },
            ) => {
                *last_delete += delete;
            }
            (_, a) => {
                ops.push(a);
            }
        }
    }

    delta.vec = ops;
}

#[cfg(test)]
mod test {
    use super::Action::*;
    use super::*;

    #[test]
    fn fuzz_r1() {
        test_multi_sites(
            8,
            &mut [
                Ins {
                    content: 3871,
                    pos: 20971570,
                    site: 0,
                },
                Sync { from: 0, to: 31 },
                Ins {
                    content: 0,
                    pos: 0,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 58502001197056,
                    site: 0,
                },
                Ins {
                    content: 13599,
                    pos: 36261893487333151,
                    site: 31,
                },
            ],
        )
    }

    #[test]
    fn fuzz_r() {
        test_multi_sites(
            8,
            &mut [
                Ins {
                    content: 5225,
                    pos: 0,
                    site: 4,
                },
                Ins {
                    content: 53,
                    pos: 4,
                    site: 4,
                },
                Ins {
                    content: 10284,
                    pos: 0,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 6,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 6,
                    site: 2,
                },
                Ins {
                    content: 8234,
                    pos: 0,
                    site: 6,
                },
                Ins {
                    content: 7710,
                    pos: 1,
                    site: 6,
                },
                Ins {
                    content: 0,
                    pos: 7,
                    site: 2,
                },
                Ins {
                    content: 127,
                    pos: 0,
                    site: 7,
                },
                Ins {
                    content: 2560,
                    pos: 0,
                    site: 0,
                },
                Ins {
                    content: 10794,
                    pos: 4,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 1,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 30,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 29,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 4,
                    site: 6,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 2,
                },
                Ins {
                    content: 4626,
                    pos: 6,
                    site: 2,
                },
                Ins {
                    content: 4626,
                    pos: 2,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 6,
                    site: 2,
                },
                Ins {
                    content: 54826,
                    pos: 0,
                    site: 0,
                },
                Ins {
                    content: 12800,
                    pos: 9,
                    site: 6,
                },
                Ins {
                    content: 3598,
                    pos: 0,
                    site: 4,
                },
                Ins {
                    content: 11308,
                    pos: 2,
                    site: 4,
                },
                Ins {
                    content: 10284,
                    pos: 3,
                    site: 4,
                },
                Ins {
                    content: 11308,
                    pos: 10,
                    site: 4,
                },
                Ins {
                    content: 11308,
                    pos: 24,
                    site: 4,
                },
                Ins {
                    content: 11308,
                    pos: 28,
                    site: 4,
                },
                Ins {
                    content: 11312,
                    pos: 16,
                    site: 4,
                },
                Ins {
                    content: 11308,
                    pos: 5,
                    site: 4,
                },
                Ins {
                    content: 15420,
                    pos: 9,
                    site: 2,
                },
                Ins {
                    content: 12800,
                    pos: 0,
                    site: 5,
                },
                Ins {
                    content: 10794,
                    pos: 6,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 21,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 34,
                    site: 2,
                },
                Ins {
                    content: 12850,
                    pos: 10,
                    site: 2,
                },
                Ins {
                    content: 12850,
                    pos: 0,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 21,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 6,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 56,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 2,
                    site: 6,
                },
                Ins {
                    content: 7710,
                    pos: 2,
                    site: 6,
                },
                Ins {
                    content: 10794,
                    pos: 27,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 70,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 69,
                    site: 2,
                },
                SyncAll,
                Ins {
                    content: 0,
                    pos: 184,
                    site: 0,
                },
                Del {
                    pos: 18,
                    len: 191,
                    site: 0,
                },
                Del {
                    pos: 4,
                    len: 204,
                    site: 4,
                },
                Del {
                    pos: 90,
                    len: 118,
                    site: 5,
                },
            ],
        );
    }

    #[test]
    fn new_encode() {
        test_multi_sites(
            8,
            &mut [
                Ins {
                    content: 3871,
                    pos: 2755657778,
                    site: 0,
                },
                Sync { from: 0, to: 31 },
                Ins {
                    content: 3840,
                    pos: 55040529478965,
                    site: 212,
                },
                Ins {
                    content: 0,
                    pos: 17381979229574397952,
                    site: 15,
                },
                Ins {
                    content: 12815,
                    pos: 2248762090699358208,
                    site: 15,
                },
                Sync { from: 0, to: 212 },
                Ins {
                    content: 25896,
                    pos: 14090375187464448,
                    site: 64,
                },
                Ins {
                    content: 0,
                    pos: 6067790159959556096,
                    site: 212,
                },
            ],
        )
    }

    #[test]
    fn snapshot() {
        test_multi_sites(
            8,
            &mut [
                Ins {
                    content: 32818,
                    pos: 0,
                    site: 1,
                },
                Ins {
                    content: 12850,
                    pos: 0,
                    site: 3,
                },
                Ins {
                    content: 13621,
                    pos: 3,
                    site: 1,
                },
            ],
        )
    }

    #[test]
    fn snapshot_2() {
        test_multi_sites(
            8,
            &mut [
                Ins {
                    content: 12850,
                    pos: 0,
                    site: 0,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 1,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 10,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 4,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 28,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 30,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 29,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 36,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 30,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 42,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 24,
                    site: 2,
                },
                Ins {
                    content: 10833,
                    pos: 36,
                    site: 2,
                },
                Ins {
                    content: 1,
                    pos: 5,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 42,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 66,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 70,
                    site: 2,
                },
                Ins {
                    content: 24106,
                    pos: 0,
                    site: 6,
                },
                Ins {
                    content: 64001,
                    pos: 47,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 5,
                },
                Ins {
                    content: 10794,
                    pos: 62,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 13,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 30,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 7,
                },
                Ins {
                    content: 10794,
                    pos: 88,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 42,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 30,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 24,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 32,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 18,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 21,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 0,
                    site: 6,
                },
                Ins {
                    content: 10794,
                    pos: 115,
                    site: 2,
                },
                Ins {
                    content: 42,
                    pos: 14,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 50,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 76,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 132,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 5,
                    site: 6,
                },
                Del {
                    pos: 106,
                    len: 57,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 58,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 106,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 9,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 24,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 21,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 98,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 21,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 26,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 63,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 122,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 28,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 138,
                    site: 2,
                },
                Ins {
                    content: 10833,
                    pos: 19,
                    site: 2,
                },
                Ins {
                    content: 1,
                    pos: 36,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 129,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 96,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 24,
                    site: 2,
                },
                Ins {
                    content: 10794,
                    pos: 14,
                    site: 6,
                },
                Del {
                    pos: 10,
                    len: 177,
                    site: 2,
                },
                Ins {
                    content: 5,
                    pos: 9,
                    site: 2,
                },
                SyncAll,
                Ins {
                    content: 10794,
                    pos: 32,
                    site: 0,
                },
                Ins {
                    content: 10794,
                    pos: 30,
                    site: 0,
                },
            ],
        )
    }

    #[test]
    fn checkout() {
        test_multi_sites(
            4,
            &mut [
                Ins {
                    content: 53,
                    pos: 4,
                    site: 2,
                },
                SyncAll,
                Ins {
                    content: 0,
                    pos: 1,
                    site: 0,
                },
                Del {
                    pos: 4,
                    len: 1,
                    site: 2,
                },
            ],
        )
    }

    #[test]
    fn snapshot_fuzz_test() {
        test_multi_sites(
            8,
            &mut [
                Ins {
                    content: 163,
                    pos: 0,
                    site: 3,
                },
                Ins {
                    content: 163,
                    pos: 1,
                    site: 3,
                },
                Ins {
                    content: 113,
                    pos: 2,
                    site: 3,
                },
                Ins {
                    content: 888,
                    pos: 3,
                    site: 3,
                },
            ],
        )
    }

    #[test]
    fn text_fuzz_2() {
        test_multi_sites(
            8,
            &mut [
                Ins {
                    content: 111,
                    pos: 0,
                    site: 1,
                },
                Ins {
                    content: 222,
                    pos: 0,
                    site: 0,
                },
                Del {
                    pos: 3,
                    len: 2,
                    site: 0,
                },
                Ins {
                    content: 332,
                    pos: 4268070197446523707,
                    site: 3,
                },
                Ins {
                    content: 163,
                    pos: 4268070197446523707,
                    site: 3,
                },
                Ins {
                    content: 163,
                    pos: 4268070197446523707,
                    site: 3,
                },
                Ins {
                    content: 163,
                    pos: 4268070197446523707,
                    site: 3,
                },
                Ins {
                    content: 163,
                    pos: 4268070197446523707,
                    site: 3,
                },
                Ins {
                    content: 113,
                    pos: 4268070197446523707,
                    site: 3,
                },
                Ins {
                    content: 888,
                    pos: 4268070197446523707,
                    site: 3,
                },
                Ins {
                    content: 999,
                    pos: 3,
                    site: 0,
                },
            ],
        )
    }

    #[test]
    fn text_fuzz_3() {
        test_multi_sites(
            2,
            &mut [
                Ins {
                    content: 12850,
                    pos: 3617008641906848306,
                    site: 10,
                },
                SyncAll,
                Ins {
                    content: 12850,
                    pos: 4048798961467195395,
                    site: 255,
                },
                SyncAll,
                Ins {
                    content: 12850,
                    pos: 3280475,
                    site: 0,
                },
                Ins {
                    content: 12851,
                    pos: 89064736817458,
                    site: 0,
                },
                Ins {
                    content: 13077,
                    pos: 4557431322972336690,
                    site: 63,
                },
                Ins {
                    content: 16191,
                    pos: 4557430888798830399,
                    site: 63,
                },
                Ins {
                    content: 16191,
                    pos: 4557430888798830399,
                    site: 63,
                },
                Ins {
                    content: 16191,
                    pos: 4557430888798830399,
                    site: 63,
                },
                Ins {
                    content: 16191,
                    pos: 4557430888798830399,
                    site: 63,
                },
                Ins {
                    content: 16191,
                    pos: 4557430888798830399,
                    site: 63,
                },
                Ins {
                    content: 16191,
                    pos: 4557430888798830399,
                    site: 63,
                },
                Ins {
                    content: 42148,
                    pos: 171061810,
                    site: 12,
                },
                Ins {
                    content: 3675,
                    pos: 336666162111538,
                    site: 0,
                },
                Sync { from: 164, to: 164 },
                Ins {
                    content: 4112,
                    pos: 1157442765409226768,
                    site: 16,
                },
                Ins {
                    content: 4112,
                    pos: 3732657327335018512,
                    site: 45,
                },
                Ins {
                    content: 52530,
                    pos: 3906253595950239181,
                    site: 15,
                },
                Ins {
                    content: 5911,
                    pos: 18446743885640439575,
                    site: 255,
                },
                Ins {
                    content: 11822,
                    pos: 3327609269301292590,
                    site: 46,
                },
                SyncAll,
                Ins {
                    content: 1568,
                    pos: 13836783189022944192,
                    site: 43,
                },
                SyncAll,
                Del {
                    pos: 16789419410837209344,
                    len: 14774117067329253930,
                    site: 0,
                },
                Ins {
                    content: 27242,
                    pos: 7668058320836127338,
                    site: 106,
                },
                Del {
                    pos: 7639230867934177898,
                    len: 7668058320836127338,
                    site: 106,
                },
            ],
        )
    }

    #[test]
    fn text_fuzz_4() {
        test_multi_sites(
            2,
            &mut [
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3607136139932740138,
                    site: 0,
                },
                Ins {
                    content: 13071,
                    pos: 14976676367971893,
                    site: 0,
                },
                SyncAll,
                Ins {
                    content: 0,
                    pos: 0,
                    site: 68,
                },
                Ins {
                    content: 52532,
                    pos: 6629299531957718322,
                    site: 92,
                },
                Del {
                    pos: 6655295901103053916,
                    len: 6655295901103053916,
                    site: 92,
                },
                Del {
                    pos: 6655295901103053916,
                    len: 14738250545257564,
                    site: 0,
                },
                Ins {
                    content: 52309,
                    pos: 3038287258827541861,
                    site: 255,
                },
                Ins {
                    content: 15159,
                    pos: 298,
                    site: 108,
                },
                Ins {
                    content: 10782,
                    pos: 18446602417805601322,
                    site: 255,
                },
                Ins {
                    content: 771,
                    pos: 3027266685993419523,
                    site: 42,
                },
                Ins {
                    content: 0,
                    pos: 2560,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 7740398491872002048,
                    site: 107,
                },
                Del {
                    pos: 7740398493674204011,
                    len: 7740398493674204011,
                    site: 107,
                },
                Del {
                    pos: 7740398493674204011,
                    len: 7740398493674204011,
                    site: 107,
                },
                Del {
                    pos: 7812738666512280684,
                    len: 10634005385065557100,
                    site: 147,
                },
                Ins {
                    content: 108,
                    pos: 3830030471958364160,
                    site: 224,
                },
                SyncAll,
                Ins {
                    content: 52730,
                    pos: 3442658613,
                    site: 11,
                },
                Ins {
                    content: 3871,
                    pos: 8444828877984183605,
                    site: 117,
                },
                Del {
                    pos: 8463800222054970741,
                    len: 3635941421513799029,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 12884901966,
                    site: 0,
                },
                Ins {
                    content: 11308,
                    pos: 143833902818798636,
                    site: 0,
                },
                Ins {
                    content: 65535,
                    pos: 1567663063039,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 4121356608997425152,
                    site: 37,
                },
                Ins {
                    content: 24576,
                    pos: 3182967475521064462,
                    site: 44,
                },
                Ins {
                    content: 47148,
                    pos: 1021239783737535532,
                    site: 44,
                },
                Ins {
                    content: 11283,
                    pos: 1021239783737535532,
                    site: 14,
                },
                Ins {
                    content: 11308,
                    pos: 3182967604875373612,
                    site: 44,
                },
                Ins {
                    content: 11308,
                    pos: 3182967604875373612,
                    site: 44,
                },
                Ins {
                    content: 11308,
                    pos: 4340410370284600380,
                    site: 60,
                },
                Ins {
                    content: 15420,
                    pos: 4340410370284600380,
                    site: 60,
                },
                Ins {
                    content: 15420,
                    pos: 4340410370284600380,
                    site: 60,
                },
                Ins {
                    content: 15420,
                    pos: 4340410370284600380,
                    site: 60,
                },
                Ins {
                    content: 15420,
                    pos: 4340410370284600380,
                    site: 60,
                },
                Ins {
                    content: 15420,
                    pos: 4340410370284600380,
                    site: 60,
                },
                Ins {
                    content: 11324,
                    pos: 3182967604875373612,
                    site: 44,
                },
                Ins {
                    content: 11308,
                    pos: 3617346860830436396,
                    site: 170,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 57927929864792618,
                    site: 0,
                },
                Ins {
                    content: 64012,
                    pos: 900719925474099199,
                    site: 12,
                },
                Ins {
                    content: 3084,
                    pos: 789516,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 86131342873526272,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 3038287259199220224,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 10794,
                    pos: 3038287259199220266,
                    site: 42,
                },
                Ins {
                    content: 11308,
                    pos: 3182967604875373612,
                    site: 44,
                },
                Ins {
                    content: 11308,
                    pos: 3182967604875373612,
                    site: 44,
                },
                Ins {
                    content: 11308,
                    pos: 3182967604875111468,
                    site: 44,
                },
                Ins {
                    content: 11308,
                    pos: 3182967604875373612,
                    site: 44,
                },
                Ins {
                    content: 11308,
                    pos: 48568231275564,
                    site: 0,
                },
                Ins {
                    content: 13568,
                    pos: 8463800223526997301,
                    site: 117,
                },
                Del {
                    pos: 216718996853,
                    len: 335007449137,
                    site: 3,
                },
                Ins {
                    content: 0,
                    pos: 3819052576016433152,
                    site: 53,
                },
                Ins {
                    content: 0,
                    pos: 4548370641345118208,
                    site: 212,
                },
                Ins {
                    content: 15104,
                    pos: 144115188075855872,
                    site: 20,
                },
                Ins {
                    content: 63999,
                    pos: 327908794171647,
                    site: 0,
                },
                Ins {
                    content: 65388,
                    pos: 3038287258997104158,
                    site: 42,
                },
                SyncAll,
                Ins {
                    content: 771,
                    pos: 217020518514230019,
                    site: 42,
                },
                Ins {
                    content: 0,
                    pos: 655360,
                    site: 0,
                },
                Del {
                    pos: 7710162562058289173,
                    len: 7740398493674204011,
                    site: 107,
                },
                Del {
                    pos: 7740398493674204011,
                    len: 7039851,
                    site: 49,
                },
                Ins {
                    content: 54335,
                    pos: 64872246332757,
                    site: 0,
                },
                Ins {
                    content: 5122,
                    pos: 72050993380600362,
                    site: 50,
                },
                Ins {
                    content: 0,
                    pos: 2170452909760708608,
                    site: 30,
                },
                Ins {
                    content: 10794,
                    pos: 217021605090393898,
                    site: 3,
                },
                Ins {
                    content: 763,
                    pos: 2606223169945797379,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 7799953079628988416,
                    site: 21,
                },
                Ins {
                    content: 0,
                    pos: 7740398493674204011,
                    site: 107,
                },
                Del {
                    pos: 7740398493674204011,
                    len: 7740398493674204011,
                    site: 107,
                },
                Del {
                    pos: 7740398493674204011,
                    len: 7782338265204091755,
                    site: 108,
                },
                Del {
                    pos: 7812738666512280684,
                    len: 10664523451937821582,
                    site: 0,
                },
                Ins {
                    content: 0,
                    pos: 18302637545179512940,
                    site: 255,
                },
                Ins {
                    content: 52730,
                    pos: 3442658613,
                    site: 11,
                },
                Ins {
                    content: 3871,
                    pos: 8444828877984183605,
                    site: 117,
                },
                Del {
                    pos: 8463800222054970741,
                    len: 10049067290889385333,
                    site: 138,
                },
                Sync { from: 138, to: 129 },
            ],
        )
    }

    #[test]
    fn richtext_fuzz_0() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 9728,
                    pos: 3829748534148603701,
                    site: 31,
                },
                SyncAll,
                Mark {
                    pos: 144373576751199690,
                    len: 39583260855602,
                    site: 38,
                    style_key: 227,
                },
                Del {
                    pos: 18446521092732302645,
                    len: 15028556109460991,
                    site: 53,
                },
            ],
        )
    }

    #[test]
    fn richtext_fuzz_1() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 41009,
                    pos: 0,
                    site: 1,
                },
                Mark {
                    pos: 0,
                    len: 2,
                    site: 1,
                    style_key: 151,
                },
                Mark {
                    pos: 0,
                    len: 1,
                    site: 0,
                    style_key: 151,
                },
            ],
        )
    }

    #[test]
    fn richtext_fuzz_2() {
        test_multi_sites(
            5,
            &mut [
                Del {
                    pos: 3617008641902972703,
                    len: 3617008641903833650,
                    site: 50,
                },
                Ins {
                    content: 12850,
                    pos: 7668058320836112946,
                    site: 106,
                },
                Mark {
                    pos: 7667941315552635498,
                    len: 7668058320836127338,
                    site: 106,
                    style_key: 106,
                },
                Mark {
                    pos: 1096122290479458922,
                    len: 17749549354505267,
                    site: 1,
                    style_key: 0,
                },
                Mark {
                    pos: 7668058389825092218,
                    len: 7668058320836127338,
                    site: 106,
                    style_key: 50,
                },
            ],
        )
    }

    #[test]
    fn richtext_fuzz_3() {
        test_multi_sites(
            5,
            &mut [Del {
                pos: 36310271995488768,
                len: 5859553690644468061,
                site: 81,
            }],
        );
    }

    #[test]
    fn fuzz_4() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 17733,
                    pos: 4991471925827290437,
                    site: 69,
                },
                Del {
                    pos: 4991471925827290437,
                    len: 4991471925827290437,
                    site: 69,
                },
                Del {
                    pos: 4991471925827290437,
                    len: 4991471925827290437,
                    site: 69,
                },
            ],
        )
    }

    #[test]
    fn fuzz_5() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 13877,
                    pos: 0,
                    site: 0,
                },
                Del {
                    pos: 3,
                    len: 4,
                    site: 0,
                },
                Del {
                    pos: 2,
                    len: 1,
                    site: 0,
                },
                Ins {
                    content: 12850,
                    pos: 0,
                    site: 1,
                },
                Ins {
                    content: 52487,
                    pos: 0,
                    site: 4,
                },
            ],
        );
    }

    #[test]
    fn fuzz_6() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 0,
                    pos: 16384000,
                    site: 0,
                },
                Mark {
                    pos: 4503599627370752,
                    len: 14829735428355981312,
                    site: 0,
                    style_key: 0,
                },
                Ins {
                    content: 10624,
                    pos: 1182309699815473152,
                    site: 0,
                },
                Ins {
                    content: 52685,
                    pos: 3474262130214096333,
                    site: 128,
                },
                Mark {
                    pos: 3607102274975328360,
                    len: 7812629349709198644,
                    site: 108,
                    style_key: 108,
                },
                Mark {
                    pos: 7812738666512280684,
                    len: 7812738666512280684,
                    site: 108,
                    style_key: 108,
                },
                Mark {
                    pos: 7812738666512280684,
                    len: 7812738666512280684,
                    site: 108,
                    style_key: 108,
                },
                Mark {
                    pos: 7812738666512280684,
                    len: 7812738666512280684,
                    site: 108,
                    style_key: 108,
                },
                Mark {
                    pos: 7812738666512280684,
                    len: 7812738666512280684,
                    site: 108,
                    style_key: 108,
                },
                Mark {
                    pos: 7812738666512280684,
                    len: 7812738666512280684,
                    site: 108,
                    style_key: 108,
                },
                Mark {
                    pos: 7812738666512280684,
                    len: 7812738666512280684,
                    site: 108,
                    style_key: 108,
                },
                Mark {
                    pos: 7812738666512280684,
                    len: 7812738666512280684,
                    site: 108,
                    style_key: 108,
                },
            ],
        );
    }

    #[test]
    fn fuzz_7() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 23507,
                    pos: 18446694595669524485,
                    site: 255,
                },
                SyncAll,
                Mark {
                    pos: 281474976710504,
                    len: 2018765,
                    site: 0,
                    style_key: 0,
                },
                Ins {
                    content: 29812,
                    pos: 13238251629368014964,
                    site: 183,
                },
                Del {
                    pos: 222575692683,
                    len: 8391339105262239744,
                    site: 120,
                },
            ],
        )
    }

    #[test]
    fn fuzz_8() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 0,
                    pos: 16384000,
                    site: 0,
                },
                Mark {
                    pos: 4503599627370752,
                    len: 14829735428355981312,
                    site: 0,
                    style_key: 0,
                },
                Ins {
                    content: 52685,
                    pos: 3474262130214096333,
                    site: 128,
                },
                Mark {
                    pos: 3607102274975328360,
                    len: 7812629349709198644,
                    site: 108,
                    style_key: 108,
                },
            ],
        )
    }

    #[test]
    fn fuzz_9() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 3855,
                    pos: 0,
                    site: 0,
                },
                SyncAll,
                Ins {
                    content: 59648,
                    pos: 3,
                    site: 0,
                },
                Ins {
                    content: 12815,
                    pos: 2,
                    site: 0,
                },
                Ins {
                    content: 65535,
                    pos: 12,
                    site: 0,
                },
                Del {
                    pos: 9,
                    len: 18,
                    site: 0,
                },
            ],
        )
    }

    #[test]
    fn fuzz_snapshot() {
        test_multi_sites(
            5,
            &mut [
                Ins {
                    content: 52480,
                    pos: 0,
                    site: 1,
                },
                Mark {
                    pos: 6,
                    len: 1,
                    site: 1,
                    style_key: 5,
                },
                Ins {
                    content: 8224,
                    pos: 0,
                    site: 1,
                },
                Del {
                    pos: 12,
                    len: 1,
                    site: 1,
                },
                Ins {
                    content: 257,
                    pos: 10,
                    site: 1,
                },
                Ins {
                    content: 332,
                    pos: 11,
                    site: 1,
                },
                Del {
                    pos: 1,
                    len: 21,
                    site: 1,
                },
                Del {
                    pos: 0,
                    len: 1,
                    site: 1,
                },
                Ins {
                    content: 11309,
                    pos: 0,
                    site: 4,
                },
            ],
        )
    }

    #[test]
    fn mini_r() {
        minify_error(5, vec![], test_multi_sites, |site_num, ans| {
            let mut sites = Vec::new();
            for i in 0..site_num {
                let loro = LoroDoc::new();
                loro.set_peer_id(i as u64).unwrap();
                sites.push(loro);
            }

            let mut applied = Vec::new();
            for action in ans.iter_mut() {
                sites.preprocess(action);
                applied.push(action.clone());
                sites.apply_action(action);
            }

            ans.to_vec()
        })
    }
}