Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Rust module documentation #2050

Merged
merged 9 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 7 additions & 172 deletions crates/bindings-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
//! Defines procedural macros like `#[spacetimedb::table]`,
//! simplifying writing SpacetimeDB modules in Rust.

// DO NOT WRITE (public) DOCS IN THIS MODULE.
// Docs should be written in the `spacetimedb` crate (i.e. `bindings/`) at reexport sites
// using `#[doc(inline)]`.
// We do this so that links to library traits, structs, etc can resolve correctly.
//
// (private documentation for the macro authors is totally fine here and you SHOULD write that!)

mod reducer;
mod sats;
mod table;
Expand Down Expand Up @@ -96,76 +103,6 @@ mod sym {
}
}

/// Marks a function as a spacetimedb reducer.
///
/// A reducer is a function which traverses and updates the database,
/// a sort of stored procedure that lives in the database, and which can be invoked remotely.
/// Each reducer call runs in its own transaction,
/// and its updates to the database are only committed if the reducer returns successfully.
///
/// A reducer may take no arguments, like so:
///
/// ```rust,ignore
/// #[spacetimedb::reducer]
/// pub fn hello_world() {
/// println!("Hello, World!");
/// }
/// ```
///
/// But it may also take some:
/// ```rust,ignore
/// #[spacetimedb::reducer]
/// pub fn add_person(name: String, age: u16) {
/// // Logic to add a person with `name` and `age`.
/// }
/// ```
///
/// Reducers cannot return values, but can return errors.
/// To do so, a reducer must have a return type of `Result<(), impl Debug>`.
/// When such an error occurs, it will be formatted and printed out to logs,
/// resulting in an aborted transaction.
///
/// # Lifecycle Reducers
///
/// You can specify special lifecycle reducers that are run at set points in
/// the module's lifecycle. You can have one each per module.
///
/// ## `#[spacetimedb::reducer(init)]`
///
/// This reducer is run the first time a module is published
/// and anytime the database is cleared.
///
/// The reducer cannot be called manually
/// and may not have any parameters except for `ReducerContext`.
/// If an error occurs when initializing, the module will not be published.
///
/// ## `#[spacetimedb::reducer(client_connected)]`
///
/// This reducer is run when a client connects to the SpacetimeDB module.
/// Their identity can be found in the sender value of the `ReducerContext`.
///
/// The reducer cannot be called manually
/// and may not have any parameters except for `ReducerContext`.
/// If an error occurs in the reducer, the client will be disconnected.
///
///
/// ## `#[spacetimedb::reducer(client_disconnected)]`
///
/// This reducer is run when a client disconnects from the SpacetimeDB module.
/// Their identity can be found in the sender value of the `ReducerContext`.
///
/// The reducer cannot be called manually
/// and may not have any parameters except for `ReducerContext`.
/// If an error occurs in the disconnect reducer,
/// the client is still recorded as disconnected.
///
/// ## `#[spacetimedb::reducer(update)]`
///
/// This reducer is run when the module is updated,
/// i.e., when publishing a module for a database that has already been initialized.
///
/// The reducer cannot be called manually and may not have any parameters.
/// If an error occurs when initializing, the module will not be published.
#[proc_macro_attribute]
pub fn reducer(args: StdTokenStream, item: StdTokenStream) -> StdTokenStream {
cvt_attr::<ItemFn>(args, item, quote!(), |args, original_function| {
Expand All @@ -190,77 +127,6 @@ fn derive_table_helper_attr() -> Attribute {
.unwrap()
}

/// Generates code for treating this struct type as a table.
///
/// Among other things, this derives `Serialize`, `Deserialize`,
/// `SpacetimeType`, and `Table` for our type.
///
/// # Example
///
/// ```ignore
/// #[spacetimedb::table(name = users, public)]
/// pub struct User {
/// #[auto_inc]
/// #[primary_key]
/// pub id: u32,
/// #[unique]
/// pub username: String,
/// #[index(btree)]
/// pub popularity: u32,
/// }
/// ```
///
/// # Macro arguments
///
/// * `public` and `private`
///
/// Tables are private by default. If you'd like to make your table publically
/// accessible by anyone, put `public` in the macro arguments (e.g.
/// `#[spacetimedb::table(public)]`). You can also specify `private` if
/// you'd like to be specific. This is fully separate from Rust's module visibility
/// system; `pub struct` or `pub(crate) struct` do not affect the table visibility, only
/// the visibility of the items in your own source code.
///
/// * `index(name = my_index, btree(columns = [a, b, c]))`
///
/// You can specify an index on 1 or more of the table's columns with the above syntax.
/// You can also just put `#[index(btree)]` on the field itself if you only need
/// a single-column attribute; see column attributes below.
///
/// * `name = my_table`
///
/// Specify the name of the table in the database, if you want it to be different from
/// the name of the struct.
///
/// # Column (field) attributes
///
/// * `#[auto_inc]`
///
/// Creates a database sequence.
///
/// When a row is inserted with the annotated field set to `0` (zero),
/// the sequence is incremented, and this value is used instead.
/// Can only be used on numeric types and may be combined with indexes.
///
/// Note that using `#[auto_inc]` on a field does not also imply `#[primary_key]` or `#[unique]`.
/// If those semantics are desired, those attributes should also be used.
///
/// * `#[unique]`
///
/// Creates an index and unique constraint for the annotated field.
///
/// * `#[primary_key]`
///
/// Similar to `#[unique]`, but generates additional CRUD methods.
///
/// * `#[index(btree)]`
///
/// Creates a single-column index with the specified algorithm.
///
/// [`Serialize`]: https://docs.rs/spacetimedb/latest/spacetimedb/trait.Serialize.html
/// [`Deserialize`]: https://docs.rs/spacetimedb/latest/spacetimedb/trait.Deserialize.html
/// [`SpacetimeType`]: https://docs.rs/spacetimedb/latest/spacetimedb/trait.SpacetimeType.html
/// [`TableType`]: https://docs.rs/spacetimedb/latest/spacetimedb/trait.TableType.html
#[proc_macro_attribute]
pub fn table(args: StdTokenStream, item: StdTokenStream) -> StdTokenStream {
// put this on the struct so we don't get unknown attribute errors
Expand Down Expand Up @@ -376,37 +242,6 @@ pub fn schema_type(input: StdTokenStream) -> StdTokenStream {
})
}

/// Generates code for registering a row-level security rule.
///
/// This attribute must be applied to a `const` binding of type [`Filter`].
/// It will be interpreted as a filter on the table to which it applies, for all client queries.
/// If a module contains multiple `client_visibility_filter`s for the same table,
/// they will be unioned together as if by SQL `OR`,
/// so that any row permitted by at least one filter is visible.
///
/// The `const` binding's identifier must be unique within the module.
///
/// The query follows the same syntax as a subscription query.
///
/// ## Example:
///
/// ```rust,ignore
/// /// Players can only see what's in their chunk
/// #[spacetimedb::client_visibility_filter]
/// const PLAYERS_SEE_ENTITIES_IN_SAME_CHUNK: Filter = Filter::Sql("
/// SELECT * FROM LocationState WHERE chunk_index IN (
/// SELECT chunk_index FROM LocationState WHERE entity_id IN (
/// SELECT entity_id FROM UserState WHERE identity = @sender
/// )
/// )
/// ");
/// ```
///
/// Queries are not checked for syntactic or semantic validity
/// until they are processed by the SpacetimeDB host.
/// This means that errors in queries, such as syntax errors, type errors or unknown tables,
/// will be reported during `spacetime publish`, not at compile time.
#[doc(hidden)] // TODO: RLS filters are currently unimplemented, and are not enforced.
#[proc_macro_attribute]
pub fn client_visibility_filter(args: StdTokenStream, item: StdTokenStream) -> StdTokenStream {
ok_or_compile_error(|| {
Expand Down
8 changes: 4 additions & 4 deletions crates/bindings-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ pub mod raw {
pub fn bytes_source_read(source: BytesSource, buffer_ptr: *mut u8, buffer_len_ptr: *mut usize) -> i16;

/// Logs at `level` a `message` message occuring in `filename:line_number`
/// with [`target`](target) being the module path at the `log!` invocation site.
/// with `target` being the module path at the `log!` invocation site.
///
/// These various pointers are interpreted lossily as UTF-8 strings with a corresponding `_len`.
///
Expand Down Expand Up @@ -592,7 +592,7 @@ pub mod raw {

/// What strategy does the database index use?
///
/// See also: https://www.postgresql.org/docs/current/sql-createindex.html
/// See also: <https://www.postgresql.org/docs/current/sql-createindex.html>
#[repr(u8)]
#[non_exhaustive]
pub enum IndexType {
Expand Down Expand Up @@ -885,7 +885,7 @@ pub fn datastore_delete_all_by_eq_bsatn(table_id: TableId, relation: &[u8]) -> R

/// Starts iteration on each row, as BSATN-encoded, of a table identified by `table_id`.
/// Returns iterator handle is written to the `out` pointer.
/// This handle can be advanced by [`row_iter_bsatn_advance`].
/// This handle can be advanced by [`RowIter::read`].
///
/// # Errors
///
Expand Down Expand Up @@ -920,7 +920,7 @@ pub fn datastore_table_scan_bsatn(table_id: TableId) -> Result<RowIter, Errno> {
/// which is unique for the module.
///
/// On success, the iterator handle is written to the `out` pointer.
/// This handle can be advanced by [`row_iter_bsatn_advance`].
/// This handle can be advanced by [`RowIter::read`].
///
/// # Non-obvious queries
///
Expand Down
Loading
Loading