@@ -12,13 +12,15 @@ extern crate core;
12
12
extern crate proc_macro;
13
13
14
14
use bitflags:: Flags ;
15
+ use heck:: ToSnakeCase ;
15
16
use module:: { derive_deserialize, derive_satstype, derive_serialize} ;
16
17
use proc_macro:: TokenStream as StdTokenStream ;
17
18
use proc_macro2:: { Span , TokenStream } ;
18
19
use quote:: { format_ident, quote, quote_spanned} ;
19
20
use spacetimedb_primitives:: ColumnAttribute ;
20
21
use std:: collections:: HashMap ;
21
22
use std:: time:: Duration ;
23
+ use syn:: ext:: IdentExt ;
22
24
use syn:: meta:: ParseNestedMeta ;
23
25
use syn:: parse:: { Parse , ParseStream , Parser } ;
24
26
use syn:: punctuated:: Punctuated ;
@@ -189,8 +191,8 @@ impl LifecycleReducer {
189
191
fn reducer_name ( & self ) -> & ' static str {
190
192
match self {
191
193
Self :: Init => "__init__" ,
192
- Self :: ClientConnected => "__client_connected__ " ,
193
- Self :: ClientDisconnected => "__client_disconnected__ " ,
194
+ Self :: ClientConnected => "__identity_connected__ " ,
195
+ Self :: ClientDisconnected => "__identity_disconnected__ " ,
194
196
Self :: Update => "__update__" ,
195
197
}
196
198
}
@@ -316,26 +318,6 @@ fn reducer_impl(args: ReducerArgs, original_function: &ItemFn) -> syn::Result<To
316
318
}
317
319
} ;
318
320
319
- // let errmsg = "reducer should have at least 2 arguments: (identity: Identity, timestamp: u64, ...)";
320
- // let ([arg1, arg2], args) = validate_reducer_args(&original_function.sig, errmsg)?;
321
-
322
- // // TODO: better (non-string-based) validation for these
323
- // if !matches!(
324
- // &*arg1.to_token_stream().to_string(),
325
- // "spacetimedb::spacetimedb_sats::hash::Hash" | "Hash"
326
- // ) {
327
- // return Err(syn::Error::new_spanned(
328
- // &arg1,
329
- // "1st parameter of a reducer must be of type \'u64\'.",
330
- // ));
331
- // }
332
- // if arg2.to_token_stream().to_string() != "u64" {
333
- // return Err(syn::Error::new_spanned(
334
- // &arg2,
335
- // "2nd parameter of a reducer must be of type \'u64\'.",
336
- // ));
337
- // }
338
-
339
321
// Extract all function parameters, except for `self` ones that aren't allowed.
340
322
let typed_args = original_function
341
323
. sig
@@ -400,11 +382,10 @@ fn reducer_impl(args: ReducerArgs, original_function: &ItemFn) -> syn::Result<To
400
382
} )
401
383
}
402
384
403
- #[ derive( Default ) ]
404
385
struct TableArgs {
405
386
public : Option < Span > ,
406
387
scheduled : Option < Path > ,
407
- name : Option < Ident > ,
388
+ name : Ident ,
408
389
indices : Vec < IndexArg > ,
409
390
}
410
391
@@ -443,9 +424,12 @@ enum IndexType {
443
424
}
444
425
445
426
impl TableArgs {
446
- fn parse ( input : TokenStream ) -> syn:: Result < Self > {
427
+ fn parse ( input : TokenStream , struct_ident : & Ident ) -> syn:: Result < Self > {
447
428
let mut specified_access = false ;
448
- let mut args = TableArgs :: default ( ) ;
429
+ let mut public = None ;
430
+ let mut scheduled = None ;
431
+ let mut name = None ;
432
+ let mut indices = Vec :: new ( ) ;
449
433
syn:: meta:: parser ( |meta| {
450
434
let mut specified_access = || {
451
435
if specified_access {
@@ -457,28 +441,40 @@ impl TableArgs {
457
441
match_meta ! ( match meta {
458
442
sym:: public => {
459
443
specified_access( ) ?;
460
- args . public = Some ( meta. path. span( ) ) ;
444
+ public = Some ( meta. path. span( ) ) ;
461
445
}
462
446
sym:: private => {
463
447
specified_access( ) ?;
464
448
}
465
449
sym:: name => {
466
- check_duplicate( & args . name, & meta) ?;
450
+ check_duplicate( & name, & meta) ?;
467
451
let value = meta. value( ) ?;
468
- args . name = Some ( value. parse( ) ?) ;
452
+ name = Some ( value. parse( ) ?) ;
469
453
}
470
- sym:: index => args . indices. push( IndexArg :: parse_meta( meta) ?) ,
454
+ sym:: index => indices. push( IndexArg :: parse_meta( meta) ?) ,
471
455
sym:: scheduled => {
472
- check_duplicate( & args . scheduled, & meta) ?;
456
+ check_duplicate( & scheduled, & meta) ?;
473
457
let in_parens;
474
458
syn:: parenthesized!( in_parens in meta. input) ;
475
- args . scheduled = Some ( in_parens. parse:: <Path >( ) ?) ;
459
+ scheduled = Some ( in_parens. parse:: <Path >( ) ?) ;
476
460
}
477
461
} ) ;
478
462
Ok ( ( ) )
479
463
} )
480
464
. parse2 ( input) ?;
481
- Ok ( args)
465
+ let name = name. ok_or_else ( || {
466
+ let table = struct_ident. to_string ( ) . to_snake_case ( ) ;
467
+ syn:: Error :: new (
468
+ Span :: call_site ( ) ,
469
+ format_args ! ( "must specify table name, e.g. `#[spacetimedb::table(name = {table})]" ) ,
470
+ )
471
+ } ) ?;
472
+ Ok ( TableArgs {
473
+ public,
474
+ scheduled,
475
+ name,
476
+ indices,
477
+ } )
482
478
}
483
479
}
484
480
@@ -586,7 +582,7 @@ impl IndexArg {
586
582
/// # Example
587
583
///
588
584
/// ```ignore
589
- /// #[spacetimedb::table(public, name = Users )]
585
+ /// #[spacetimedb::table(name = users, public )]
590
586
/// pub struct User {
591
587
/// #[auto_inc]
592
588
/// #[primary_key]
@@ -654,7 +650,7 @@ pub fn table(args: StdTokenStream, item: StdTokenStream) -> StdTokenStream {
654
650
// put this on the struct so we don't get unknown attribute errors
655
651
let extra_attr = quote ! ( #[ derive( spacetimedb:: __TableHelper) ] ) ;
656
652
cvt_attr :: < syn:: DeriveInput > ( args, item, extra_attr, |args, item| {
657
- let args = TableArgs :: parse ( args) ?;
653
+ let args = TableArgs :: parse ( args, & item . ident ) ?;
658
654
table_impl ( args, item)
659
655
} )
660
656
}
@@ -717,15 +713,10 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
717
713
reducer_type_check ( & item, reducer)
718
714
} ) ;
719
715
720
- let mut sats_ty = module:: sats_type_from_derive ( & item, quote ! ( spacetimedb:: spacetimedb_lib) ) ?;
716
+ let sats_ty = module:: sats_type_from_derive ( & item, quote ! ( spacetimedb:: spacetimedb_lib) ) ?;
721
717
722
718
let original_struct_ident = sats_ty. ident ;
723
- // TODO: error on setting sats name for a table
724
- let table_name = args
725
- . name
726
- . map ( |s| s. to_string ( ) )
727
- . unwrap_or_else ( || original_struct_ident. to_string ( ) ) ;
728
- sats_ty. name . clone_from ( & table_name) ;
719
+ let table_name = args. name . unraw ( ) . to_string ( ) ;
729
720
let module:: SatsTypeData :: Product ( fields) = & sats_ty. data else {
730
721
return Err ( syn:: Error :: new ( Span :: call_site ( ) , "spacetimedb table must be a struct" ) ) ;
731
722
} ;
@@ -858,7 +849,7 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
858
849
859
850
Some ( quote ! {
860
851
// TODO: should we expose spacetimedb::query::FilterByIter ?
861
- #vis fn #filter_func_ident< ' a> ( #column_ident: & #column_type) -> impl Iterator <Item = Self > {
852
+ #vis fn #filter_func_ident( #column_ident: & #column_type) -> impl Iterator <Item = Self > {
862
853
spacetimedb:: query:: filter_by_field:: <Self , #column_type, #column_index>( #column_ident)
863
854
}
864
855
#vis fn #delete_func_ident( #column_ident: & #column_type) -> u32 {
@@ -896,7 +887,7 @@ fn table_impl(mut args: TableArgs, mut item: MutItem<syn::DeriveInput>) -> syn::
896
887
897
888
let deserialize_impl = derive_deserialize ( & sats_ty) ;
898
889
let serialize_impl = derive_serialize ( & sats_ty) ;
899
- let schema_impl = derive_satstype ( & sats_ty, false ) ;
890
+ let schema_impl = derive_satstype ( & sats_ty, * original_struct_ident != table_name ) ;
900
891
let column_attrs = columns. iter ( ) . map ( |col| {
901
892
Ident :: new (
902
893
ColumnAttribute :: FLAGS
@@ -1309,7 +1300,7 @@ impl ClosureLike {
1309
1300
/// ```ignore // unfortunately, doctest doesn't work well inside proc-macro
1310
1301
/// use spacetimedb::query;
1311
1302
///
1312
- /// #[spacetimedb::table]
1303
+ /// #[spacetimedb::table(name = people) ]
1313
1304
/// pub struct Person {
1314
1305
/// name: String,
1315
1306
/// age: u32,
0 commit comments