loro_internal/
configure.rs

1use rustc_hash::FxHashSet;
2use loro_common::ContainerID;
3
4pub use crate::container::richtext::config::{StyleConfig, StyleConfigMap};
5use crate::LoroDoc;
6use std::sync::atomic::{AtomicBool, AtomicI64};
7use std::sync::RwLock;
8use std::sync::{Arc, Mutex};
9
10#[derive(Clone, Debug)]
11pub struct Configure {
12    pub(crate) text_style_config: Arc<RwLock<StyleConfigMap>>,
13    record_timestamp: Arc<AtomicBool>,
14    pub(crate) merge_interval_in_s: Arc<AtomicI64>,
15    pub(crate) editable_detached_mode: Arc<AtomicBool>,
16    pub(crate) deleted_root_containers: Arc<Mutex<FxHashSet<ContainerID>>>,
17    pub(crate) hide_empty_root_containers: Arc<AtomicBool>,
18}
19
20impl LoroDoc {
21    pub(crate) fn set_config(&self, config: &Configure) {
22        self.config_text_style(config.text_style_config.read().unwrap().clone());
23        self.set_record_timestamp(config.record_timestamp());
24        self.set_change_merge_interval(config.merge_interval());
25        self.set_detached_editing(config.detached_editing());
26    }
27}
28
29impl Default for Configure {
30    fn default() -> Self {
31        Self {
32            text_style_config: Arc::new(RwLock::new(StyleConfigMap::default_rich_text_config())),
33            record_timestamp: Arc::new(AtomicBool::new(false)),
34            editable_detached_mode: Arc::new(AtomicBool::new(false)),
35            merge_interval_in_s: Arc::new(AtomicI64::new(1000)),
36            deleted_root_containers: Arc::new(Mutex::new(Default::default())),
37            hide_empty_root_containers: Arc::new(AtomicBool::new(false)),
38        }
39    }
40}
41
42impl Configure {
43    pub fn fork(&self) -> Self {
44        Self {
45            text_style_config: Arc::new(RwLock::new(
46                self.text_style_config.read().unwrap().clone(),
47            )),
48            record_timestamp: Arc::new(AtomicBool::new(
49                self.record_timestamp
50                    .load(std::sync::atomic::Ordering::Relaxed),
51            )),
52            merge_interval_in_s: Arc::new(AtomicI64::new(
53                self.merge_interval_in_s
54                    .load(std::sync::atomic::Ordering::Relaxed),
55            )),
56            editable_detached_mode: Arc::new(AtomicBool::new(
57                self.editable_detached_mode
58                    .load(std::sync::atomic::Ordering::Relaxed),
59            )),
60            deleted_root_containers: Arc::new(Mutex::new(
61                self.deleted_root_containers.lock().unwrap().clone(),
62            )),
63            hide_empty_root_containers: Arc::new(AtomicBool::new(
64                self.hide_empty_root_containers
65                    .load(std::sync::atomic::Ordering::Relaxed),
66            )),
67        }
68    }
69
70    pub fn text_style_config(&self) -> &Arc<RwLock<StyleConfigMap>> {
71        &self.text_style_config
72    }
73
74    pub fn record_timestamp(&self) -> bool {
75        self.record_timestamp
76            .load(std::sync::atomic::Ordering::Relaxed)
77    }
78
79    pub fn set_record_timestamp(&self, record: bool) {
80        self.record_timestamp
81            .store(record, std::sync::atomic::Ordering::Relaxed);
82    }
83
84    pub fn detached_editing(&self) -> bool {
85        self.editable_detached_mode
86            .load(std::sync::atomic::Ordering::Relaxed)
87    }
88
89    pub fn set_detached_editing(&self, mode: bool) {
90        self.editable_detached_mode
91            .store(mode, std::sync::atomic::Ordering::Relaxed);
92    }
93
94    pub fn merge_interval(&self) -> i64 {
95        self.merge_interval_in_s
96            .load(std::sync::atomic::Ordering::Relaxed)
97    }
98
99    pub fn set_merge_interval(&self, interval: i64) {
100        self.merge_interval_in_s
101            .store(interval, std::sync::atomic::Ordering::Relaxed);
102    }
103
104    pub fn set_hide_empty_root_containers(&self, hide: bool) {
105        self.hide_empty_root_containers
106            .store(hide, std::sync::atomic::Ordering::Relaxed);
107    }
108}
109
110#[derive(Debug)]
111pub struct DefaultRandom;
112
113#[cfg(test)]
114use std::sync::atomic::AtomicU64;
115#[cfg(test)]
116static mut TEST_RANDOM: AtomicU64 = AtomicU64::new(0);
117
118impl SecureRandomGenerator for DefaultRandom {
119    fn fill_byte(&self, dest: &mut [u8]) {
120        #[cfg(not(test))]
121        getrandom::getrandom(dest).unwrap();
122
123        #[cfg(test)]
124        // SAFETY: this is only used in test
125        unsafe {
126            #[allow(static_mut_refs)]
127            let bytes = TEST_RANDOM.fetch_add(1, std::sync::atomic::Ordering::Release);
128            dest.copy_from_slice(&bytes.to_le_bytes());
129        }
130    }
131}
132
133pub trait SecureRandomGenerator: Send + Sync {
134    fn fill_byte(&self, dest: &mut [u8]);
135    fn next_u64(&self) -> u64 {
136        let mut buf = [0u8; 8];
137        self.fill_byte(&mut buf);
138        u64::from_le_bytes(buf)
139    }
140
141    fn next_u32(&self) -> u32 {
142        let mut buf = [0u8; 4];
143        self.fill_byte(&mut buf);
144        u32::from_le_bytes(buf)
145    }
146
147    fn next_i64(&self) -> i64 {
148        let mut buf = [0u8; 8];
149        self.fill_byte(&mut buf);
150        i64::from_le_bytes(buf)
151    }
152
153    fn next_i32(&self) -> i32 {
154        let mut buf = [0u8; 4];
155        self.fill_byte(&mut buf);
156        i32::from_le_bytes(buf)
157    }
158}