loro_internal/delta/
text.rs1use rustc_hash::FxHashMap;
2use loro_common::{InternalString, LoroValue, PeerID};
3use serde::{Deserialize, Serialize};
4
5use crate::change::Lamport;
6use crate::container::richtext::{Style, Styles};
7use crate::event::TextMeta;
8use crate::ToJson;
9
10use super::Meta;
11
12#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub struct StyleMeta {
14 map: FxHashMap<InternalString, StyleMetaItem>,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub struct StyleMetaItem {
19 pub lamport: Lamport,
21 pub peer: PeerID,
22 pub value: LoroValue,
23}
24
25impl StyleMetaItem {
26 pub fn try_replace(&mut self, other: &StyleMetaItem) {
27 if (self.lamport, self.peer) < (other.lamport, other.peer) {
28 self.lamport = other.lamport;
29 self.peer = other.peer;
30 self.value = other.value.clone();
31 }
32 }
33}
34
35impl From<&Styles> for StyleMeta {
36 fn from(styles: &Styles) -> Self {
37 let mut map = FxHashMap::with_capacity_and_hasher(styles.len(), Default::default());
38 for (key, value) in styles.iter() {
39 if let Some(value) = value.get() {
40 map.insert(
41 key.key().clone(),
42 StyleMetaItem {
43 value: value.to_value(),
44 lamport: value.lamport,
45 peer: value.peer,
46 },
47 );
48 }
49 }
50 Self { map }
51 }
52}
53
54impl From<Styles> for StyleMeta {
55 fn from(styles: Styles) -> Self {
56 let temp = &styles;
57 temp.into()
58 }
59}
60
61impl Meta for StyleMeta {
62 fn is_empty(&self) -> bool {
63 self.map.is_empty()
64 }
65
66 fn compose(&mut self, other: &Self, _type_pair: (super::DeltaType, super::DeltaType)) {
67 for (key, value) in other.map.iter() {
68 match self.map.get_mut(key) {
69 Some(old_value) => {
70 old_value.try_replace(value);
71 }
72 None => {
73 self.map.insert(key.clone(), value.clone());
74 }
75 }
76 }
77 }
78
79 fn is_mergeable(&self, other: &Self) -> bool {
80 self.map == other.map
81 }
82
83 fn merge(&mut self, _: &Self) {}
84}
85
86impl Meta for TextMeta {
87 fn is_empty(&self) -> bool {
88 self.0.is_empty()
89 }
90
91 fn compose(&mut self, other: &Self, _: (super::DeltaType, super::DeltaType)) {
92 for (key, value) in other.0.iter() {
93 self.0.insert(key.clone(), value.clone());
94 }
95 }
96
97 fn is_mergeable(&self, other: &Self) -> bool {
98 self.0 == other.0
99 }
100
101 fn merge(&mut self, _: &Self) {}
102}
103
104impl StyleMeta {
105 pub(crate) fn iter(&self) -> impl Iterator<Item = (InternalString, Style)> + '_ {
106 self.map.iter().map(|(key, style)| {
107 (
108 key.clone(),
109 Style {
110 key: key.clone(),
111 data: style.value.clone(),
112 },
113 )
114 })
115 }
116
117 pub(crate) fn insert(&mut self, key: InternalString, value: StyleMetaItem) {
118 self.map.insert(key, value);
119 }
120
121 pub(crate) fn contains_key(&self, key: &InternalString) -> bool {
122 self.map.contains_key(key)
123 }
124
125 pub(crate) fn to_value(&self) -> LoroValue {
126 LoroValue::Map(self.to_map_without_null_value().into())
127 }
128
129 fn to_map_without_null_value(&self) -> FxHashMap<String, LoroValue> {
130 self.map
131 .iter()
132 .filter_map(|(key, value)| {
133 if value.value.is_null() {
134 None
135 } else {
136 Some((key.to_string(), value.value.clone()))
137 }
138 })
139 .collect()
140 }
141
142 pub(crate) fn to_map(&self) -> FxHashMap<String, LoroValue> {
143 self.map
144 .iter()
145 .map(|(key, value)| (key.to_string(), value.value.clone()))
146 .collect()
147 }
148
149 pub(crate) fn to_option_map(&self) -> Option<FxHashMap<String, LoroValue>> {
150 if self.is_empty() {
151 return None;
152 }
153
154 Some(self.to_map())
155 }
156}
157
158impl ToJson for TextMeta {
159 fn to_json_value(&self) -> serde_json::Value {
160 let mut map = serde_json::Map::new();
161 for (key, value) in self.0.iter() {
162 let value = serde_json::to_value(value).unwrap();
163 map.insert(key.to_string(), value);
164 }
165
166 serde_json::Value::Object(map)
167 }
168
169 fn from_json(s: &str) -> Self {
170 let map: FxHashMap<String, LoroValue> = serde_json::from_str(s).unwrap();
171 TextMeta(map)
172 }
173}