Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 13 additions & 1 deletion crates/bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,13 +1084,25 @@ pub struct ProcedureContext {

/// Methods for performing HTTP requests.
pub http: crate::http::HttpClient,
// TODO: Add rng?
// TODO: Change rng?
// Complex and requires design because we may want procedure RNG to behave differently from reducer RNG,
// as it could actually be seeded by OS randomness rather than a deterministic source.
#[cfg(feature = "rand08")]
rng: std::cell::OnceCell<StdbRng>,
}

#[cfg(feature = "unstable")]
impl ProcedureContext {
fn new(sender: Identity, connection_id: Option<ConnectionId>, timestamp: Timestamp) -> Self {
Self {
sender,
timestamp,
connection_id,
http: http::HttpClient {},
#[cfg(feature = "rand08")]
rng: std::cell::OnceCell::new(),
}
}
/// Read the current module's [`Identity`].
pub fn identity(&self) -> Identity {
// Hypothetically, we *could* read the module identity out of the system tables.
Expand Down
47 changes: 47 additions & 0 deletions crates/bindings/src/rng.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "unstable")]
use crate::ProcedureContext;
use crate::{rand, ReducerContext};
use core::cell::UnsafeCell;
use core::marker::PhantomData;
Expand Down Expand Up @@ -49,6 +51,51 @@ impl ReducerContext {
}
}

#[cfg(feature = "unstable")]
impl ProcedureContext {
/// Generates a random value.
///
/// Similar to [`rand::random()`], but using [`StdbRng`] instead.
///
/// See also [`ProcedureContext::rng()`].
#[cfg(feature = "unstable")]
pub fn random<T>(&self) -> T
where
Standard: Distribution<T>,
{
Standard.sample(&mut self.rng())
}

/// Retrieve the random number generator for this procedure transaction,
/// seeded by the timestamp of the procedure call.
///
/// If you only need a single random value, you can use [`ProcedureContext::random()`].
///
/// # Examples
/// ```no_run
/// # #[cfg(target_arch = "wasm32")] mod demo {
/// use spacetimedb::{procedure, ProcedureContext};
/// use rand::Rng;
///
/// #[spacetimedb::procedure]
/// fn rng_demo(ctx: &spacetimedb::ProcedureContext) {
/// // Can be used in method chaining style:
/// let digit = ctx.rng().gen_range(0..=9);
///
/// // Or, cache locally for reuse:
/// let mut rng = ctx.rng();
/// let floats: Vec<f32> = rng.sample_iter(rand::distributions::Standard).collect();
/// }
/// # }
/// ```
///
/// For more information, see [`StdbRng`] and [`rand::Rng`].
#[cfg(feature = "unstable")]
pub fn rng(&self) -> &StdbRng {
self.rng.get_or_init(|| StdbRng::seed_from_ts(self.timestamp))
}
}

/// A reference to the random number generator for this reducer call.
///
/// An instance can be obtained via [`ReducerContext::rng()`]. Import
Expand Down
7 changes: 1 addition & 6 deletions crates/bindings/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,12 +1034,7 @@ extern "C" fn __call_procedure__(
let timestamp = Timestamp::from_micros_since_unix_epoch(timestamp as i64);

// Assemble the `ProcedureContext`.
let ctx = ProcedureContext {
connection_id: conn_id,
sender,
timestamp,
http: crate::http::HttpClient {},
};
let ctx = ProcedureContext::new(sender, conn_id, timestamp);

// Grab the list of procedures, which is populated by the preinit functions.
let procedures = PROCEDURES.get().unwrap();
Expand Down