AppBuilder

Struct AppBuilder 

Source
pub struct AppBuilder { /* private fields */ }
Expand description

Builder for constructing a MAF application. Used to register stores, RPC functions, background tasks, and more.

Implementations§

Source§

impl AppBuilder

Source

pub fn on_connect<Params, Handler, const IS_ASYNC: bool>( self, handler: Handler, ) -> Self
where Handler: IntoCallable<OnConnectDiconnectContext, Params, (), OnConnectDisconnectError, (), IS_ASYNC>,

Register a function to run when a user connects. To get the user object, use the User struct as a parameter.

§Example
use maf::prelude::*;

fn on_connect(user: User) {
    println!("user connected! id: {}", user.meta.id());
}

fn build() -> App {
   App::builder()
       .on_connect(on_connect)
       .build()
}
Source

pub fn on_disconnect<Params, Handler, const IS_ASYNC: bool>( self, handler: Handler, ) -> Self
where Handler: IntoCallable<OnConnectDiconnectContext, Params, (), OnConnectDisconnectError, (), IS_ASYNC>,

Register a function to run when a user disconnects. To get the user object, use the User struct as a parameter.

§Example
use maf::prelude::*;

fn on_disconnect(user: User) {
    println!("user disconnected! id: {}", user.meta.id());
}

fn build() -> App {
   App::builder()
       .on_disconnect(on_disconnect)
       .build()
}
Source

pub fn rpc<Params, Return, const IS_ASYNC: bool, Handler: IntoCallable<RpcRequestContext, Params, Return, RpcError, RpcRequestInit, IS_ASYNC>>( self, method: impl ToString, handler: Handler, ) -> Self
where Return: Serialize + 'static,

Register a new RPC method.

See crate::rpc module-level documentation for more details on RPCs.

§Example
use maf::prelude::*;

struct CounterStore {
    count: i32,
}

impl StoreData for CounterStore { /* ... */ }

async fn add(Params(count): Params<i32>, store: Store<CounterStore>) -> i32 {
    let mut data = store.write().await;
    *data += count;
    println!("incremented counter by {count}. new value: {}", &*data);
    *data
}

fn build() -> App {
    App::builder()
        .rpc("add", add)
        .store::<CounterStore>()
        .build()
}

maf::register!(build);
Source

pub fn background<Params, Handler, const IS_ASYNC: bool>( self, handler: Handler, ) -> Self
where Handler: IntoCallable<BackgroundFnContext, Params, (), BackgroundFnError, (), IS_ASYNC>,

Register a task to run in the background.

§Example
use maf::prelude::*;

async fn background() {
    loop {
        tasks::sleep(std::time::Duration::from_secs(1)).await;
        println!("Hello from the background!");  
    }
}

fn build() -> App {
    App::builder()
        .background(background)
        .build()
}
Source

pub fn store<T: StoreData>(self) -> Self

Statically declare a store, initializing it with the default value.

This method should be called with a type argument that implements StoreData.

§Example
use maf::prelude::*;

struct CounterStore {
    count: i32,
}

impl StoreData for CounterStore {
    type Select<'this> = i32; // Serializable type representing the store's data

    // The default value for the store should be provided here
    fn init() -> Self {
        CounterStore { count: 0 }
    }

    fn select(&self, _user: &User) -> Self::Select<'_> {
        self.count
    }

    fn name() -> impl AsRef<str> {
        "counter"
    }
}

fn build() -> App {
    App::builder()
        // Register the store so it can be used in RPCs and elsewhere. The type argument
        // specifies the store's data type.
        .store::<CounterStore>()
        .build()
}

maf::register!(build);
Source

pub fn select<Name: ToString, Params, Ret, Handler: IntoCallable<SelectContext, Params, Ret, Infallible, (), IS_ASYNC>, const IS_ASYNC: bool, const N_PARAMS: usize>( self, name: Name, handler: Handler, ) -> Self
where Params: GetParamSelectDependencies<N_PARAMS>, Ret: Serialize + 'static,

Register a store where its contents are derived with the provided function.

This is useful for creating “views” of existing stores that automatically update when their dependencies change.

§Example
use maf::prelude::*;

#[derive(Debug, Serialize)]
pub struct Player {
    id: Uuid,
    name: String,
    is_alive: bool,
}

struct GameStore {
    players: HashMap<Uuid, Player>,
}

impl StoreData for GameStore {
    // On this store, we are not exposing any data to the client.
    type Select<'this> = ();

    // ... implement init, name, and select ...
}

fn build() -> App {
    App::builder()
        // Register the main game store
        .store::<GameStore>()
        // The "alive_players" select will automatically update whenever the `GameStore`
        // changes. Clients will see an "alive_players" store that contains only the alive
        // players.
        .select("alive_players", |store: StoreRef<GameStore>| {
            store.players.values()
                .filter(|player| player.is_alive)
                .cloned()
                .collect::<Vec<Player>>()
        })
        // Multiple selects can be added. Here is another example that counts the number of
        // players in the game.
        .select("player_count", |store: StoreRef<GameStore>| {
            store.players.len()
        })
        .build()
}

maf::register!(build);
Source

pub fn meta<Name: ToString, Params, Ret, Handler: IntoCallable<MetaContext, Params, Ret, Infallible, (), IS_ASYNC>, const IS_ASYNC: bool, const N_PARAMS: usize>( self, visibility: MetaVisibility, name: Name, handler: Handler, ) -> Self
where Params: GetParamSelectDependencies<N_PARAMS>, Ret: Serialize + 'static,

Subscribes a meta entry to be automatically updated when its dependencies change.

The handler function is called to compute the meta value whenever any of its dependencies change.

§Example
use maf::prelude::*;

struct CounterStore {
    count: i32,
}

impl StoreData for CounterStore { /* ... */ }

fn build() -> App {
    App::builder()
        .store::<CounterStore>()
        // Whenever the `CounterStore` is updated, the "count" meta value will also be
        // updated.
        .meta(MetaVisibility::Public, "count", |store: StoreRef<CounterStore>| {
            store.count
        })
}

maf::register!(build);
Source

pub fn local<T: Send + Sync + 'static>(self, state: T) -> Self

Declares a crate::Local, a piece of state that does not need to be synchronized with connect clients. If synchronization with clients is needed, use crate::Store

The initial value of the local state should be provided as an argument.

§Example
use maf::prelude::*;

struct Points {
    points: u32,
}

// [`Points`] does not need to be `serde::Serialize` and is not visible to clients
async fn score_point(points: Local<Points>) {
    let points = points.write().await;
    points += 1;
    if points > 100 {
        println!("You win!");
    }
}

fn build() -> App {
    App::builder()
        .local(Points { points: 0 })
        .rpc("score_point", score_point)
        .build()
}
Source

pub fn hook<Params, Return, Handler, const IS_ASYNC: bool>( self, method: impl ToString, handler: Handler, ) -> Self
where Handler: IntoCallable<HookContext, Params, Return, HookError, (), IS_ASYNC>, Return: Serialize + 'static,

Declare a hook function. TODO: write documentation for this.

Source

pub fn platform(self, platform: TargetPlatform) -> Self

Binds the MAF app to a specified TargetPlatform.

See crate::platform for more details on platforms.

Source

pub fn build(self) -> App

Source§

impl AppBuilder

Source

pub fn plugin(self, plugin: impl Plugin) -> Self

Registers a plugin to modify the application.

§Examples
use maf::prelude::*;

// A plugin that adds game functionality to the app.
// NOTE: options and configuration can be passed to the plugin via its fields.
pub struct GamePlugin {
    total_rounds: u32,
}

// ... other plugin code ...

impl Plugin for GamePlugin {
    fn build(&self, app: AppBuilder) -> AppBuilder {
        // Initialize game state, RPCs, stores, etc.
        app
            // .store::<GameState>()
            // .rpc("start_round", start_round)
            // ...
    }
}

// ... where the app is built ...
fn build() -> App {
    App::builder()
        // Consume the plugin to modify the app
        .plugin(GamePlugin { total_rounds: 5 })
        // ... other app configuration ...
        .build()
}

maf::register!(build);

Trait Implementations§

Source§

impl Default for AppBuilder

Source§

fn default() -> AppBuilder

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V