Decode compressed CRDT operations.
(data: &[u8])
| 93 | |
| 94 | /// Decode compressed CRDT operations. |
| 95 | pub fn decode(data: &[u8]) -> Result<Vec<CrdtOp>, CodecError> { |
| 96 | if data.len() < 4 { |
| 97 | return Err(CodecError::Truncated { |
| 98 | expected: 4, |
| 99 | actual: data.len(), |
| 100 | }); |
| 101 | } |
| 102 | |
| 103 | let count = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize; |
| 104 | if count == 0 { |
| 105 | return Ok(Vec::new()); |
| 106 | } |
| 107 | |
| 108 | let mut pos = 4; |
| 109 | |
| 110 | // Actor dictionary. |
| 111 | if pos + 2 > data.len() { |
| 112 | return Err(CodecError::Truncated { |
| 113 | expected: pos + 2, |
| 114 | actual: data.len(), |
| 115 | }); |
| 116 | } |
| 117 | let actor_count = u16::from_le_bytes([data[pos], data[pos + 1]]) as usize; |
| 118 | pos += 2; |
| 119 | |
| 120 | let actor_bytes = actor_count * 8; |
| 121 | if pos + actor_bytes > data.len() { |
| 122 | return Err(CodecError::Truncated { |
| 123 | expected: pos + actor_bytes, |
| 124 | actual: data.len(), |
| 125 | }); |
| 126 | } |
| 127 | let actor_dict: Vec<u64> = data[pos..pos + actor_bytes] |
| 128 | .chunks_exact(8) |
| 129 | .map(|c| u64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])) |
| 130 | .collect(); |
| 131 | pos += actor_bytes; |
| 132 | |
| 133 | // Lamport block. |
| 134 | if pos + 4 > data.len() { |
| 135 | return Err(CodecError::Truncated { |
| 136 | expected: pos + 4, |
| 137 | actual: data.len(), |
| 138 | }); |
| 139 | } |
| 140 | let lamport_size = |
| 141 | u32::from_le_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]) as usize; |
| 142 | pos += 4; |
| 143 | if pos + lamport_size > data.len() { |
| 144 | return Err(CodecError::Truncated { |
| 145 | expected: pos + lamport_size, |
| 146 | actual: data.len(), |
| 147 | }); |
| 148 | } |
| 149 | let lamports = crate::delta::decode(&data[pos..pos + lamport_size])?; |
| 150 | pos += lamport_size; |
| 151 | |
| 152 | // Actor index width + data. |