Skip to content

Commit 0835ba2

Browse files
committed
add random seed generation
1 parent df2ea0f commit 0835ba2

11 files changed

Lines changed: 258 additions & 100 deletions

File tree

Cargo.lock

Lines changed: 165 additions & 98 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ members = [
1111
"crates/roc_stdio",
1212
"crates/roc_env",
1313
"crates/roc_sqlite",
14+
"crates/roc_random",
1415
]
1516

1617
[workspace.package]
@@ -37,6 +38,7 @@ roc_http = { path = "crates/roc_http" }
3738
roc_io_error = { path = "crates/roc_io_error" }
3839
roc_stdio = { path = "crates/roc_stdio" }
3940
roc_env = { path = "crates/roc_env" }
41+
roc_random = { path = "crates/roc_random" }
4042
roc_sqlite = { path = "crates/roc_sqlite" }
4143
memchr = "=2.7.4"
4244
hyper = { version = "=1.6.0", default-features = false, features = [
@@ -61,3 +63,4 @@ libc = "=0.2.172"
6163
backtrace = "=0.3.75"
6264
libsqlite3-sys = { version = "=0.33.0", features = ["bundled"] }
6365
thread_local = "=1.1.8"
66+
getrandom = { version = "0.3.3", features = [ "std" ] }

ci/expect_scripts/random.exp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/expect
2+
3+
# uncomment line below for debugging
4+
# exp_internal 1
5+
6+
set timeout 7
7+
8+
source ./ci/expect_scripts/shared-code.exp
9+
10+
spawn $env(EXAMPLES_DIR)random-seed
11+
12+
expect -re "Seed is: \\d+" {
13+
expect eof {
14+
check_exit_and_segfault
15+
}
16+
}
17+
18+
puts stderr "\nExpect script failed: output was different from expected value. uncomment `exp_internal 1` to debug."
19+
exit 1

crates/roc_host/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ roc_io_error.workspace = true
2727
roc_http.workspace = true
2828
roc_stdio.workspace = true
2929
roc_env.workspace = true
30+
roc_random.workspace = true
3031
roc_sqlite.workspace = true
3132
hyper.workspace = true
3233
hyper-rustls.workspace = true
3334
tokio.workspace = true
3435
bytes.workspace = true
3536
http-body-util.workspace = true
36-
hyper-util.workspace = true
37+
hyper-util.workspace = true

crates/roc_host/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ pub fn init() {
349349
roc_fx_temp_dir as _,
350350
roc_fx_get_locale as _,
351351
roc_fx_get_locales as _,
352+
roc_fx_random_seed as _,
352353
roc_fx_sqlite_bind as _,
353354
roc_fx_sqlite_column_value as _,
354355
roc_fx_sqlite_columns as _,
@@ -658,7 +659,7 @@ async fn async_send_request(request: hyper::Request<http_body_util::Full<Bytes>>
658659

659660
let client: Client<_, http_body_util::Full<Bytes>> =
660661
Client::builder(TokioExecutor::new()).build(https);
661-
662+
662663
let response_res = client.request(request).await;
663664

664665
match response_res {
@@ -809,6 +810,11 @@ pub extern "C" fn roc_fx_get_locales() -> RocList<RocStr> {
809810
roc_env::get_locales()
810811
}
811812

813+
#[no_mangle]
814+
pub extern "C" fn roc_fx_random_seed() -> RocResult<u64, IOErr> {
815+
roc_random::seed()
816+
}
817+
812818
#[no_mangle]
813819
pub extern "C" fn roc_fx_sqlite_bind(
814820
stmt: RocBox<()>,

crates/roc_random/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "roc_random"
3+
description = "Common functionality for Roc to interface with rand"
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
version.workspace = true
9+
10+
[dependencies]
11+
roc_std.workspace = true
12+
roc_io_error.workspace = true
13+
getrandom.workspace = true

crates/roc_random/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use roc_std::RocResult;
2+
use roc_io_error::IOErr;
3+
4+
5+
pub fn seed() -> RocResult<u64, IOErr> {
6+
getrandom::u64()
7+
.map_err(|e| std::io::Error::from(e))
8+
.map_err(|e| IOErr::from(e))
9+
.into()
10+
}

examples/random-seed.roc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
app [main!] { pf: platform "../platform/main.roc" }
2+
3+
# To run this example: check the README.md in this folder
4+
5+
# Demo of basic-cli Random functions
6+
7+
import pf.Stdout
8+
import pf.Random
9+
import pf.Arg exposing [Arg]
10+
11+
main! : List Arg => Result {} _
12+
main! = |_args|
13+
seed = Random.seed!({})?
14+
15+
Stdout.line!("Seed is: ${Inspect.to_str(seed)}")

platform/Host.roc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ hosted [
3333
hard_link!,
3434
path_type!,
3535
posix_time!,
36+
random_seed!,
3637
send_request!,
3738
set_cwd!,
3839
sleep_millis!,
@@ -146,3 +147,5 @@ env_dict! : {} => List (Str, Str)
146147
env_var! : Str => Result Str {}
147148
exe_path! : {} => Result (List U8) {}
148149
set_cwd! : List U8 => Result {} {}
150+
151+
random_seed! : {} => Result U64 InternalIOErr.IOErrFromHost

platform/Random.roc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module [
2+
IOErr,
3+
seed!,
4+
]
5+
6+
import InternalIOErr
7+
import Host
8+
9+
10+
## Tag union of possible errors when getting a random seed.
11+
##
12+
## > This is the same as [`File.IOErr`](File#IOErr).
13+
IOErr : InternalIOErr.IOErr
14+
15+
## Generate a random U64 using the system's source of randomness.
16+
## This uses the Rust crate `getrandom`.
17+
seed! : {} => Result U64 [RandomErr IOErr]
18+
seed! = |{}|
19+
Host.random_seed!({})
20+
|> Result.map_err(|err| RandomErr(InternalIOErr.handle_err(err)))

0 commit comments

Comments
 (0)