1use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
5
6use crate::{generate::compile_error, key_conformance::expand_tests};
7
8pub struct KeyField {
9 pub name: String,
10 pub column: KeyColumn,
11 pub ty: String,
12}
13
14#[derive(Clone, Copy)]
15pub enum KeyColumn {
16 U8,
17 U16,
18 U32,
19 U64,
20 U128,
21 RowNumber,
22 GroupId,
23 Blob16,
24 TableId,
25 ColumnId,
26 ObjectId,
27 StorageId,
28 FlowId,
29 FlowEdgeId,
30 OperatorId,
31 HandlerId,
32 NamespaceId,
33 SumTypeId,
34 SequenceId,
35 EpochSeconds,
36 IdentityId,
37 ViewId,
38 SeriesId,
39 SinkId,
40 WindowedViewGroupId,
41 SourceId,
42 QueueId,
43 RingBufferId,
44 BindingId,
45 DictionaryId,
46 ProcedureId,
47 DateTime,
48 Partition,
49 ColumnPropertyId,
50 RowShapeFingerprint,
51 RelationshipId,
52 MigrationId,
53 MigrationEventId,
54 PrimaryKeyId,
55 ColumnBlockId,
56 IndexId,
57 OptionU8,
58 ReprU8,
59 Str,
60 DisplayStr,
61 EscapedBytes,
62 KeyspaceId,
63 RawTail,
64 TaggedIndexId,
65 VarintU128,
66 SortRun,
67 AscRowNumber,
68 AscU64,
69}
70
71impl KeyColumn {
72 fn width(self) -> usize {
73 match self {
74 KeyColumn::U8 | KeyColumn::ReprU8 | KeyColumn::KeyspaceId => 1,
75 KeyColumn::Str
76 | KeyColumn::DisplayStr
77 | KeyColumn::EscapedBytes
78 | KeyColumn::RawTail
79 | KeyColumn::SortRun => 16,
80 KeyColumn::TaggedIndexId => 9,
81 KeyColumn::VarintU128 => 17,
82 KeyColumn::AscRowNumber | KeyColumn::AscU64 => 8,
83 KeyColumn::U16 => 2,
84 KeyColumn::U32 => 4,
85 KeyColumn::U64
86 | KeyColumn::RowNumber
87 | KeyColumn::TableId
88 | KeyColumn::ColumnId
89 | KeyColumn::FlowId
90 | KeyColumn::FlowEdgeId
91 | KeyColumn::OperatorId
92 | KeyColumn::HandlerId
93 | KeyColumn::NamespaceId
94 | KeyColumn::SumTypeId
95 | KeyColumn::SequenceId
96 | KeyColumn::EpochSeconds
97 | KeyColumn::ViewId
98 | KeyColumn::SeriesId
99 | KeyColumn::SinkId
100 | KeyColumn::WindowedViewGroupId
101 | KeyColumn::SourceId
102 | KeyColumn::QueueId
103 | KeyColumn::RingBufferId
104 | KeyColumn::BindingId
105 | KeyColumn::DictionaryId
106 | KeyColumn::ProcedureId
107 | KeyColumn::DateTime
108 | KeyColumn::ColumnPropertyId
109 | KeyColumn::RowShapeFingerprint
110 | KeyColumn::RelationshipId
111 | KeyColumn::MigrationId
112 | KeyColumn::MigrationEventId
113 | KeyColumn::ColumnBlockId
114 | KeyColumn::PrimaryKeyId
115 | KeyColumn::IndexId => 8,
116 KeyColumn::ObjectId | KeyColumn::StorageId => 9,
117 KeyColumn::OptionU8 => 2,
118 KeyColumn::U128 | KeyColumn::Blob16 | KeyColumn::Partition | KeyColumn::IdentityId => 16,
119 KeyColumn::GroupId => 24,
120 }
121 }
122
123 fn field_exprs(self, field: &str) -> Vec<String> {
124 let u = |width: &str, expr: String| vec![format!("Field::UDesc(Width::{width}, {expr} as u128)")];
125 let cow = |expr: String| format!("::std::borrow::Cow::Borrowed({expr})");
126 match self {
127 KeyColumn::Str => vec![format!(
128 "Field::BytesDesc(ByteEncoding::Escaped, {})",
129 cow(format!("self.{field}.as_ref().as_bytes()"))
130 )],
131 KeyColumn::DisplayStr => vec![format!(
132 "Field::BytesDesc(ByteEncoding::Escaped, ::std::borrow::Cow::Owned(self.{field}.to_string().into_bytes()))"
133 )],
134 KeyColumn::EscapedBytes => vec![format!(
135 "Field::BytesDesc(ByteEncoding::Escaped, {})",
136 cow(format!("self.{field}.as_slice()"))
137 )],
138 KeyColumn::KeyspaceId => u("U8", format!("self.{field}.0")),
139 KeyColumn::RawTail => {
140 vec![format!(
141 "Field::RawAsc(RawEncoding::Verbatim, {})",
142 cow(format!("self.{field}.as_slice()"))
143 )]
144 }
145 KeyColumn::TaggedIndexId => vec![
146 format!("Field::UAsc(Width::U8, index_tag(&self.{field}) as u128)"),
147 format!("Field::UDesc(Width::U64, self.{field}.as_u64() as u128)"),
148 ],
149 KeyColumn::VarintU128 => u("Varint", format!("self.{field}")),
150 KeyColumn::SortRun => {
151 vec![format!(
152 "Field::RawAsc(RawEncoding::SortRun, {})",
153 cow(format!("self.{field}.as_slice()"))
154 )]
155 }
156 KeyColumn::AscRowNumber => vec![format!("Field::UAsc(Width::U64, self.{field}.0.0 as u128)")],
157 KeyColumn::AscU64 => vec![format!("Field::UAsc(Width::U64, self.{field}.0 as u128)")],
158 KeyColumn::U8 => u("U8", format!("self.{field}")),
159 KeyColumn::U16 => u("U16", format!("self.{field}")),
160 KeyColumn::U32 => u("U32", format!("self.{field}")),
161 KeyColumn::U64 => u("U64", format!("self.{field}")),
162 KeyColumn::U128 => u("U128", format!("self.{field}")),
163 KeyColumn::ReprU8 => u("U8", format!("self.{field} as u8")),
164 KeyColumn::RowNumber => u("U64", format!("self.{field}.0")),
165 KeyColumn::Partition => u("U128", format!("self.{field}.0")),
166 KeyColumn::ProcedureId => u("U64", format!("*self.{field}")),
167 KeyColumn::EpochSeconds => u("U64", format!("self.{field}.seconds()")),
168 KeyColumn::DateTime => u("U64", format!("self.{field}.to_order()")),
169 KeyColumn::RowShapeFingerprint | KeyColumn::IndexId => {
170 u("U64", format!("self.{field}.as_u64()"))
171 }
172 KeyColumn::GroupId => vec![format!(
173 "Field::BytesDesc(ByteEncoding::Fixed, ::std::borrow::Cow::Borrowed(self.{field}.as_bytes()))"
174 )],
175 KeyColumn::IdentityId => vec![format!(
176 "Field::BytesDesc(ByteEncoding::Escaped, ::std::borrow::Cow::Borrowed(self.{field}.as_bytes()))"
177 )],
178 KeyColumn::Blob16 => vec![format!(
179 "Field::RawAsc(RawEncoding::Verbatim, ::std::borrow::Cow::Borrowed(&self.{field}))"
180 )],
181 KeyColumn::ObjectId | KeyColumn::StorageId => vec![
182 format!("Field::UAsc(Width::U8, self.{field}.type_tag() as u128)"),
183 format!("Field::UDesc(Width::U64, self.{field}.as_u64() as u128)"),
184 ],
185 KeyColumn::OptionU8 => vec![
186 format!("Field::UDesc(Width::U8, self.{field}.is_some() as u128)"),
187 format!("Field::UDesc(Width::U8, self.{field}.unwrap_or(0u8) as u128)"),
188 ],
189 KeyColumn::TableId
190 | KeyColumn::ColumnId
191 | KeyColumn::FlowId
192 | KeyColumn::FlowEdgeId
193 | KeyColumn::OperatorId
194 | KeyColumn::HandlerId
195 | KeyColumn::NamespaceId
196 | KeyColumn::SumTypeId
197 | KeyColumn::SequenceId
198 | KeyColumn::ViewId
199 | KeyColumn::SeriesId
200 | KeyColumn::SinkId
201 | KeyColumn::WindowedViewGroupId
202 | KeyColumn::SourceId
203 | KeyColumn::QueueId
204 | KeyColumn::RingBufferId
205 | KeyColumn::BindingId
206 | KeyColumn::DictionaryId
207 | KeyColumn::ColumnPropertyId
208 | KeyColumn::RelationshipId
209 | KeyColumn::MigrationId
210 | KeyColumn::MigrationEventId
211 | KeyColumn::ColumnBlockId
212 | KeyColumn::PrimaryKeyId => u("U64", format!("self.{field}.0")),
213 }
214 }
215
216 fn encode_stmt(self, field: &str) -> String {
217 match self {
218 KeyColumn::Str => format!("serializer.extend_str(&self.{field});"),
219 KeyColumn::DisplayStr => format!("serializer.extend_str(self.{field}.to_string());"),
220 KeyColumn::EscapedBytes => format!("serializer.extend_bytes(&self.{field});"),
221 KeyColumn::KeyspaceId => format!("serializer.extend_u8(self.{field}.0);"),
222 KeyColumn::RawTail => format!("serializer.extend_raw(self.{field}.as_slice());"),
223 KeyColumn::TaggedIndexId => format!("serializer.extend_index_id(self.{field});"),
224 KeyColumn::VarintU128 => format!("serializer.extend_u128_varint(self.{field});"),
225 KeyColumn::SortRun => format!("extend_sort_run(&mut serializer, &self.{field});"),
226 KeyColumn::AscRowNumber => format!("serializer.extend_raw(&self.{field}.0.0.to_be_bytes());"),
227 KeyColumn::AscU64 => format!("serializer.extend_raw(&self.{field}.0.to_be_bytes());"),
228 KeyColumn::U8 => format!("serializer.extend_u8(self.{field});"),
229 KeyColumn::ReprU8 => format!("serializer.extend_u8(self.{field} as u8);"),
230 KeyColumn::U16 => format!("serializer.extend_u16(self.{field});"),
231 KeyColumn::U32 => format!("serializer.extend_u32(self.{field});"),
232 KeyColumn::U64 => format!("serializer.extend_u64(self.{field});"),
233 KeyColumn::U128 => format!("serializer.extend_u128(self.{field});"),
234 KeyColumn::RowNumber => format!("serializer.extend_u64(self.{field}.0);"),
235 KeyColumn::GroupId => format!("serializer.extend_fixed(*self.{field}.as_bytes());"),
236 KeyColumn::Blob16 => format!("serializer.extend_raw(&self.{field});"),
237 KeyColumn::IdentityId => format!("serializer.extend_identity_id(&self.{field});"),
238 KeyColumn::TableId
239 | KeyColumn::ColumnId
240 | KeyColumn::FlowId
241 | KeyColumn::FlowEdgeId
242 | KeyColumn::OperatorId
243 | KeyColumn::HandlerId
244 | KeyColumn::NamespaceId
245 | KeyColumn::SumTypeId
246 | KeyColumn::SequenceId
247 | KeyColumn::ViewId
248 | KeyColumn::SeriesId
249 | KeyColumn::SinkId
250 | KeyColumn::WindowedViewGroupId
251 | KeyColumn::SourceId
252 | KeyColumn::QueueId
253 | KeyColumn::RingBufferId
254 | KeyColumn::BindingId
255 | KeyColumn::DictionaryId
256 | KeyColumn::ColumnPropertyId
257 | KeyColumn::RelationshipId
258 | KeyColumn::MigrationId
259 | KeyColumn::MigrationEventId
260 | KeyColumn::ColumnBlockId
261 | KeyColumn::PrimaryKeyId => format!("serializer.extend_u64(self.{field}.0);"),
262 KeyColumn::ProcedureId => format!("serializer.extend_u64(*self.{field});"),
263 KeyColumn::EpochSeconds => format!("serializer.extend_u64(self.{field}.seconds());"),
264 KeyColumn::DateTime => format!("serializer.extend_datetime(&self.{field});"),
265 KeyColumn::RowShapeFingerprint => format!("serializer.extend_u64(self.{field}.as_u64());"),
266 KeyColumn::Partition => format!("serializer.extend_u128(self.{field}.0);"),
267 KeyColumn::IndexId => format!("serializer.extend_u64(self.{field}.as_u64());"),
268 KeyColumn::ObjectId | KeyColumn::StorageId => {
269 format!("serializer.extend_object_id(self.{field});")
270 }
271 KeyColumn::OptionU8 => format!(
272 "match self.{field} {{ Some(v) => {{ serializer.extend_u8(1u8).extend_u8(v); }} \
273 None => {{ serializer.extend_u8(0u8).extend_u8(0u8); }} }}"
274 ),
275 }
276 }
277
278 fn decode_expr(self, field_type: &str) -> String {
279 match self {
280 KeyColumn::Str => format!("{field_type}(de.read_str().ok()?)"),
281 KeyColumn::DisplayStr => {
282 format!("<{field_type} as ::core::str::FromStr>::from_str(&de.read_str().ok()?).ok()?")
283 }
284 KeyColumn::EscapedBytes => format!("{field_type}::new(de.read_bytes().ok()?)"),
285 KeyColumn::KeyspaceId => "KeyspaceId(de.read_u8().ok()?)".to_string(),
286 KeyColumn::RawTail if field_type == "Vec<u8>" => {
287 "de.read_raw(de.remaining()).ok()?.to_vec()".to_string()
288 }
289 KeyColumn::RawTail => format!("{field_type}::new(de.read_raw(de.remaining()).ok()?)"),
290 KeyColumn::TaggedIndexId => "de.read_index_id().ok()?".to_string(),
291 KeyColumn::VarintU128 => "de.read_u128_varint().ok()?".to_string(),
292 KeyColumn::SortRun => "read_sort_run(&mut de)?".to_string(),
293 KeyColumn::AscRowNumber => "read_row_tail(&mut de)?".to_string(),
294 KeyColumn::AscU64 => {
295 "Asc(u64::from_be_bytes(de.read_raw(8).ok()?.try_into().ok()?))".to_string()
296 }
297 KeyColumn::U8 => "de.read_u8().ok()?".to_string(),
298 KeyColumn::ReprU8 => format!("{field_type}::try_from(de.read_u8().ok()?).ok()?"),
299 KeyColumn::U16 => "de.read_u16().ok()?".to_string(),
300 KeyColumn::U32 => "de.read_u32().ok()?".to_string(),
301 KeyColumn::U64 => "de.read_u64().ok()?".to_string(),
302 KeyColumn::U128 => "de.read_u128().ok()?".to_string(),
303 KeyColumn::RowNumber => "RowNumber(de.read_u64().ok()?)".to_string(),
304 KeyColumn::GroupId => "GroupId::from_bytes(de.read_fixed().ok()?)".to_string(),
305 KeyColumn::Blob16 => "{ let bytes = de.read_raw(16).ok()?; let mut buf = [0u8; 16]; \
306 buf.copy_from_slice(bytes); buf }"
307 .to_string(),
308 KeyColumn::IdentityId => "de.read_identity_id().ok()?".to_string(),
309 KeyColumn::TableId
310 | KeyColumn::ColumnId
311 | KeyColumn::FlowId
312 | KeyColumn::FlowEdgeId
313 | KeyColumn::OperatorId
314 | KeyColumn::HandlerId
315 | KeyColumn::NamespaceId
316 | KeyColumn::SumTypeId
317 | KeyColumn::SequenceId
318 | KeyColumn::ViewId
319 | KeyColumn::SeriesId
320 | KeyColumn::SinkId
321 | KeyColumn::WindowedViewGroupId
322 | KeyColumn::SourceId
323 | KeyColumn::QueueId
324 | KeyColumn::RingBufferId
325 | KeyColumn::BindingId
326 | KeyColumn::DictionaryId
327 | KeyColumn::ColumnPropertyId
328 | KeyColumn::RelationshipId
329 | KeyColumn::MigrationId
330 | KeyColumn::MigrationEventId
331 | KeyColumn::ColumnBlockId
332 | KeyColumn::PrimaryKeyId => format!("{field_type}(de.read_u64().ok()?)"),
333 KeyColumn::ProcedureId => "ProcedureId::from_raw(de.read_u64().ok()?)".to_string(),
334 KeyColumn::EpochSeconds => "EpochSeconds::new(de.read_u64().ok()?)".to_string(),
335 KeyColumn::DateTime => "de.read_datetime().ok()?".to_string(),
336 KeyColumn::RowShapeFingerprint => "RowShapeFingerprint::new(de.read_u64().ok()?)".to_string(),
337 KeyColumn::Partition => "Partition(de.read_u128().ok()?)".to_string(),
338 KeyColumn::IndexId => "IndexId::Primary(PrimaryKeyId(de.read_u64().ok()?))".to_string(),
339 KeyColumn::ObjectId => "de.read_object_id().ok()?".to_string(),
340 KeyColumn::StorageId => "StorageId::from_object(de.read_object_id().ok()?)?".to_string(),
341 KeyColumn::OptionU8 => "match de.read_u8().ok()? { 1u8 => Some(de.read_u8().ok()?), 0u8 => { \
342 de.read_u8().ok()?; None }, _ => return None }"
343 .to_string(),
344 }
345 }
346}
347
348pub fn derive_key(input: TokenStream) -> TokenStream {
349 let tokens: Vec<TokenTree> = input.into_iter().collect();
350 let mut iter = tokens.iter().peekable();
351
352 let mut tag: Option<String> = None;
353 while let Some(TokenTree::Punct(p)) = iter.peek() {
354 if p.as_char() != '#' {
355 break;
356 }
357 iter.next();
358 match iter.next() {
359 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => {
360 if let Some(found) = parse_key_attribute(g) {
361 tag = Some(found);
362 }
363 }
364 _ => return compile_error("expected an attribute after '#'"),
365 }
366 }
367
368 let tag = match tag {
369 Some(tag) => tag,
370 None => return compile_error("KeyCodec requires #[key(tag = Variant)] naming its KeyTag"),
371 };
372
373 if let Some(TokenTree::Ident(i)) = iter.peek()
374 && *i == "pub"
375 {
376 iter.next();
377 if let Some(TokenTree::Group(g)) = iter.peek()
378 && g.delimiter() == Delimiter::Parenthesis
379 {
380 iter.next();
381 }
382 }
383
384 match iter.next() {
385 Some(TokenTree::Ident(i)) if *i == "struct" => {}
386 _ => return compile_error("KeyCodec can only be derived for structs"),
387 }
388
389 let name = match iter.next() {
390 Some(TokenTree::Ident(i)) => i.to_string(),
391 _ => return compile_error("expected struct name"),
392 };
393
394 let body = match iter.next() {
395 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => g.clone(),
396 Some(TokenTree::Punct(p)) if p.as_char() == '<' => {
397 return compile_error("KeyCodec cannot be derived for a generic struct");
398 }
399 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => {
400 return compile_error("KeyCodec requires named fields, so a tuple struct has no field order");
401 }
402 _ => return compile_error("expected struct body"),
403 };
404
405 let fields = match parse_fields(&body) {
406 Ok(fields) => fields,
407 Err(err) => return err,
408 };
409
410 expand(&name, &tag, &fields)
411}
412
413fn parse_key_attribute(group: &Group) -> Option<String> {
414 let tokens: Vec<TokenTree> = group.stream().into_iter().collect();
415 let mut iter = tokens.iter();
416
417 match iter.next() {
418 Some(TokenTree::Ident(i)) if *i == "key" => {}
419 _ => return None,
420 }
421
422 let inner = match iter.next() {
423 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => g.clone(),
424 _ => return None,
425 };
426
427 let inner_tokens: Vec<TokenTree> = inner.stream().into_iter().collect();
428 match inner_tokens.as_slice() {
429 [TokenTree::Ident(tag_ident), TokenTree::Punct(eq), TokenTree::Ident(variant)]
430 if *tag_ident == "tag" && eq.as_char() == '=' =>
431 {
432 Some(variant.to_string())
433 }
434 _ => None,
435 }
436}
437
438fn parse_fields(body: &Group) -> Result<Vec<KeyField>, TokenStream> {
439 let tokens: Vec<TokenTree> = body.stream().into_iter().collect();
440 let mut iter = tokens.iter().peekable();
441 let mut fields = Vec::new();
442
443 while iter.peek().is_some() {
444 let mut attribute: Option<FieldAttribute> = None;
445 while let Some(TokenTree::Punct(p)) = iter.peek() {
446 if p.as_char() == '#' {
447 iter.next();
448 if let Some(TokenTree::Group(g)) = iter.peek() {
449 if g.delimiter() == Delimiter::Bracket
450 && let Some(found) = field_attribute(g)
451 {
452 attribute = Some(found);
453 }
454 iter.next();
455 }
456 } else {
457 break;
458 }
459 }
460 if iter.peek().is_none() {
461 break;
462 }
463
464 if let Some(TokenTree::Ident(i)) = iter.peek()
465 && *i == "pub"
466 {
467 iter.next();
468 if let Some(TokenTree::Group(g)) = iter.peek()
469 && g.delimiter() == Delimiter::Parenthesis
470 {
471 iter.next();
472 }
473 }
474
475 let field_name = match iter.next() {
476 Some(TokenTree::Ident(i)) => i.to_string(),
477 _ => return Err(compile_error("expected field name")),
478 };
479
480 match iter.next() {
481 Some(TokenTree::Punct(p)) if p.as_char() == ':' => {}
482 _ => return Err(compile_error("expected ':' after field name")),
483 }
484
485 let mut ty_tokens: Vec<TokenTree> = Vec::new();
486 loop {
487 match iter.peek() {
488 Some(TokenTree::Punct(p)) if p.as_char() == ',' => {
489 iter.next();
490 break;
491 }
492 Some(t) => {
493 ty_tokens.push((*t).clone());
494 iter.next();
495 }
496 None => break,
497 }
498 }
499
500 if ty_tokens.is_empty() {
501 return Err(compile_error(&format!("field '{}' has no type", field_name)));
502 }
503
504 let ty = render(&ty_tokens);
505 let column = match attribute {
506 Some(FieldAttribute::ReprU8) => KeyColumn::ReprU8,
507 Some(FieldAttribute::Display) => KeyColumn::DisplayStr,
508 Some(FieldAttribute::Tagged) if ty.ends_with("IndexId") => KeyColumn::TaggedIndexId,
509 Some(FieldAttribute::Varint) if ty.ends_with("u128") => KeyColumn::VarintU128,
510 Some(FieldAttribute::Tagged) | Some(FieldAttribute::Varint) => {
511 return Err(compile_error(&format!(
512 "field '{}' has type '{}', which its key attribute does not apply to",
513 field_name, ty
514 )));
515 }
516 None => match column_type(&ty_tokens) {
517 Some(column) => column,
518 None => {
519 return Err(compile_error(&format!(
520 "field '{}' has type '{}', which has no flat key column type",
521 field_name, ty
522 )));
523 }
524 },
525 };
526
527 if fields.last().is_some_and(|last: &KeyField| matches!(last.column, KeyColumn::RawTail)) {
528 return Err(compile_error(&format!(
529 "field '{}' follows a raw tail, which must be the last field because it takes the rest of the key",
530 field_name
531 )));
532 }
533
534 fields.push(KeyField {
535 name: field_name,
536 column,
537 ty,
538 });
539 }
540
541 Ok(fields)
542}
543
544#[derive(Clone, Copy)]
545enum FieldAttribute {
546 ReprU8,
547 Display,
548 Tagged,
549 Varint,
550}
551
552fn field_attribute(group: &Group) -> Option<FieldAttribute> {
553 let tokens: Vec<TokenTree> = group.stream().into_iter().collect();
554 let mut iter = tokens.iter();
555
556 match iter.next() {
557 Some(TokenTree::Ident(i)) if *i == "key" => {}
558 _ => return None,
559 }
560
561 let inner = match iter.next() {
562 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => g.clone(),
563 _ => return None,
564 };
565
566 let inner_tokens: Vec<TokenTree> = inner.stream().into_iter().collect();
567 match inner_tokens.as_slice() {
568 [TokenTree::Ident(repr), TokenTree::Punct(eq), TokenTree::Ident(width)]
569 if *repr == "repr" && eq.as_char() == '=' && *width == "u8" =>
570 {
571 Some(FieldAttribute::ReprU8)
572 }
573 [TokenTree::Ident(word)] if *word == "display" => Some(FieldAttribute::Display),
574 [TokenTree::Ident(word)] if *word == "tagged" => Some(FieldAttribute::Tagged),
575 [TokenTree::Ident(word)] if *word == "varint" => Some(FieldAttribute::Varint),
576 _ => None,
577 }
578}
579
580fn column_type(tokens: &[TokenTree]) -> Option<KeyColumn> {
581 if let [TokenTree::Group(group)] = tokens {
582 return (group.delimiter() == Delimiter::Bracket && is_byte_array_16(group))
583 .then_some(KeyColumn::Blob16);
584 }
585
586 if is_option_u8(tokens) {
587 return Some(KeyColumn::OptionU8);
588 }
589
590 if is_generic_of(tokens, "Vec", "u8") {
591 return Some(KeyColumn::RawTail);
592 }
593
594 if is_generic_of(strip_path(tokens), "Asc", "RowNumber") {
595 return Some(KeyColumn::AscRowNumber);
596 }
597
598 if is_generic_of(strip_path(tokens), "Asc", "u64") {
599 return Some(KeyColumn::AscU64);
600 }
601
602 let unqualified = strip_path(tokens);
603 if unqualified.len() != 1 {
604 return None;
605 }
606
607 let head = match unqualified.first() {
608 Some(TokenTree::Ident(i)) => i.to_string(),
609 _ => return None,
610 };
611
612 match head.as_str() {
613 "u8" => Some(KeyColumn::U8),
614 "u16" => Some(KeyColumn::U16),
615 "u32" => Some(KeyColumn::U32),
616 "u64" => Some(KeyColumn::U64),
617 "u128" => Some(KeyColumn::U128),
618 "RowNumber" => Some(KeyColumn::RowNumber),
619 "GroupId" => Some(KeyColumn::GroupId),
620 "TableId" => Some(KeyColumn::TableId),
621 "ColumnId" => Some(KeyColumn::ColumnId),
622 "ObjectId" => Some(KeyColumn::ObjectId),
623 "StorageId" => Some(KeyColumn::StorageId),
624 "QueueId" => Some(KeyColumn::QueueId),
625 "RingBufferId" => Some(KeyColumn::RingBufferId),
626 "SeriesId" => Some(KeyColumn::SeriesId),
627 "DateTime" => Some(KeyColumn::DateTime),
628 "Partition" => Some(KeyColumn::Partition),
629 "FlowId" => Some(KeyColumn::FlowId),
630 "FlowEdgeId" => Some(KeyColumn::FlowEdgeId),
631 "OperatorId" => Some(KeyColumn::OperatorId),
632 "HandlerId" => Some(KeyColumn::HandlerId),
633 "NamespaceId" => Some(KeyColumn::NamespaceId),
634 "SumTypeId" => Some(KeyColumn::SumTypeId),
635 "SequenceId" => Some(KeyColumn::SequenceId),
636 "EpochSeconds" => Some(KeyColumn::EpochSeconds),
637 "IdentityId" => Some(KeyColumn::IdentityId),
638 "AuthenticationId"
639 | "AuthenticationMethodId"
640 | "IdentityAttributeId"
641 | "RoleId"
642 | "PolicyId"
643 | "TokenId" => Some(KeyColumn::U64),
644 "ViewId" => Some(KeyColumn::ViewId),
645 "SinkId" => Some(KeyColumn::SinkId),
646 "WindowedViewGroupId" => Some(KeyColumn::WindowedViewGroupId),
647 "SourceId" => Some(KeyColumn::SourceId),
648 "BindingId" => Some(KeyColumn::BindingId),
649 "DictionaryId" => Some(KeyColumn::DictionaryId),
650 "ProcedureId" => Some(KeyColumn::ProcedureId),
651 "ColumnPropertyId" => Some(KeyColumn::ColumnPropertyId),
652 "RowShapeFingerprint" => Some(KeyColumn::RowShapeFingerprint),
653 "IndexId" => Some(KeyColumn::IndexId),
654 "RelationshipId" => Some(KeyColumn::RelationshipId),
655 "MigrationId" => Some(KeyColumn::MigrationId),
656 "MigrationEventId" => Some(KeyColumn::MigrationEventId),
657 "PrimaryKeyId" => Some(KeyColumn::PrimaryKeyId),
658 "ColumnBlockId" => Some(KeyColumn::ColumnBlockId),
659 "EncodedKey" => Some(KeyColumn::EscapedBytes),
660 "KeyspaceId" => Some(KeyColumn::KeyspaceId),
661 "EncodedIndexKey" => Some(KeyColumn::RawTail),
662 "SortRun" => Some(KeyColumn::SortRun),
663 _ => None,
664 }
665}
666
667fn is_generic_of(tokens: &[TokenTree], outer: &str, inner: &str) -> bool {
668 matches!(
669 tokens,
670 [TokenTree::Ident(o), TokenTree::Punct(lt), TokenTree::Ident(u), TokenTree::Punct(gt)]
671 if *o == outer && lt.as_char() == '<' && *u == inner && gt.as_char() == '>'
672 )
673}
674
675fn is_option_u8(tokens: &[TokenTree]) -> bool {
676 matches!(
677 tokens,
678 [TokenTree::Ident(o), TokenTree::Punct(lt), TokenTree::Ident(u), TokenTree::Punct(gt)]
679 if *o == "Option" && lt.as_char() == '<' && *u == "u8" && gt.as_char() == '>'
680 )
681}
682
683fn is_byte_array_16(group: &Group) -> bool {
684 let tokens: Vec<TokenTree> = group.stream().into_iter().collect();
685 match tokens.as_slice() {
686 [TokenTree::Ident(element), TokenTree::Punct(semi), TokenTree::Literal(len)] => {
687 *element == "u8" && semi.as_char() == ';' && len.to_string() == "16"
688 }
689 _ => false,
690 }
691}
692
693fn strip_path(tokens: &[TokenTree]) -> &[TokenTree] {
694 let mut at = 0;
695 if is_colon(tokens.first()) && is_colon(tokens.get(1)) {
696 at = 2;
697 }
698 while matches!(tokens.get(at), Some(TokenTree::Ident(_)))
699 && is_colon(tokens.get(at + 1))
700 && is_colon(tokens.get(at + 2))
701 {
702 at += 3;
703 }
704 &tokens[at..]
705}
706
707fn is_colon(token: Option<&TokenTree>) -> bool {
708 matches!(token, Some(TokenTree::Punct(p)) if p.as_char() == ':')
709}
710
711fn render(tokens: &[TokenTree]) -> String {
712 tokens.iter().map(|token| token.to_string()).collect()
713}
714
715fn expand(name: &str, tag: &str, fields: &[KeyField]) -> TokenStream {
716 let capacity: usize = 1 + fields.iter().map(|f| f.column.width()).sum::<usize>();
717
718 let mut encode_body = String::new();
719 for field in fields {
720 encode_body.push_str("\t\t");
721 encode_body.push_str(&field.column.encode_stmt(&field.name));
722 encode_body.push('\n');
723 }
724
725 let mut decode_body = String::new();
726 for field in fields {
727 decode_body.push_str(&format!("\t\t\t{}: {},\n", field.name, field.column.decode_expr(&field.ty)));
728 }
729
730 let mut out = String::new();
731 out.push_str(&format!("impl {name} {{\n"));
732 out.push_str(&format!("\tpub const TAG: KeyTag = KeyTag::{tag};\n\n"));
733 out.push_str("\tpub fn encode(&self) -> EncodedKey {\n");
734 out.push_str(&format!(
735 "\t\tlet mut serializer = ::reifydb_codec::key::serializer::KeySerializer::with_capacity({capacity});\n"
736 ));
737 out.push_str("\t\tserializer.extend_u8(Self::TAG as u8);\n");
738 out.push_str(&encode_body);
739 out.push_str("\t\tserializer.to_encoded_key()\n\t}\n\n");
740 out.push_str("\tpub fn decode(key: &EncodedKey) -> Option<Self> {\n");
741 out.push_str(
742 "\t\tlet mut de = ::reifydb_codec::key::deserializer::KeyDeserializer::from_bytes(key.as_slice());\n",
743 );
744 out.push_str("\t\tlet found: KeyTag = de.read_u8().ok()?.try_into().ok()?;\n");
745 out.push_str("\t\tif found != Self::TAG {\n\t\t\treturn None;\n\t\t}\n");
746 out.push_str(&format!("\t\tlet decoded = Self {{\n{decode_body}\t\t}};\n"));
747 out.push_str("\t\tif !de.is_empty() {\n\t\t\treturn None;\n\t\t}\n");
748 out.push_str("\t\tSome(decoded)\n\t}\n}\n\n");
749
750 out.push_str(&format!("#[automatically_derived]\nimpl KeyFields for {name} {{\n"));
751 out.push_str("\tfn fields(&self) -> ::smallvec::SmallVec<[Field<'_>; 6]> {\n");
752 out.push_str("\t\t::smallvec::smallvec![\n");
753 for field in fields {
754 for expr in field.column.field_exprs(&field.name) {
755 out.push_str(&format!("\t\t\t{expr},\n"));
756 }
757 }
758 out.push_str("\t\t]\n\t}\n}\n\n");
759 out.push_str(&format!("#[automatically_derived]\nimpl {name} {{\n"));
760 out.push_str("\tpub fn cmp_fields(&self, other: &Self) -> ::core::cmp::Ordering {\n");
761 for field in fields {
762 for expr in field.column.field_exprs(&field.name) {
763 let theirs = expr.replace("self.", "other.");
764 out.push_str(&format!(
765 "\t\tmatch Ord::cmp(&{expr}, &{theirs}) {{\n\t\t\t::core::cmp::Ordering::Equal => {{}}\n\t\t\tordering => return ordering,\n\t\t}}\n"
766 ));
767 }
768 }
769 out.push_str("\t\t::core::cmp::Ordering::Equal\n\t}\n}\n\n");
770 out.push_str(&expand_tests(name, fields));
771
772 out.parse().expect("derived key impl must be valid Rust")
773}
774
775#[cfg(test)]
776mod tests {
777 use super::derive_key;
778
779 fn expand(source: &str) -> String {
780 derive_key(source.parse().unwrap()).to_string()
781 }
782
783 #[test]
784 fn missing_attribute_is_rejected() {
785 let out = expand("struct RowKey { row: u64 }");
786 assert!(out.contains("compile_error"), "{out}");
787 assert!(out.contains("key"), "{out}");
788 }
789
790 #[test]
791 fn a_well_formed_struct_expands_without_an_error() {
792 let out = expand("#[key(tag = Row)] struct RowKey { table: u64, row: RowNumber }");
793 assert!(!out.contains("compile_error"), "{out}");
794 assert!(out.contains("impl RowKey { pub const TAG"), "{out}");
795 assert!(out.contains("KeyTag :: Row"), "{out}");
796 }
797
798 #[test]
799 fn fields_are_encoded_in_declaration_order() {
800 let out = expand("#[key(tag = Row)] struct RowKey { table: u64, row: RowNumber }");
801 let table = out.find("self . table").expect("table field encoded");
802 let row = out.find("self . row").expect("row field encoded");
803 assert!(table < row, "{out}");
804 }
805
806 #[test]
807 fn a_repr_u8_field_encodes_the_discriminant_and_decodes_through_try_from() {
808 let out = expand("#[key(tag = SystemVersion)] struct K { #[key(repr = u8)] version: SystemVersion }");
811 assert!(!out.contains("compile_error"), "{out}");
812 assert!(out.contains("extend_u8 (self . version as u8)"), "{out}");
813 assert!(out.contains("SystemVersion :: try_from"), "{out}");
814 }
815
816 #[test]
817 fn a_repr_u8_field_still_rejects_a_type_the_attribute_was_not_put_on() {
818 let out = expand("#[key(tag = SystemVersion)] struct K { version: SystemVersion }");
819 assert!(out.contains("compile_error"), "{out}");
820 }
821
822 #[test]
823 fn an_unrecognised_field_type_is_rejected() {
824 let out = expand("#[key(tag = Row)] struct RowKey { at: String }");
825 assert!(out.contains("compile_error"), "{out}");
826 assert!(out.contains("at"), "{out}");
827 assert!(out.contains("String"), "{out}");
828 }
829
830 #[test]
831 fn a_tuple_struct_is_rejected() {
832 let out = expand("#[key(tag = Row)] struct RowKey(u64);");
833 assert!(out.contains("compile_error"), "{out}");
834 }
835
836 #[test]
837 fn a_generic_struct_is_rejected() {
838 let out = expand("#[key(tag = Row)] struct RowKey<T> { row: T }");
839 assert!(out.contains("compile_error"), "{out}");
840 }
841
842 #[test]
843 fn a_byte_array_field_maps_to_blob16() {
844 let out = expand("#[key(tag = Row)] struct RowKey { blob: [u8; 16] }");
845 assert!(!out.contains("compile_error"), "{out}");
846 assert!(out.contains("extend_raw"));
847 }
848
849 #[test]
850 fn a_byte_array_of_the_wrong_width_is_rejected() {
851 let out = expand("#[key(tag = Row)] struct RowKey { blob: [u8; 32] }");
852 assert!(out.contains("compile_error"), "{out}");
853 }
854
855 #[test]
856 fn table_id_and_column_id_encode_via_their_wrapped_u64() {
857 let out = expand("#[key(tag = Table)] struct TableKey { table: TableId, column: ColumnId }");
858 assert!(!out.contains("compile_error"), "{out}");
859 assert!(out.contains("self . table . 0"), "{out}");
860 assert!(out.contains("TableId (de . read_u64 () . ok () ?)"), "{out}");
861 assert!(out.contains("ColumnId (de . read_u64 () . ok () ?)"), "{out}");
862 }
863
864 #[test]
865 fn an_option_u8_field_encodes_as_a_fixed_two_byte_presence_and_value_pair() {
866 let out = expand("#[key(tag = Row)] struct RowKey { tag: Option<u8> }");
867 assert!(!out.contains("compile_error"), "{out}");
868 assert!(out.contains("with_capacity (3)"), "{out}: width must stay fixed at 2 bytes for None and Some");
869 assert!(out.contains("Some (v) => { serializer . extend_u8 (1u8) . extend_u8 (v) ; }"), "{out}");
870 assert!(out.contains("None => { serializer . extend_u8 (0u8) . extend_u8 (0u8) ; }"), "{out}");
871 assert!(out.contains("1u8 => Some (de . read_u8 () . ok () ?)"), "{out}");
872 assert!(out.contains("0u8 => { de . read_u8 () . ok () ?; None }"), "{out}");
873 }
874
875 #[test]
876 fn object_id_and_storage_id_encode_via_the_catalog_ext() {
877 let out = expand("#[key(tag = Row)] struct RowKey { storage: StorageId, object: ObjectId }");
878 assert!(!out.contains("compile_error"), "{out}");
879 assert!(out.contains("extend_object_id (self . storage)"), "{out}");
880 assert!(out.contains("extend_object_id (self . object)"), "{out}");
881 assert!(out.contains("StorageId :: from_object (de . read_object_id () . ok () ?) ?"), "{out}");
882 assert!(out.contains("de . read_object_id () . ok () ?"), "{out}");
883 }
884}