Skip to content

Commit

Permalink
aneri-rand refactor + cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Absolucy committed Apr 15, 2024
1 parent 630552e commit 8e48b8a
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 197 deletions.
15 changes: 5 additions & 10 deletions crates/rand/src/global/number.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
use super::global;
use crate::shared;
use rand::Rng;

#[byond_fn]
Expand All @@ -23,17 +24,11 @@ pub fn random_int_signed(secure: Option<bool>) -> i32 {
}

#[byond_fn]
pub fn random_range_int_unsigned(mut min: u32, mut max: u32, secure: Option<bool>) -> u32 {
if min > max {
std::mem::swap(&mut min, &mut max);
}
global(secure).gen_range(min..=max)
pub fn random_range_int_unsigned(min: u32, max: u32, secure: Option<bool>) -> u32 {
shared::random_range_int_unsigned(&mut global(secure), min, max)
}

#[byond_fn]
pub fn random_range_int_signed(mut min: i32, mut max: i32, secure: Option<bool>) -> i32 {
if min > max {
std::mem::swap(&mut min, &mut max);
}
global(secure).gen_range(min..=max)
pub fn random_range_int_signed(min: i32, max: i32, secure: Option<bool>) -> i32 {
shared::random_range_int_signed(&mut global(secure), min, max)
}
49 changes: 5 additions & 44 deletions crates/rand/src/global/pick.rs
Original file line number Diff line number Diff line change
@@ -1,53 +1,14 @@
// SPDX-License-Identifier: MPL-2.0
use super::global;
use crate::shared;
use meowtonin::{ByondResult, ByondValue};
use rand::{
distributions::{Distribution, WeightedIndex},
Rng,
};

#[byond_fn]
pub fn pick(options: ByondValue, secure: Option<bool>) -> ByondResult<Option<ByondValue>> {
if !options.is_list() {
return Ok(None);
}
let length = options.length()?;
match length {
0 => return Ok(None),
1 => return options.read_list_index(&1).map(Some),
_ => {}
}
let idx = global(secure).gen_range::<usize, _>(1..=length);
options.read_list_index(&idx).map(Some)
pub fn pick(options: ByondValue, secure: Option<bool>) -> ByondResult<ByondValue> {
shared::pick(&mut global(secure), options)
}

#[byond_fn]
pub fn pick_weighted(options: ByondValue, secure: Option<bool>) -> ByondResult<Option<ByondValue>> {
if !options.is_list() {
return Ok(None);
}
let length = options.length::<usize>()?;
match length {
0 => return Ok(None),
1 => return options.read_list_index(&1).map(Some),
_ => {}
}
let options = options.read_assoc_list()?;
let weights = options
.iter()
.map(|[_, weight]| weight.get_number())
.filter_map(|weight| weight.ok())
.filter(|weight| weight.is_normal() && weight.is_sign_positive())
.collect::<Vec<f32>>();
match weights.len() {
0 => return Ok(None),
1 => return Ok(options.get(1).and_then(|entry| entry.get(1)).cloned()),
_ => {}
}
let dist = match WeightedIndex::new(weights) {
Ok(dist) => dist,
Err(_) => return Ok(None),
};
let idx = dist.sample(&mut global(secure));
Ok(options.get(idx).and_then(|entry| entry.get(2)).cloned())
pub fn pick_weighted(options: ByondValue, secure: Option<bool>) -> ByondResult<ByondValue> {
shared::pick_weighted(&mut global(secure), options)
}
10 changes: 3 additions & 7 deletions crates/rand/src/global/prob.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
use super::global;
use rand::Rng;
use crate::shared;

#[byond_fn]
pub fn prob(probability: f64, secure: Option<bool>) -> bool {
if !probability.is_finite() {
return true;
}
let probability = (probability / 100.0).clamp(0.0, 1.0);
global(secure).gen_bool(probability)
shared::prob(&mut global(secure), probability)
}

#[byond_fn]
pub fn prob_ratio(numerator: u32, denominator: u32, secure: Option<bool>) -> bool {
global(secure).gen_ratio(numerator, denominator)
shared::prob_ratio(&mut global(secure), numerator, denominator)
}
33 changes: 9 additions & 24 deletions crates/rand/src/global/string.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
// SPDX-License-Identifier: MPL-2.0
use super::global;
use rand::{
distributions::{Alphanumeric, Bernoulli, Distribution},
Rng,
};
use crate::shared;

#[byond_fn]
pub fn random_string_alphanumeric(length: usize, secure: Option<bool>) -> String {
let mut rng = global(secure);
(0..=length)
.map(|_| rng.sample(Alphanumeric) as char)
.collect()
shared::random_string_alphanumeric(&mut global(secure), length)
}

#[byond_fn]
Expand All @@ -21,20 +15,11 @@ pub fn replace_chars_prob(
skip_whitespace: Option<bool>,
secure: Option<bool>,
) -> String {
if !prob.is_normal() || !prob.is_sign_positive() {
return input;
}
let skip_whitespace = skip_whitespace.unwrap_or(false);
let mut rng = global(secure);
let distro =
Bernoulli::new((prob as f64 / 100.0).clamp(0.0, 1.0)).expect("invalid probability, wtf???");
let mut output = String::with_capacity(input.len() * replacement.len()); // Allocate for worst case scenario.
input.chars().for_each(|c| {
if (!skip_whitespace || !c.is_whitespace()) && distro.sample(&mut rng) {
output.push_str(&replacement);
} else {
output.push(c);
}
});
output
shared::replace_chars_prob(
&mut global(secure),
input,
replacement,
prob,
skip_whitespace,
)
}
41 changes: 11 additions & 30 deletions crates/rand/src/instance/number.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
use super::INSTANCES;
use crate::shared;
use aneri_core::ByondSlotKey;
use rand::{
distributions::{
Expand All @@ -15,18 +16,6 @@ where
{
INSTANCES.lock().get_mut(src).map(|rng| rng.gen())
}

fn range_impl<Output, Range>(src: ByondSlotKey, range: Range) -> Option<Output>
where
Output: SampleUniform,
Range: SampleRange<Output>,
{
INSTANCES
.lock()
.get_mut(src)
.map(|rng| rng.gen_range(range))
}

#[byond_fn]
pub fn instanced_random_byte(src: ByondSlotKey) -> Option<u8> {
rand_impl(src)
Expand All @@ -48,25 +37,17 @@ pub fn instanced_random_int_signed(src: ByondSlotKey) -> Option<i32> {
}

#[byond_fn]
pub fn instanced_random_range_int_unsigned(
src: ByondSlotKey,
mut min: u32,
mut max: u32,
) -> Option<u32> {
if min > max {
std::mem::swap(&mut min, &mut max);
}
range_impl(src, min..=max)
pub fn instanced_random_range_int_unsigned(src: ByondSlotKey, min: u32, max: u32) -> Option<u32> {
INSTANCES
.lock()
.get_mut(src)
.map(|rng| shared::random_range_int_unsigned(rng, min, max))
}

#[byond_fn]
pub fn instanced_random_range_int_signed(
src: ByondSlotKey,
mut min: i32,
mut max: i32,
) -> Option<i32> {
if min > max {
std::mem::swap(&mut min, &mut max);
}
range_impl(src, min..=max)
pub fn instanced_random_range_int_signed(src: ByondSlotKey, min: i32, max: i32) -> Option<i32> {
INSTANCES
.lock()
.get_mut(src)
.map(|rng| shared::random_range_int_signed(rng, min, max))
}
59 changes: 11 additions & 48 deletions crates/rand/src/instance/pick.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
use super::INSTANCES;
use crate::shared;
use aneri_core::ByondSlotKey;
use meowtonin::{ByondResult, ByondValue};
use rand::{
Expand All @@ -9,59 +10,21 @@ use rand::{

#[byond_fn]
pub fn instanced_pick(src: ByondSlotKey, options: ByondValue) -> ByondResult<Option<ByondValue>> {
if !options.is_list() {
return Ok(None);
}
let length = options.length::<usize>()?;
match length {
0 => return Ok(None),
1 => return options.read_list_index(&1).map(Some),
_ => {}
}
let mut instances = INSTANCES.lock();
let rng = match instances.get_mut(src) {
Some(rng) => rng,
None => return Ok(None),
};
let idx = rng.gen_range::<usize, _>(1..=length);
options.read_list_index(&idx).map(Some)
INSTANCES
.lock()
.get_mut(src)
.map(|rng| shared::pick(rng, options))
.transpose()
}

#[byond_fn]
pub fn instanced_pick_weighted(
src: ByondSlotKey,
options: ByondValue,
) -> ByondResult<Option<ByondValue>> {
if !options.is_list() {
return Ok(None);
}
let length = options.length::<usize>()?;
match length {
0 => return Ok(None),
1 => return options.read_list_index(&1).map(Some),
_ => {}
}
let options = options.read_assoc_list()?;
let weights = options
.iter()
.map(|[_, weight]| weight.get_number())
.filter_map(|weight| weight.ok())
.filter(|weight| weight.is_normal() && weight.is_sign_positive())
.collect::<Vec<f32>>();
match weights.len() {
0 => return Ok(None),
1 => return Ok(options.get(1).and_then(|entry| entry.get(1)).cloned()),
_ => {}
}
let dist = match WeightedIndex::new(weights) {
Ok(dist) => dist,
Err(_) => return Ok(None),
};
let mut instances = INSTANCES.lock();
let rng = match instances.get_mut(src) {
Some(rng) => rng,
None => return Ok(None),
};
let idx = dist.sample(rng);
Ok(options.get(idx).and_then(|entry| entry.get(2)).cloned())
INSTANCES
.lock()
.get_mut(src)
.map(|rng| shared::pick_weighted(rng, options))
.transpose()
}
10 changes: 3 additions & 7 deletions crates/rand/src/instance/prob.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
// SPDX-License-Identifier: MPL-2.0
use super::INSTANCES;
use crate::shared;
use aneri_core::ByondSlotKey;
use rand::Rng;

#[byond_fn]
pub fn instanced_prob(src: ByondSlotKey, probability: f64) -> Option<bool> {
if !probability.is_finite() {
return Some(true);
}
let probability = (probability / 100.0).clamp(0.0, 1.0);
INSTANCES
.lock()
.get_mut(src)
.map(|rng| rng.gen_bool(probability))
.map(|rng| shared::prob(rng, probability))
}

#[byond_fn]
pub fn instanced_prob_ratio(src: ByondSlotKey, numerator: u32, denominator: u32) -> Option<bool> {
INSTANCES
.lock()
.get_mut(src)
.map(|rng| rng.gen_ratio(numerator, denominator))
.map(|rng| shared::prob_ratio(rng, numerator, denominator))
}
37 changes: 10 additions & 27 deletions crates/rand/src/instance/string.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,26 @@
// SPDX-License-Identifier: MPL-2.0
use super::INSTANCES;
use crate::shared;
use aneri_core::ByondSlotKey;
use rand::{
distributions::{Alphanumeric, Bernoulli, Distribution},
Rng,
};

#[byond_fn]
pub fn instanced_random_string_alphanumeric(src: ByondSlotKey, length: usize) -> Option<String> {
INSTANCES.lock().get_mut(src).map(|rng| {
(0..=length)
.map(|_| rng.sample(Alphanumeric) as char)
.collect()
})
INSTANCES
.lock()
.get_mut(src)
.map(|rng| shared::random_string_alphanumeric(rng, length))
}

#[byond_fn]
pub fn instnaced_replace_chars_prob(
pub fn instanced_replace_chars_prob(
src: ByondSlotKey,
input: String,
replacement: String,
prob: f32,
skip_whitespace: Option<bool>,
) -> Option<String> {
if !prob.is_normal() || !prob.is_sign_positive() {
return Some(input);
}
let skip_whitespace = skip_whitespace.unwrap_or(false);
INSTANCES.lock().get_mut(src).map(|rng| {
let distro = Bernoulli::new((prob as f64 / 100.0).clamp(0.0, 1.0))
.expect("invalid probability, wtf???");
let mut output = String::with_capacity(input.len() * replacement.len()); // Allocate for worst case scenario.
input.chars().for_each(|c| {
if (!skip_whitespace || !c.is_whitespace()) && distro.sample(rng) {
output.push_str(&replacement);
} else {
output.push(c);
}
});
output
})
INSTANCES
.lock()
.get_mut(src)
.map(|rng| shared::replace_chars_prob(rng, input, replacement, prob, skip_whitespace))
}
3 changes: 3 additions & 0 deletions crates/rand/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ extern crate meowtonin;

pub mod global;
pub mod instance;
pub mod shared;

pub(crate) use instance::dispatcher::RngDispatcher;

pub fn cleanup() {
global::reseed_global_rng();
Expand Down
11 changes: 11 additions & 0 deletions crates/rand/src/shared.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MPL-2.0

mod number;
mod pick;
mod prob;
mod string;

pub(crate) use number::*;
pub(crate) use pick::*;
pub(crate) use prob::*;
pub(crate) use string::*;
Loading

0 comments on commit 8e48b8a

Please sign in to comment.