| 1 | use crate::block::{ItemPtr, BLOCK_GC_REF_NUMBER, GC, HAS_ORIGIN, HAS_RIGHT_ORIGIN}; |
| 2 | use crate::types::TypePtr; |
| 3 | use crate::updates::encoder::Encoder; |
| 4 | use crate::ID; |
| 5 | use std::ops::Deref; |
| 6 | |
| 7 | #[derive(Debug, Clone, Eq, PartialEq)] |
| 8 | pub(crate) enum BlockSlice { |
| 9 | Item(ItemSlice), |
| 10 | GC(GCSlice), |
| 11 | } |
| 12 | |
| 13 | impl BlockSlice { |
| 14 | pub fn clock_start(&self) -> u32 { |
| 15 | match self { |
| 16 | BlockSlice::Item(s) => s.clock_start(), |
| 17 | BlockSlice::GC(s) => s.clock_start(), |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | pub fn clock_end(&self) -> u32 { |
| 22 | match self { |
| 23 | BlockSlice::Item(s) => s.clock_end(), |
| 24 | BlockSlice::GC(s) => s.clock_end(), |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | pub(crate) fn as_item(&self) -> Option<ItemPtr> { |
| 29 | if let BlockSlice::Item(s) = self { |
| 30 | Some(s.ptr) |
| 31 | } else { |
| 32 | None |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | pub fn len(&self) -> u32 { |
| 37 | match self { |
| 38 | BlockSlice::Item(s) => s.len(), |
| 39 | BlockSlice::GC(s) => s.len(), |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | #[allow(dead_code)] |
| 44 | pub fn is_deleted(&self) -> bool { |
| 45 | match self { |
| 46 | BlockSlice::Item(s) => s.is_deleted(), |
| 47 | BlockSlice::GC(_) => true, |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | /// Trim a number of countable elements from the beginning of a current slice. |
| 52 | pub fn trim_start(&mut self, count: u32) { |
| 53 | match self { |
| 54 | BlockSlice::Item(s) => s.trim_start(count), |
| 55 | BlockSlice::GC(s) => s.trim_start(count), |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | /// Trim a number of countable elements from the end of a current slice. |
| 60 | pub fn trim_end(&mut self, count: u32) { |
| 61 | match self { |
| 62 | BlockSlice::Item(s) => s.trim_end(count), |
| 63 | BlockSlice::GC(s) => s.trim_end(count), |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | pub fn encode<E: Encoder>(&self, encoder: &mut E) { |
| 68 | match self { |
| 69 | BlockSlice::Item(s) => s.encode(encoder), |
| 70 | BlockSlice::GC(s) => s.encode(encoder), |
| 71 | } |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | impl From<ItemSlice> for BlockSlice { |
| 76 | fn from(slice: ItemSlice) -> Self { |
| 77 | BlockSlice::Item(slice) |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | impl From<GCSlice> for BlockSlice { |
| 82 | fn from(slice: GCSlice) -> Self { |
| 83 | BlockSlice::GC(slice) |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /// Defines a logical slice of an underlying [Item]. Yrs blocks define a series of sequential |
| 88 | /// updates performed by a single peer, while [ItemSlice]s enable to refer to a sub-range of these |
| 89 | /// blocks without need to splice them. |
| 90 | /// |
| 91 | /// If an underlying [Item] needs to be spliced to fit the boundaries defined by a corresponding |
| 92 | /// [ItemSlice], this can be done with help of transaction (see: [Store::materialize]). |
| 93 | #[derive(Debug, Clone, Eq, PartialEq)] |
| 94 | pub(crate) struct ItemSlice { |
| 95 | pub ptr: ItemPtr, |
| 96 | pub start: u32, |
| 97 | pub end: u32, |
| 98 | } |
| 99 | |
| 100 | impl ItemSlice { |
| 101 | pub fn new(ptr: ItemPtr, start: u32, end: u32) -> Self { |
| 102 | debug_assert!(start <= end); |
| 103 | ItemSlice { ptr, start, end } |
| 104 | } |
| 105 | pub fn clock_start(&self) -> u32 { |
| 106 | self.ptr.id.clock + self.start |
| 107 | } |
| 108 | |
| 109 | pub fn clock_end(&self) -> u32 { |
| 110 | self.ptr.id.clock + self.end |
| 111 | } |
| 112 | |
| 113 | /// Returns the number of elements (counted as Yjs ID clock length) of the block range described |
| 114 | /// by current [ItemSlice]. |
| 115 | pub fn len(&self) -> u32 { |
| 116 | self.end - self.start + 1 |
| 117 | } |
| 118 | |
| 119 | /// Returns the first [ID] covered by this slice (inclusive). |
| 120 | pub fn id(&self) -> ID { |
| 121 | let mut id = self.ptr.id; |
| 122 | id.clock += self.start; |
| 123 | id |
| 124 | } |
| 125 | |
| 126 | /// Returns the last [ID] covered by this slice (inclusive). |
| 127 | pub fn last_id(&self) -> ID { |
| 128 | let mut id = self.ptr.id; |
| 129 | id.clock += self.end; |
| 130 | id |
| 131 | } |
| 132 | |
| 133 | /// Trim a number of countable elements from the beginning of a current slice. |
| 134 | pub(crate) fn trim_start(&mut self, count: u32) { |
| 135 | debug_assert!(count <= self.len()); |
| 136 | self.start += count; |
| 137 | } |
| 138 | |
| 139 | /// Trim a number of countable elements from the end of a current slice. |
| 140 | pub(crate) fn trim_end(&mut self, count: u32) { |
| 141 | debug_assert!(count <= self.len()); |
| 142 | self.end -= count; |
| 143 | } |
| 144 | |
| 145 | /// Returns true when current [ItemSlice] left boundary is equal to the boundary of the |
| 146 | /// [ItemPtr] this slice wraps. |
| 147 | pub fn adjacent_left(&self) -> bool { |
| 148 | self.start == 0 |
| 149 | } |
| 150 | |
| 151 | /// Returns true when current [ItemSlice] right boundary is equal to the boundary of the |
| 152 | /// [ItemPtr] this slice wraps. |
| 153 | pub fn adjacent_right(&self) -> bool { |
| 154 | self.end == self.ptr.len() - 1 |
| 155 | } |
| 156 | |
| 157 | /// Returns true when boundaries marked by the current [ItemSlice] match the boundaries |
| 158 | /// of the underlying [ItemPtr]. |
| 159 | pub fn adjacent(&self) -> bool { |
| 160 | self.adjacent_left() && self.adjacent_right() |
| 161 | } |
| 162 | |
| 163 | /// Checks if an underlying [Item] has been marked as deleted. |
| 164 | pub fn is_deleted(&self) -> bool { |
| 165 | self.ptr.is_deleted() |
| 166 | } |
| 167 | |
| 168 | /// Checks if an underlying [Item] has been marked as countable. |
| 169 | pub fn is_countable(&self) -> bool { |
| 170 | self.ptr.is_countable() |
| 171 | } |
| 172 | |
| 173 | /// Checks if provided `id` exists within the bounds described by current [ItemSlice]. |
| 174 | pub fn contains_id(&self, id: &ID) -> bool { |
| 175 | let myself = self.ptr.id(); |
| 176 | myself.client == id.client |
| 177 | && id.clock >= myself.clock + self.start |
| 178 | && id.clock <= myself.clock + self.end |
| 179 | } |
| 180 | |
| 181 | pub fn encode<E: Encoder>(&self, encoder: &mut E) { |
| 182 | let item = self.ptr.deref(); |
| 183 | let mut info = item.info(); |
| 184 | let origin = if self.adjacent_left() { |
| 185 | item.origin |
| 186 | } else { |
| 187 | Some(ID::new(item.id.client, item.id.clock + self.start - 1)) |
| 188 | }; |
| 189 | if origin.is_some() { |
| 190 | info |= HAS_ORIGIN; |
| 191 | } |
| 192 | let cant_copy_parent_info = info & (HAS_ORIGIN | HAS_RIGHT_ORIGIN) == 0; |
| 193 | encoder.write_info(info); |
| 194 | if let Some(origin_id) = origin { |
| 195 | encoder.write_left_id(&origin_id); |
| 196 | } |
| 197 | if self.adjacent_right() { |
| 198 | if let Some(right_origin_id) = item.right_origin.as_ref() { |
| 199 | encoder.write_right_id(right_origin_id); |
| 200 | } |
| 201 | } |
| 202 | if cant_copy_parent_info { |
| 203 | match &item.parent { |
| 204 | TypePtr::Branch(branch) => { |
| 205 | if let Some(block) = branch.item { |
| 206 | encoder.write_parent_info(false); |
| 207 | encoder.write_left_id(block.id()); |
| 208 | } else if let Some(name) = branch.name.as_deref() { |
| 209 | encoder.write_parent_info(true); |
| 210 | encoder.write_string(name); |
| 211 | } else { |
| 212 | unreachable!("Could not get parent branch info for item") |
| 213 | } |
| 214 | } |
| 215 | TypePtr::Named(name) => { |
| 216 | encoder.write_parent_info(true); |
| 217 | encoder.write_string(name); |
| 218 | } |
| 219 | TypePtr::ID(id) => { |
| 220 | encoder.write_parent_info(false); |
| 221 | encoder.write_left_id(id); |
| 222 | } |
| 223 | TypePtr::Unknown => { |
| 224 | panic!("Couldn't get item's parent") |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | if let Some(parent_sub) = item.parent_sub.as_ref() { |
| 229 | encoder.write_string(parent_sub.as_ref()); |
| 230 | } |
| 231 | } |
| 232 | item.content.encode_slice(encoder, self.start, self.end); |
| 233 | } |
| 234 | |
| 235 | /// Returns a [ItemSlice] wrapper for a [Item] identified as a right neighbor of this slice. |
| 236 | /// This method doesn't have to be equivalent of [Item::right]: if current slices's end range |
| 237 | /// is not an equivalent to the end of underlying [Item], a returned slice will contain the |
| 238 | /// same block that starts when the current ends. |
| 239 | /// |
| 240 | /// # Example |
| 241 | /// |
| 242 | /// If an underlying block is responsible for clock range of [0..10) and current slice is [2..8) |
| 243 | /// then right slice returned by this method will be [8..10). |
| 244 | pub fn right(&self) -> Option<ItemSlice> { |
| 245 | let last_clock = self.ptr.len() - 1; |
| 246 | if self.end == last_clock { |
| 247 | let item = self.ptr.deref(); |
| 248 | let right_ptr = item.right?; |
| 249 | Some(ItemSlice::from(right_ptr)) |
| 250 | } else { |
| 251 | Some(ItemSlice::new(self.ptr, self.end + 1, last_clock)) |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | /// Returns a [ItemSlice] wrapper for a [Item] identified as a left neighbor of this slice. |
| 256 | /// This method doesn't have to be equivalent of [Item::right]: if current slices's start range |
| 257 | /// is not an equivalent to the start of underlying [Item], a returned slice will contain the |
| 258 | /// range that starts with current underlying block start and end where this slice starts. |
| 259 | /// |
| 260 | /// # Example |
| 261 | /// |
| 262 | /// If an underlying block is responsible for clock range of [0..10) and current slice is [2..8) |
| 263 | /// then right slice returned by this method will be [0..2). |
| 264 | pub fn left(&self) -> Option<ItemSlice> { |
| 265 | if self.start == 0 { |
| 266 | let item = self.ptr.deref(); |
| 267 | let left_ptr = item.left?; |
| 268 | Some(ItemSlice::from(left_ptr)) |
| 269 | } else { |
| 270 | Some(ItemSlice::new(self.ptr, 0, self.start - 1)) |
| 271 | } |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | impl From<ItemPtr> for ItemSlice { |
| 276 | fn from(ptr: ItemPtr) -> Self { |
| 277 | ItemSlice::new(ptr, 0, ptr.len() - 1) |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | #[derive(Debug, Clone, Eq, PartialEq)] |
| 282 | pub(crate) struct GCSlice { |
| 283 | pub start: u32, |
| 284 | pub end: u32, |
| 285 | } |
| 286 | |
| 287 | impl GCSlice { |
| 288 | pub fn clock_start(&self) -> u32 { |
| 289 | self.start |
| 290 | } |
| 291 | |
| 292 | pub fn clock_end(&self) -> u32 { |
| 293 | self.end |
| 294 | } |
| 295 | |
| 296 | /// Trim a number of countable elements from the beginning of a current slice. |
| 297 | pub(crate) fn trim_start(&mut self, count: u32) { |
| 298 | debug_assert!(count <= self.len()); |
| 299 | self.start += count; |
| 300 | } |
| 301 | |
| 302 | /// Trim a number of countable elements from the end of a current slice. |
| 303 | pub(crate) fn trim_end(&mut self, count: u32) { |
| 304 | debug_assert!(count <= self.len()); |
| 305 | self.end -= count; |
| 306 | } |
| 307 | |
| 308 | pub fn len(&self) -> u32 { |
| 309 | self.end - self.start + 1 |
| 310 | } |
| 311 | |
| 312 | pub fn encode<E: Encoder>(&self, encoder: &mut E) { |
| 313 | encoder.write_info(BLOCK_GC_REF_NUMBER); |
| 314 | encoder.write_len(self.len()); |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | impl From<GC> for GCSlice { |
| 319 | fn from(gc: GC) -> Self { |
| 320 | GCSlice { |
| 321 | start: gc.start, |
| 322 | end: gc.end, |
| 323 | } |
| 324 | } |
| 325 | } |
| 326 | |