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
263 changes: 165 additions & 98 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"crates/roc_stdio",
"crates/roc_env",
"crates/roc_sqlite",
"crates/roc_random",
]

[workspace.package]
Expand All @@ -37,6 +38,7 @@ roc_http = { path = "crates/roc_http" }
roc_io_error = { path = "crates/roc_io_error" }
roc_stdio = { path = "crates/roc_stdio" }
roc_env = { path = "crates/roc_env" }
roc_random = { path = "crates/roc_random" }
roc_sqlite = { path = "crates/roc_sqlite" }
memchr = "=2.7.4"
hyper = { version = "=1.6.0", default-features = false, features = [
Expand All @@ -61,3 +63,4 @@ libc = "=0.2.172"
backtrace = "=0.3.75"
libsqlite3-sys = { version = "=0.33.0", features = ["bundled"] }
thread_local = "=1.1.8"
getrandom = { version = "0.3.3", features = [ "std" ] }
24 changes: 24 additions & 0 deletions ci/expect_scripts/random.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/expect

# uncomment line below for debugging
# exp_internal 1

set timeout 7

source ./ci/expect_scripts/shared-code.exp

spawn $env(EXAMPLES_DIR)random

set expected_output [normalize_output "
Random U64 seed is: \\\d+
Random U32 seed is: \\\d+
"]

expect -re $expected_output {
expect eof {
check_exit_and_segfault
}
}

puts stderr "\nExpect script failed: output was different from expected value. uncomment `exp_internal 1` to debug."
exit 1
3 changes: 2 additions & 1 deletion crates/roc_host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ roc_io_error.workspace = true
roc_http.workspace = true
roc_stdio.workspace = true
roc_env.workspace = true
roc_random.workspace = true
roc_sqlite.workspace = true
hyper.workspace = true
hyper-rustls.workspace = true
tokio.workspace = true
bytes.workspace = true
http-body-util.workspace = true
hyper-util.workspace = true
hyper-util.workspace = true
14 changes: 13 additions & 1 deletion crates/roc_host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ pub fn init() {
roc_fx_temp_dir as _,
roc_fx_get_locale as _,
roc_fx_get_locales as _,
roc_fx_random_u64 as _,
roc_fx_random_u32 as _,
roc_fx_sqlite_bind as _,
roc_fx_sqlite_column_value as _,
roc_fx_sqlite_columns as _,
Expand Down Expand Up @@ -658,7 +660,7 @@ async fn async_send_request(request: hyper::Request<http_body_util::Full<Bytes>>

let client: Client<_, http_body_util::Full<Bytes>> =
Client::builder(TokioExecutor::new()).build(https);

let response_res = client.request(request).await;

match response_res {
Expand Down Expand Up @@ -809,6 +811,16 @@ pub extern "C" fn roc_fx_get_locales() -> RocList<RocStr> {
roc_env::get_locales()
}

#[no_mangle]
pub extern "C" fn roc_fx_random_u64() -> RocResult<u64, IOErr> {
roc_random::random_u64()
}

#[no_mangle]
pub extern "C" fn roc_fx_random_u32() -> RocResult<u32, IOErr> {
roc_random::random_u32()
}

#[no_mangle]
pub extern "C" fn roc_fx_sqlite_bind(
stmt: RocBox<()>,
Expand Down
13 changes: 13 additions & 0 deletions crates/roc_random/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "roc_random"
description = "Common functionality for Roc to interface with getrandom"
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
version.workspace = true

[dependencies]
roc_std.workspace = true
roc_io_error.workspace = true
getrandom.workspace = true
17 changes: 17 additions & 0 deletions crates/roc_random/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use roc_std::{RocList, RocResult};
use roc_io_error::IOErr;


pub fn random_u64() -> RocResult<u64, IOErr> {
getrandom::u64()
.map_err(|e| std::io::Error::from(e))
.map_err(|e| IOErr::from(e))
.into()
}

pub fn random_u32() -> RocResult<u32, IOErr> {
getrandom::u32()
.map_err(|e| std::io::Error::from(e))
.map_err(|e| IOErr::from(e))
.into()
}
20 changes: 20 additions & 0 deletions examples/random.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
app [main!] { pf: platform "../platform/main.roc" }

# To run this example: check the README.md in this folder

# Demo of basic-cli Random functions

import pf.Stdout
import pf.Random
import pf.Arg exposing [Arg]

main! : List Arg => Result {} _
main! = |_args|
random_u64 = Random.random_seed_u64!({})?
Stdout.line!("Random U64 seed is: ${Inspect.to_str(random_u64)}")?

random_u32 = Random.random_seed_u32!({})?
Stdout.line!("Random U32 seed is: ${Inspect.to_str(random_u32)}")

# See the example linked below on how to generate a sequence of random numbers using a seed
# https://github.com/roc-lang/examples/blob/main/examples/RandomNumbers/main.roc
5 changes: 5 additions & 0 deletions platform/Host.roc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ hosted [
hard_link!,
path_type!,
posix_time!,
random_u64!,
random_u32!,
send_request!,
set_cwd!,
sleep_millis!,
Expand Down Expand Up @@ -146,3 +148,6 @@ env_dict! : {} => List (Str, Str)
env_var! : Str => Result Str {}
exe_path! : {} => Result (List U8) {}
set_cwd! : List U8 => Result {} {}

random_u64! : {} => Result U64 InternalIOErr.IOErrFromHost
random_u32! : {} => Result U32 InternalIOErr.IOErrFromHost
52 changes: 52 additions & 0 deletions platform/Random.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
module [
IOErr,
random_seed_u64!,
random_seed_u32!,
]

import InternalIOErr
import Host


## Tag union of possible errors when getting a random seed.
##
## > This is the same as [`File.IOErr`](File#IOErr).
IOErr : InternalIOErr.IOErr

## Generate a random `U64` seed using the system's source of randomness.
## A "seed" is a starting value used to deterministically generate a random sequence.
##
## > !! This function is NOT cryptographically secure.
##
## This uses the [`u64()`](https://docs.rs/getrandom/latest/getrandom/fn.u64.html) function
## of the [getrandom crate](https://crates.io/crates/getrandom) to produce
## a single random 64-bit integer.
##
## For hobby purposes, you can just call this function repreatedly to get random numbers.
## In general, we recommend using this seed in combination with a library like
## [roc-random](https://github.com/lukewilliamboswell/roc-random) to generate additional
## random numbers quickly.
##
random_seed_u64! : {} => Result U64 [RandomErr IOErr]
random_seed_u64! = |{}|
Host.random_u64!({})
|> Result.map_err(|err| RandomErr(InternalIOErr.handle_err(err)))

## Generate a random `U32` seed using the system's source of randomness.
## A "seed" is a starting value used to deterministically generate a random sequence.
##
## > !! This function is NOT cryptographically secure.
##
## This uses the [`u32()`](https://docs.rs/getrandom/0.3.3/getrandom/fn.u32.html) function
## of the [getrandom crate](https://crates.io/crates/getrandom) to produce
## a single random 32-bit integer.
##
## For hobby purposes, you can just call this function repreatedly to get random numbers.
## In general, we recommend using this seed in combination with a library like
## [roc-random](https://github.com/lukewilliamboswell/roc-random) to generate additional
## random numbers quickly.
##
random_seed_u32! : {} => Result U32 [RandomErr IOErr]
random_seed_u32! = |{}|
Host.random_u32!({})
|> Result.map_err(|err| RandomErr(InternalIOErr.handle_err(err)))
1 change: 1 addition & 0 deletions platform/main.roc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ platform "cli"
Tty,
Locale,
Sqlite,
Random,
]
packages {}
imports []
Expand Down