1use std::fmt;
4
5use crate::{
6 AggregateTypeId, ConflictKey, Date, EntityKey, EntityTypeId, EnumVariantId, IndexEntryKey,
7 IndexId, PartitionKey, Timestamp,
8 limits::MAX_KEY_BYTES,
9 {
10 CONFLICT_KEY_V1_PREFIX, ENTITY_KEY_V1_PREFIX, INDEX_ENTRY_KEY_V1_PREFIX,
11 PARTITION_KEY_V1_PREFIX,
12 },
13};
14
15macro_rules! key_component_methods {
16 () => {
17 pub fn push_bool(&mut self, value: bool) -> Result<&mut Self, KeyEncodingError> {
19 self.0.push_fixed(&[u8::from(value)])?;
20 Ok(self)
21 }
22
23 pub fn push_u32(&mut self, value: u32) -> Result<&mut Self, KeyEncodingError> {
25 self.0.push_fixed(&value.to_be_bytes())?;
26 Ok(self)
27 }
28
29 pub fn push_u64(&mut self, value: u64) -> Result<&mut Self, KeyEncodingError> {
31 self.0.push_fixed(&value.to_be_bytes())?;
32 Ok(self)
33 }
34
35 pub fn push_i32(&mut self, value: i32) -> Result<&mut Self, KeyEncodingError> {
37 let mut bytes = value.to_be_bytes();
38 bytes[0] ^= 0x80;
39 self.0.push_fixed(&bytes)?;
40 Ok(self)
41 }
42
43 pub fn push_i64(&mut self, value: i64) -> Result<&mut Self, KeyEncodingError> {
45 let mut bytes = value.to_be_bytes();
46 bytes[0] ^= 0x80;
47 self.0.push_fixed(&bytes)?;
48 Ok(self)
49 }
50
51 pub fn push_timestamp(&mut self, value: Timestamp) -> Result<&mut Self, KeyEncodingError> {
53 let mut seconds = value.seconds().to_be_bytes();
54 seconds[0] ^= 0x80;
55 let nanoseconds = value.nanoseconds().to_be_bytes();
56 let mut bytes = [0; 12];
57 bytes[..8].copy_from_slice(&seconds);
58 bytes[8..].copy_from_slice(&nanoseconds);
59 self.0.push_fixed(&bytes)?;
60 Ok(self)
61 }
62
63 pub fn push_date(&mut self, value: Date) -> Result<&mut Self, KeyEncodingError> {
65 let mut bytes = value.days_since_unix_epoch().to_be_bytes();
66 bytes[0] ^= 0x80;
67 self.0.push_fixed(&bytes)?;
68 Ok(self)
69 }
70
71 pub fn push_enum_variant(
73 &mut self,
74 value: EnumVariantId,
75 ) -> Result<&mut Self, KeyEncodingError> {
76 self.0.push_fixed(&value.to_be_bytes())?;
77 Ok(self)
78 }
79
80 pub fn push_uuid(&mut self, value: &[u8; 16]) -> Result<&mut Self, KeyEncodingError> {
82 self.0.push_fixed(value)?;
83 Ok(self)
84 }
85
86 pub fn push_bytes(&mut self, value: &[u8]) -> Result<&mut Self, KeyEncodingError> {
88 self.0.push_bytes(value)?;
89 Ok(self)
90 }
91
92 pub fn push_str(&mut self, value: &str) -> Result<&mut Self, KeyEncodingError> {
94 self.0.push_bytes(value.as_bytes())?;
95 Ok(self)
96 }
97
98 pub fn push_ordered_bytes(&mut self, value: &[u8]) -> Result<&mut Self, KeyEncodingError> {
100 self.0.push_ordered_bytes(value, true)?;
101 Ok(self)
102 }
103
104 pub fn push_ordered_bytes_prefix(
106 &mut self,
107 value: &[u8],
108 ) -> Result<&mut Self, KeyEncodingError> {
109 self.0.push_ordered_bytes(value, false)?;
110 Ok(self)
111 }
112
113 pub fn as_bytes(&self) -> &[u8] {
115 &self.0.bytes
116 }
117 };
118}
119
120#[derive(Clone)]
122pub struct EntityKeyBuilder(KeyBuilder);
123
124impl EntityKeyBuilder {
125 pub fn new(entity_type: EntityTypeId) -> Self {
127 Self(KeyBuilder::new(
128 &ENTITY_KEY_V1_PREFIX,
129 entity_type.get().to_be_bytes(),
130 ))
131 }
132
133 key_component_methods!();
134
135 pub fn finish(self) -> Result<EntityKey, KeyEncodingError> {
137 Ok(EntityKey::from_validated_bytes(self.0.bytes))
138 }
139}
140
141impl fmt::Debug for EntityKeyBuilder {
142 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
143 formatter
144 .debug_struct("EntityKeyBuilder")
145 .field("bytes", &"[REDACTED]")
146 .field("length", &self.0.bytes.len())
147 .finish()
148 }
149}
150
151#[derive(Clone)]
153pub struct ConflictKeyBuilder(KeyBuilder);
154
155impl ConflictKeyBuilder {
156 pub fn new(aggregate_type: AggregateTypeId) -> Self {
158 Self(KeyBuilder::new(
159 &CONFLICT_KEY_V1_PREFIX,
160 aggregate_type.get().to_be_bytes(),
161 ))
162 }
163
164 key_component_methods!();
165
166 pub fn finish(self) -> Result<ConflictKey, KeyEncodingError> {
168 Ok(ConflictKey::from_validated_bytes(self.0.bytes))
169 }
170}
171
172impl fmt::Debug for ConflictKeyBuilder {
173 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
174 formatter
175 .debug_struct("ConflictKeyBuilder")
176 .field("bytes", &"[REDACTED]")
177 .field("length", &self.0.bytes.len())
178 .finish()
179 }
180}
181
182#[derive(Clone)]
184pub struct PartitionKeyBuilder(KeyBuilder);
185
186impl PartitionKeyBuilder {
187 pub fn new(aggregate_type: AggregateTypeId) -> Self {
189 Self(KeyBuilder::new(
190 &PARTITION_KEY_V1_PREFIX,
191 aggregate_type.get().to_be_bytes(),
192 ))
193 }
194
195 key_component_methods!();
196
197 pub fn finish(self) -> Result<PartitionKey, KeyEncodingError> {
199 Ok(PartitionKey::from_validated_bytes(self.0.bytes))
200 }
201}
202
203impl fmt::Debug for PartitionKeyBuilder {
204 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
205 formatter
206 .debug_struct("PartitionKeyBuilder")
207 .field("bytes", &"[REDACTED]")
208 .field("length", &self.0.bytes.len())
209 .finish()
210 }
211}
212
213#[derive(Clone)]
215pub struct IndexEntryKeyBuilder(KeyBuilder);
216
217impl IndexEntryKeyBuilder {
218 pub fn new(index: IndexId) -> Self {
220 Self(KeyBuilder::new(
221 &INDEX_ENTRY_KEY_V1_PREFIX,
222 index.get().to_be_bytes(),
223 ))
224 }
225
226 key_component_methods!();
227
228 pub fn finish(mut self, entity_key: EntityKey) -> Result<IndexEntryKey, KeyEncodingError> {
230 self.0.push_bytes(entity_key.as_bytes())?;
231 Ok(IndexEntryKey::from_validated_bytes(self.0.bytes))
232 }
233}
234
235impl fmt::Debug for IndexEntryKeyBuilder {
236 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
237 formatter
238 .debug_struct("IndexEntryKeyBuilder")
239 .field("bytes", &"[REDACTED]")
240 .field("length", &self.0.bytes.len())
241 .finish()
242 }
243}
244
245#[derive(Clone)]
246struct KeyBuilder {
247 bytes: Vec<u8>,
248}
249
250impl KeyBuilder {
251 const INITIAL_CAPACITY: usize = 64;
260
261 fn new(prefix: &[u8], type_id: [u8; 4]) -> Self {
262 let mut bytes = Vec::with_capacity(Self::INITIAL_CAPACITY);
263 bytes.extend_from_slice(prefix);
264 bytes.extend_from_slice(&type_id);
265 Self { bytes }
266 }
267
268 fn push_fixed(&mut self, bytes: &[u8]) -> Result<(), KeyEncodingError> {
269 self.ensure_additional(bytes.len())?;
270 self.bytes.extend_from_slice(bytes);
271 Ok(())
272 }
273
274 fn push_bytes(&mut self, bytes: &[u8]) -> Result<(), KeyEncodingError> {
275 let length =
276 u32::try_from(bytes.len()).map_err(|_| KeyEncodingError::ComponentTooLong {
277 actual: bytes.len(),
278 maximum: u32::MAX as usize,
279 })?;
280 let additional = 4usize
281 .checked_add(bytes.len())
282 .ok_or(KeyEncodingError::TooLong {
283 actual: usize::MAX,
284 maximum: MAX_KEY_BYTES,
285 })?;
286 self.ensure_additional(additional)?;
287 self.bytes.extend_from_slice(&length.to_be_bytes());
288 self.bytes.extend_from_slice(bytes);
289 Ok(())
290 }
291
292 fn push_ordered_bytes(
293 &mut self,
294 bytes: &[u8],
295 terminated: bool,
296 ) -> Result<(), KeyEncodingError> {
297 let zeros = bytes.iter().filter(|byte| **byte == 0).count();
298 let additional = bytes
299 .len()
300 .checked_add(zeros)
301 .and_then(|value| value.checked_add(if terminated { 2 } else { 0 }))
302 .ok_or(KeyEncodingError::TooLong {
303 actual: usize::MAX,
304 maximum: MAX_KEY_BYTES,
305 })?;
306 self.ensure_additional(additional)?;
307 for byte in bytes {
308 if *byte == 0 {
309 self.bytes.extend_from_slice(&[0, 0xff]);
310 } else {
311 self.bytes.push(*byte);
312 }
313 }
314 if terminated {
315 self.bytes.extend_from_slice(&[0, 0]);
316 }
317 Ok(())
318 }
319
320 fn ensure_additional(&self, additional: usize) -> Result<(), KeyEncodingError> {
321 let actual = self
322 .bytes
323 .len()
324 .checked_add(additional)
325 .ok_or(KeyEncodingError::TooLong {
326 actual: usize::MAX,
327 maximum: MAX_KEY_BYTES,
328 })?;
329 if actual > MAX_KEY_BYTES {
330 return Err(KeyEncodingError::TooLong {
331 actual,
332 maximum: MAX_KEY_BYTES,
333 });
334 }
335 Ok(())
336 }
337}
338
339#[derive(Clone, Debug, Eq, PartialEq)]
341pub enum KeyEncodingError {
342 TooLong {
344 actual: usize,
346 maximum: usize,
348 },
349 ComponentTooLong {
351 actual: usize,
353 maximum: usize,
355 },
356}
357
358impl fmt::Display for KeyEncodingError {
359 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
360 match self {
361 Self::TooLong { actual, maximum } => {
362 write!(
363 formatter,
364 "key would have {actual} bytes; maximum is {maximum}"
365 )
366 }
367 Self::ComponentTooLong { actual, maximum } => write!(
368 formatter,
369 "key component has {actual} bytes; maximum is {maximum}"
370 ),
371 }
372 }
373}
374
375impl std::error::Error for KeyEncodingError {}
376
377#[cfg(test)]
378mod tests {
379 use super::*;
380
381 #[test]
382 fn key_identity_is_part_of_the_immutable_prefix() {
383 assert_eq!(
384 EntityKeyBuilder::new(EntityTypeId::new(0x0102_0304).expect("nonzero")).as_bytes(),
385 &[0x45, 0x01, 0x01, 0x02, 0x03, 0x04]
386 );
387 assert_eq!(
388 ConflictKeyBuilder::new(AggregateTypeId::new(0x0506_0708).expect("nonzero")).as_bytes(),
389 &[0x43, 0x01, 0x05, 0x06, 0x07, 0x08]
390 );
391 assert_eq!(
392 PartitionKeyBuilder::new(AggregateTypeId::new(0x090a_0b0c).expect("nonzero"))
393 .as_bytes(),
394 &[0x50, 0x01, 0x09, 0x0a, 0x0b, 0x0c]
395 );
396 assert_eq!(
397 IndexEntryKeyBuilder::new(IndexId::new(0x0d0e_0f10).expect("nonzero")).as_bytes(),
398 &[0x49, 0x01, 0x0d, 0x0e, 0x0f, 0x10]
399 );
400 }
401
402 #[test]
403 fn failed_append_does_not_mutate_builder() {
404 let mut builder = EntityKeyBuilder::new(EntityTypeId::first());
405 let before = builder.as_bytes().to_vec();
406 assert!(builder.push_bytes(&vec![0; MAX_KEY_BYTES]).is_err());
407 assert_eq!(builder.as_bytes(), before);
408 }
409}