@@ -15,7 +15,7 @@ use heck::ToSnakeCase;
1515use module:: { derive_deserialize, derive_satstype, derive_serialize} ;
1616use proc_macro:: TokenStream as StdTokenStream ;
1717use proc_macro2:: { Span , TokenStream } ;
18- use quote:: { format_ident, quote, quote_spanned} ;
18+ use quote:: { format_ident, quote, quote_spanned, ToTokens } ;
1919use std:: collections:: HashMap ;
2020use std:: time:: Duration ;
2121use syn:: ext:: IdentExt ;
@@ -567,12 +567,8 @@ impl IndexArg {
567567 Ok ( IndexArg { kind, name } )
568568 }
569569
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 {
576572 IndexType :: BTree { columns } => {
577573 let cols = columns
578574 . iter ( )
@@ -585,28 +581,98 @@ impl IndexArg {
585581 } )
586582 . collect :: < syn:: Result < Vec < _ > > > ( ) ?;
587583
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 } => {
588615 let col_ids = cols. iter ( ) . map ( |col| col. index ) ;
589- let algo = quote ! ( spacetimedb:: table:: IndexAlgo :: BTree {
616+ quote ! ( spacetimedb:: table:: IndexAlgo :: BTree {
590617 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+ }
592629
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 ;
594634 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> {
597655 spacetimedb:: BTreeIndex :: __new( )
598656 }
599- } ;
657+ }
658+ }
659+ }
660+ }
600661
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+ }
602674 }
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+ }
610676 }
611677}
612678
@@ -821,16 +887,15 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
821887
822888 let row_type = quote ! ( #original_struct_ident) ;
823889
824- let ( indexes , index_accessors ) = args
890+ let indices = args
825891 . indices
826892 . 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 ( ) ) ;
834899
835900 let unique_field_accessors = unique_columns. iter ( ) . map ( |unique| {
836901 let column_index = unique. index ;
@@ -907,7 +972,7 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
907972 // the default value if not specified is Private
908973 #( const TABLE_ACCESS : spacetimedb:: table:: TableAccess = #table_access; ) *
909974 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 ) , * ] ;
911976 #( const PRIMARY_KEY : Option <u16 > = Some ( #primary_col_id) ; ) *
912977 const SEQUENCES : & ' static [ u16 ] = & [ #( #sequence_col_ids) , * ] ;
913978 #( 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::
10061071
10071072 #tabletype_impl
10081073
1074+ #[ allow( non_camel_case_types) ]
1075+ mod __indices {
1076+ #( #index_marker_types) *
1077+ }
1078+
10091079 #describe_table_func
10101080 } ;
10111081
0 commit comments