@@ -15,7 +15,7 @@ use heck::ToSnakeCase;
15
15
use module:: { derive_deserialize, derive_satstype, derive_serialize} ;
16
16
use proc_macro:: TokenStream as StdTokenStream ;
17
17
use proc_macro2:: { Span , TokenStream } ;
18
- use quote:: { format_ident, quote, quote_spanned} ;
18
+ use quote:: { format_ident, quote, quote_spanned, ToTokens } ;
19
19
use std:: collections:: HashMap ;
20
20
use std:: time:: Duration ;
21
21
use syn:: ext:: IdentExt ;
@@ -567,12 +567,8 @@ impl IndexArg {
567
567
Ok ( IndexArg { kind, name } )
568
568
}
569
569
570
- fn to_desc_and_accessor (
571
- & self ,
572
- index_index : u32 ,
573
- cols : & [ Column ] ,
574
- ) -> Result < ( TokenStream , TokenStream ) , syn:: Error > {
575
- let ( algo, accessor) = match & self . kind {
570
+ fn validate < ' a > ( & ' a self , table_name : & str , cols : & ' a [ Column < ' a > ] ) -> syn:: Result < ValidatedIndex < ' _ > > {
571
+ let kind = match & self . kind {
576
572
IndexType :: BTree { columns } => {
577
573
let cols = columns
578
574
. iter ( )
@@ -585,28 +581,98 @@ impl IndexArg {
585
581
} )
586
582
. collect :: < syn:: Result < Vec < _ > > > ( ) ?;
587
583
584
+ ValidatedIndexType :: BTree { cols }
585
+ }
586
+ } ;
587
+ let index_name = match & kind {
588
+ ValidatedIndexType :: BTree { cols } => ( [ table_name, "btree" ] . into_iter ( ) )
589
+ . chain ( cols. iter ( ) . map ( |col| col. field . name . as_deref ( ) . unwrap ( ) ) )
590
+ . collect :: < Vec < _ > > ( )
591
+ . join ( "_" ) ,
592
+ } ;
593
+ Ok ( ValidatedIndex {
594
+ index_name,
595
+ accessor_name : & self . name ,
596
+ kind,
597
+ } )
598
+ }
599
+ }
600
+
601
+ struct ValidatedIndex < ' a > {
602
+ index_name : String ,
603
+ accessor_name : & ' a Ident ,
604
+ kind : ValidatedIndexType < ' a > ,
605
+ }
606
+
607
+ enum ValidatedIndexType < ' a > {
608
+ BTree { cols : Vec < & ' a Column < ' a > > } ,
609
+ }
610
+
611
+ impl ValidatedIndex < ' _ > {
612
+ fn desc ( & self ) -> TokenStream {
613
+ let algo = match & self . kind {
614
+ ValidatedIndexType :: BTree { cols } => {
588
615
let col_ids = cols. iter ( ) . map ( |col| col. index ) ;
589
- let algo = quote ! ( spacetimedb:: table:: IndexAlgo :: BTree {
616
+ quote ! ( spacetimedb:: table:: IndexAlgo :: BTree {
590
617
columns: & [ #( #col_ids) , * ]
591
- } ) ;
618
+ } )
619
+ }
620
+ } ;
621
+ let index_name = & self . index_name ;
622
+ let accessor_name = ident_to_litstr ( self . accessor_name ) ;
623
+ quote ! ( spacetimedb:: table:: IndexDesc {
624
+ name: #index_name,
625
+ accessor_name: #accessor_name,
626
+ algo: #algo,
627
+ } )
628
+ }
592
629
593
- let index_ident = & self . name ;
630
+ fn accessor ( & self , vis : & syn:: Visibility , row_type_ident : & Ident ) -> TokenStream {
631
+ match & self . kind {
632
+ ValidatedIndexType :: BTree { cols } => {
633
+ let index_ident = self . accessor_name ;
594
634
let col_tys = cols. iter ( ) . map ( |col| col. ty ) ;
595
- let accessor = quote ! {
596
- fn #index_ident( & self ) -> spacetimedb:: BTreeIndex <Self , ( #( #col_tys, ) * ) , #index_index> {
635
+ let doc_columns = cols
636
+ . iter ( )
637
+ . map ( |col| {
638
+ format ! (
639
+ "- [`{ident}`][{row_type_ident}#structfield.{ident}]: [`{ty}`]\n " ,
640
+ ident = col. field. ident. unwrap( ) ,
641
+ ty = col. ty. to_token_stream( )
642
+ )
643
+ } )
644
+ . collect :: < String > ( ) ;
645
+ let doc = format ! (
646
+ "Gets the `{index_ident}` [`BTreeIndex`][spacetimedb::BTreeIndex] as defined \
647
+ on this table. \n \
648
+ \n \
649
+ This B-tree index is defined on the following columns, in order:\n \
650
+ {doc_columns}"
651
+ ) ;
652
+ quote ! {
653
+ #[ doc = #doc]
654
+ #vis fn #index_ident( & self ) -> spacetimedb:: BTreeIndex <Self , ( #( #col_tys, ) * ) , __indices:: #index_ident> {
597
655
spacetimedb:: BTreeIndex :: __new( )
598
656
}
599
- } ;
657
+ }
658
+ }
659
+ }
660
+ }
600
661
601
- ( algo, accessor)
662
+ fn marker_type ( & self ) -> TokenStream {
663
+ let index_ident = self . accessor_name ;
664
+ let index_name = & self . index_name ;
665
+ quote ! {
666
+ pub struct #index_ident;
667
+ impl spacetimedb:: table:: Index for #index_ident {
668
+ fn index_id( ) -> spacetimedb:: table:: IndexId {
669
+ static INDEX_ID : std:: sync:: OnceLock <spacetimedb:: table:: IndexId > = std:: sync:: OnceLock :: new( ) ;
670
+ * INDEX_ID . get_or_init( || {
671
+ spacetimedb:: sys:: index_id_from_name( #index_name) . unwrap( )
672
+ } )
673
+ }
602
674
}
603
- } ;
604
- let accessor_name = ident_to_litstr ( & self . name ) ;
605
- let desc = quote ! ( spacetimedb:: table:: IndexDesc {
606
- accessor_name: #accessor_name,
607
- algo: #algo,
608
- } ) ;
609
- Ok ( ( desc, accessor) )
675
+ }
610
676
}
611
677
}
612
678
@@ -821,16 +887,15 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
821
887
822
888
let row_type = quote ! ( #original_struct_ident) ;
823
889
824
- let ( indexes , index_accessors ) = args
890
+ let indices = args
825
891
. indices
826
892
. iter ( )
827
- . enumerate ( )
828
- . map ( |( i, index) | index. to_desc_and_accessor ( i as u32 , & columns) )
829
- // TODO: stabilized in 1.79
830
- // .collect::<syn::Result<(Vec<_>, Vec<_>)>>()?;
831
- . collect :: < syn:: Result < Vec < _ > > > ( ) ?
832
- . into_iter ( )
833
- . unzip :: < _ , _ , Vec < _ > , Vec < _ > > ( ) ;
893
+ . map ( |index| index. validate ( & table_name, & columns) )
894
+ . collect :: < syn:: Result < Vec < _ > > > ( ) ?;
895
+
896
+ let index_descs = indices. iter ( ) . map ( |index| index. desc ( ) ) ;
897
+ let index_accessors = indices. iter ( ) . map ( |index| index. accessor ( vis, original_struct_ident) ) ;
898
+ let index_marker_types = indices. iter ( ) . map ( |index| index. marker_type ( ) ) ;
834
899
835
900
let unique_field_accessors = unique_columns. iter ( ) . map ( |unique| {
836
901
let column_index = unique. index ;
@@ -907,7 +972,7 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
907
972
// the default value if not specified is Private
908
973
#( const TABLE_ACCESS : spacetimedb:: table:: TableAccess = #table_access; ) *
909
974
const UNIQUE_COLUMNS : & ' static [ u16 ] = & [ #( #unique_col_ids) , * ] ;
910
- const INDEXES : & ' static [ spacetimedb:: table:: IndexDesc <' static >] = & [ #( #indexes ) , * ] ;
975
+ const INDEXES : & ' static [ spacetimedb:: table:: IndexDesc <' static >] = & [ #( #index_descs ) , * ] ;
911
976
#( const PRIMARY_KEY : Option <u16 > = Some ( #primary_col_id) ; ) *
912
977
const SEQUENCES : & ' static [ u16 ] = & [ #( #sequence_col_ids) , * ] ;
913
978
#( const SCHEDULED_REDUCER_NAME : Option <& ' static str > = Some ( <#scheduled_reducer_ident as spacetimedb:: rt:: ReducerInfo >:: NAME ) ; ) *
@@ -1006,6 +1071,11 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
1006
1071
1007
1072
#tabletype_impl
1008
1073
1074
+ #[ allow( non_camel_case_types) ]
1075
+ mod __indices {
1076
+ #( #index_marker_types) *
1077
+ }
1078
+
1009
1079
#describe_table_func
1010
1080
} ;
1011
1081
0 commit comments