mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
add script to prebuild platform-switching rust
This commit is contained in:
parent
81f466fee0
commit
1b0cd14715
17 changed files with 57 additions and 845 deletions
|
@ -2,7 +2,7 @@ on:
|
|||
#pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 9 * * *'
|
||||
- cron: "0 9 * * *"
|
||||
|
||||
name: Nightly Release macOS Apple Silicon
|
||||
|
||||
|
@ -56,8 +56,10 @@ jobs:
|
|||
- name: extract tar for a quick test
|
||||
run: ls | grep tar | xargs tar -xf
|
||||
|
||||
- name: test with rust platform
|
||||
run: cd ${{ env.RELEASE_FOLDER_NAME }} && ./roc examples/platform-switching/rocLovesRust.roc
|
||||
- name: test with rust platform (prebuild the host first)
|
||||
run: |
|
||||
examples/platform-switching/rust-platform/build.sh
|
||||
cd ${{ env.RELEASE_FOLDER_NAME }} && ./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
- name: print short commit SHA
|
||||
run: git rev-parse --short "$GITHUB_SHA"
|
||||
|
|
|
@ -39,12 +39,6 @@ jobs:
|
|||
- name: roc test all builtins
|
||||
run: nix develop -c ./ci/roc_test_builtins.sh
|
||||
|
||||
- name: make a libapp.so for the next step
|
||||
run: nix develop -c cargo run -- build --lib examples/platform-switching/rust-platform/libapp.roc
|
||||
|
||||
- name: check that the platform`s produced dylib is loadable
|
||||
run: cd examples/platform-switching/rust-platform && nix develop -c cargo test --release --locked
|
||||
|
||||
- name: test aarch64 dev backend
|
||||
run: nix develop -c cargo nextest-gen-dev --locked --release --no-fail-fast
|
||||
|
||||
|
|
6
.github/workflows/nix_macos_x86_64.yml
vendored
6
.github/workflows/nix_macos_x86_64.yml
vendored
|
@ -22,9 +22,3 @@ jobs:
|
|||
|
||||
- name: roc test all builtins
|
||||
run: nix develop -c ./ci/roc_test_builtins.sh
|
||||
|
||||
- name: make a libapp.so for the next step
|
||||
run: nix develop -c cargo run -- build --lib examples/platform-switching/rust-platform/libapp.roc
|
||||
|
||||
- name: check that the platform`s produced dylib is loadable
|
||||
run: cd examples/platform-switching/rust-platform && nix develop -c cargo test --release --locked
|
||||
|
|
|
@ -30,7 +30,9 @@ jobs:
|
|||
run: cd roc_nightly && ./roc examples/helloWorld.roc
|
||||
|
||||
- name: test platform switching rust
|
||||
run: cd roc_nightly && ./roc examples/platform-switching/rocLovesRust.roc
|
||||
run: |
|
||||
examples/platform-switching/rust-platform/build.sh
|
||||
cd roc_nightly && ./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
- name: test platform switching zig
|
||||
run: cd roc_nightly && ./roc examples/platform-switching/rocLovesZig.roc
|
||||
|
|
3
.github/workflows/ubuntu_x86_64.yml
vendored
3
.github/workflows/ubuntu_x86_64.yml
vendored
|
@ -42,9 +42,6 @@ jobs:
|
|||
- name: tests examples in docs
|
||||
run: cargo test --doc --release
|
||||
|
||||
- name: check that the platform`s produced dylib is loadable
|
||||
run: cd examples/platform-switching/rust-platform && LD_LIBRARY_PATH=. cargo test --release --locked
|
||||
|
||||
- name: test the dev backend # these tests require an explicit feature flag
|
||||
run: cargo test --locked --release --package test_gen --no-default-features --features gen-dev
|
||||
|
||||
|
|
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -3267,6 +3267,14 @@ dependencies = [
|
|||
"roc_work",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-platform"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"roc_std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
|
|
|
@ -31,6 +31,7 @@ members = [
|
|||
"crates/wasm_interp",
|
||||
"crates/language_server",
|
||||
"crates/roc_std_heap",
|
||||
"examples/platform-switching/rust-platform",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
|
|
|
@ -31,7 +31,8 @@ cd roc_nightly
|
|||
# test roc hello world
|
||||
./roc examples/helloWorld.roc
|
||||
|
||||
# test rust platform
|
||||
# test rust platform (first prebuild the host)
|
||||
examples/platform-switching/rust-platform/build.sh
|
||||
./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
# test zig platform
|
||||
|
|
|
@ -52,22 +52,25 @@ mod cli_tests {
|
|||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn platform_switching_rust() {
|
||||
// pre-build the platform
|
||||
std::process::Command::new("bash")
|
||||
.arg(file_from_root(
|
||||
"examples/platform-switching/rust-platform",
|
||||
"build.sh",
|
||||
))
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_BUILD,
|
||||
roc_cli::CMD_RUN,
|
||||
file_from_root("examples/platform-switching", "rocLovesRust.roc"),
|
||||
)
|
||||
.arg(BUILD_HOST_FLAG)
|
||||
.arg(SUPPRESS_BUILD_HOST_WARNING_FLAG);
|
||||
);
|
||||
|
||||
let expected_output = "Roc <3 Rust!\n";
|
||||
|
||||
cli_build.full_check_build_and_run(
|
||||
expected_output,
|
||||
TEST_LEGACY_LINKER,
|
||||
ALLOW_VALGRIND,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let output = cli_build.run();
|
||||
|
||||
output.assert_clean_stdout(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,22 +1,15 @@
|
|||
[package]
|
||||
name = "host"
|
||||
name = "rust-platform"
|
||||
authors = ["The Roc Contributors"]
|
||||
edition = "2021"
|
||||
license = "UPL-1.0"
|
||||
links = "app"
|
||||
version = "0.0.1"
|
||||
|
||||
[lib]
|
||||
name = "host"
|
||||
name = "rustplatform"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["staticlib", "lib"]
|
||||
|
||||
[[bin]]
|
||||
name = "host"
|
||||
path = "src/main.rs"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
roc_std = { path = "../../../crates/roc_std" }
|
||||
|
||||
[workspace]
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(windows))]
|
||||
println!("cargo:rustc-link-lib=dylib=app");
|
||||
|
||||
#[cfg(windows)]
|
||||
println!("cargo:rustc-link-lib=dylib=libapp");
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let dylib_file_name = "libapp.dylib";
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let dylib_file_name = "libapp.so";
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let dylib_file_name = "libapp.dll";
|
||||
|
||||
// Get the build cache directory (OUT_DIR)
|
||||
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||
|
||||
let lib_app = workspace_root()
|
||||
.join("examples")
|
||||
.join("platform-switching")
|
||||
.join("rust-platform")
|
||||
.join(dylib_file_name);
|
||||
|
||||
let out_path = Path::new(&out_dir).join(dylib_file_name);
|
||||
|
||||
// copy the dylib to the output build cache
|
||||
std::fs::copy(lib_app, out_path).unwrap();
|
||||
|
||||
// Search for the dylib in the cache directory
|
||||
println!("cargo:rustc-link-search={out_dir}");
|
||||
}
|
||||
|
||||
pub fn workspace_root() -> PathBuf {
|
||||
let root = std::env::var("ROC_WORKSPACE_DIR").expect("Can't find the ROC_WORKSPACE_DIR variable expected to be set in .cargo/config.toml. Are you running tests outside of cargo?");
|
||||
PathBuf::from(root)
|
||||
}
|
11
examples/platform-switching/rust-platform/build.sh
Normal file
11
examples/platform-switching/rust-platform/build.sh
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||
set -euxo pipefail
|
||||
|
||||
# set the working directory to the directory of the script
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
cargo build -p rust-platform
|
||||
|
||||
cp ../../../target/debug/librustplatform.a ./libhost.a
|
|
@ -1,3 +0,0 @@
|
|||
extern int rust_main();
|
||||
|
||||
int main() { return rust_main(); }
|
|
@ -1,3 +0,0 @@
|
|||
app [main] { pf: platform "main.roc" }
|
||||
|
||||
main = "STUBBED APP"
|
|
@ -1,744 +0,0 @@
|
|||
// ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc glue` CLI command
|
||||
|
||||
#![allow(unused_unsafe)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_mut)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(clippy::undocumented_unsafe_blocks)]
|
||||
#![allow(clippy::redundant_static_lifetimes)]
|
||||
#![allow(clippy::unused_unit)]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
#![allow(clippy::let_and_return)]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
#![allow(clippy::redundant_static_lifetimes)]
|
||||
#![allow(clippy::needless_borrow)]
|
||||
#![allow(clippy::clone_on_copy)]
|
||||
|
||||
type Op_StderrWrite = roc_std::RocStr;
|
||||
type Op_StdoutWrite = roc_std::RocStr;
|
||||
type TODO_roc_function_69 = roc_std::RocStr;
|
||||
type TODO_roc_function_70 = roc_std::RocStr;
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum discriminant_Op {
|
||||
Done = 0,
|
||||
StderrWrite = 1,
|
||||
StdoutWrite = 2,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for discriminant_Op {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::Done => f.write_str("discriminant_Op::Done"),
|
||||
Self::StderrWrite => f.write_str("discriminant_Op::StderrWrite"),
|
||||
Self::StdoutWrite => f.write_str("discriminant_Op::StdoutWrite"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
#[repr(transparent)]
|
||||
pub struct Op {
|
||||
pointer: *mut union_Op,
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
#[repr(C)]
|
||||
union union_Op {
|
||||
StderrWrite: core::mem::ManuallyDrop<Op_StderrWrite>,
|
||||
StdoutWrite: core::mem::ManuallyDrop<Op_StdoutWrite>,
|
||||
_sizer: [u8; 8],
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
//TODO HAS CLOSURE 2
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
#[repr(C)]
|
||||
pub struct RocFunction_66 {
|
||||
pub closure_data: roc_std::RocList<u8>,
|
||||
}
|
||||
|
||||
impl RocFunction_66 {
|
||||
pub fn force_thunk(mut self, arg_0: ()) -> Op {
|
||||
extern "C" {
|
||||
fn roc__mainForHost_0_caller(arg_0: &(), closure_data: *mut u8, output: *mut Op);
|
||||
}
|
||||
|
||||
let mut output = std::mem::MaybeUninit::uninit();
|
||||
let ptr = self.closure_data.as_mut_ptr();
|
||||
unsafe { roc__mainForHost_0_caller(&arg_0, ptr, output.as_mut_ptr()) };
|
||||
unsafe { output.assume_init() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
#[repr(C)]
|
||||
pub struct RocFunction_67 {
|
||||
pub closure_data: roc_std::RocList<u8>,
|
||||
}
|
||||
|
||||
impl RocFunction_67 {
|
||||
pub fn force_thunk(mut self, arg_0: ()) -> Op {
|
||||
extern "C" {
|
||||
fn roc__mainForHost_1_caller(arg_0: &(), closure_data: *mut u8, output: *mut Op);
|
||||
}
|
||||
|
||||
let mut output = std::mem::MaybeUninit::uninit();
|
||||
let ptr = self.closure_data.as_mut_ptr();
|
||||
unsafe { roc__mainForHost_1_caller(&arg_0, ptr, output.as_mut_ptr()) };
|
||||
unsafe { output.assume_init() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
#[inline(always)]
|
||||
fn storage(&self) -> Option<&core::cell::Cell<roc_std::Storage>> {
|
||||
let mask = match std::mem::size_of::<usize>() {
|
||||
4 => 0b11,
|
||||
8 => 0b111,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// NOTE: pointer provenance is probably lost here
|
||||
let unmasked_address = (self.pointer as usize) & !mask;
|
||||
let untagged = unmasked_address as *const core::cell::Cell<roc_std::Storage>;
|
||||
|
||||
if untagged.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe { Some(&*untagged.sub(1)) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
|
||||
/// Returns which variant this tag union holds. Note that this never includes a payload!
|
||||
pub fn discriminant(&self) -> discriminant_Op {
|
||||
// The discriminant is stored in the unused bytes at the end of the recursive pointer
|
||||
unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b11) }
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
|
||||
/// Internal helper
|
||||
fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op {
|
||||
// The discriminant is stored in the unused bytes at the end of the union pointer
|
||||
let untagged = (pointer as usize) & (!0b11 as usize);
|
||||
let tagged = untagged | (discriminant as usize);
|
||||
|
||||
tagged as *mut union_Op
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
|
||||
/// Internal helper
|
||||
fn union_pointer(&self) -> *mut union_Op {
|
||||
// The discriminant is stored in the unused bytes at the end of the union pointer
|
||||
((self.pointer as usize) & (!0b11 as usize)) as *mut union_Op
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
/// A tag named Done, which has no payload.
|
||||
pub const Done: Self = Self {
|
||||
pointer: core::ptr::null_mut(),
|
||||
};
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload at index 0.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
|
||||
pub unsafe fn get_StderrWrite_0(&self) -> roc_std::RocStr {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "roc__getter__2_generic"]
|
||||
fn getter(_: *mut roc_std::RocStr, _: *const Op);
|
||||
}
|
||||
|
||||
let mut ret = core::mem::MaybeUninit::uninit();
|
||||
getter(ret.as_mut_ptr(), self);
|
||||
ret.assume_init()
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload at index 1.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
|
||||
pub unsafe fn get_StderrWrite_1(&self) -> RocFunction_67 {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "roc__getter__3_size"]
|
||||
fn size() -> usize;
|
||||
|
||||
#[link_name = "roc__getter__3_generic"]
|
||||
fn getter(_: *mut u8, _: *const Op);
|
||||
}
|
||||
|
||||
// allocate memory to store this variably-sized value
|
||||
// allocates with roc_alloc, but that likely still uses the heap
|
||||
let it = std::iter::repeat(0xAAu8).take(size());
|
||||
let mut bytes = roc_std::RocList::from_iter(it);
|
||||
|
||||
getter(bytes.as_mut_ptr(), self);
|
||||
|
||||
RocFunction_67 {
|
||||
closure_data: bytes,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
/// Construct a tag named `StderrWrite`, with the appropriate payload
|
||||
pub fn StderrWrite(arg: Op_StderrWrite) -> Self {
|
||||
let size = core::mem::size_of::<union_Op>();
|
||||
let align = core::mem::align_of::<union_Op>() as u32;
|
||||
|
||||
unsafe {
|
||||
let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
|
||||
|
||||
*ptr = union_Op {
|
||||
StderrWrite: core::mem::ManuallyDrop::new(arg),
|
||||
};
|
||||
|
||||
Self {
|
||||
pointer: Self::tag_discriminant(ptr, discriminant_Op::StderrWrite),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
|
||||
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
|
||||
let mut uninitialized = core::mem::MaybeUninit::uninit();
|
||||
let swapped = unsafe {
|
||||
core::mem::replace(
|
||||
&mut (*ptr).StderrWrite,
|
||||
core::mem::ManuallyDrop::new(uninitialized.assume_init()),
|
||||
)
|
||||
};
|
||||
|
||||
core::mem::forget(self);
|
||||
|
||||
core::mem::ManuallyDrop::into_inner(swapped)
|
||||
};
|
||||
|
||||
payload
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
|
||||
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
|
||||
|
||||
unsafe { &(*ptr).StderrWrite }
|
||||
};
|
||||
|
||||
&payload
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload at index 0.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
|
||||
pub unsafe fn get_StdoutWrite_0(&self) -> roc_std::RocStr {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "roc__getter__2_generic"]
|
||||
fn getter(_: *mut roc_std::RocStr, _: *const Op);
|
||||
}
|
||||
|
||||
let mut ret = core::mem::MaybeUninit::uninit();
|
||||
getter(ret.as_mut_ptr(), self);
|
||||
ret.assume_init()
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload at index 1.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
|
||||
pub unsafe fn get_StdoutWrite_1(&self) -> RocFunction_66 {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "roc__getter__3_size"]
|
||||
fn size() -> usize;
|
||||
|
||||
#[link_name = "roc__getter__3_generic"]
|
||||
fn getter(_: *mut u8, _: *const Op);
|
||||
}
|
||||
|
||||
// allocate memory to store this variably-sized value
|
||||
// allocates with roc_alloc, but that likely still uses the heap
|
||||
let it = std::iter::repeat(0xAAu8).take(size());
|
||||
let mut bytes = roc_std::RocList::from_iter(it);
|
||||
|
||||
getter(bytes.as_mut_ptr(), self);
|
||||
|
||||
RocFunction_66 {
|
||||
closure_data: bytes,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
/// Construct a tag named `StdoutWrite`, with the appropriate payload
|
||||
pub fn StdoutWrite(arg: Op_StdoutWrite) -> Self {
|
||||
let size = core::mem::size_of::<union_Op>();
|
||||
let align = core::mem::align_of::<union_Op>() as u32;
|
||||
|
||||
unsafe {
|
||||
let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
|
||||
|
||||
*ptr = union_Op {
|
||||
StdoutWrite: core::mem::ManuallyDrop::new(arg),
|
||||
};
|
||||
|
||||
Self {
|
||||
pointer: Self::tag_discriminant(ptr, discriminant_Op::StdoutWrite),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
|
||||
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
|
||||
let mut uninitialized = core::mem::MaybeUninit::uninit();
|
||||
let swapped = unsafe {
|
||||
core::mem::replace(
|
||||
&mut (*ptr).StdoutWrite,
|
||||
core::mem::ManuallyDrop::new(uninitialized.assume_init()),
|
||||
)
|
||||
};
|
||||
|
||||
core::mem::forget(self);
|
||||
|
||||
core::mem::ManuallyDrop::into_inner(swapped)
|
||||
};
|
||||
|
||||
payload
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
|
||||
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
|
||||
|
||||
unsafe { &(*ptr).StdoutWrite }
|
||||
};
|
||||
|
||||
&payload
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
|
||||
/// Returns which variant this tag union holds. Note that this never includes a payload!
|
||||
pub fn discriminant(&self) -> discriminant_Op {
|
||||
// The discriminant is stored in the unused bytes at the end of the recursive pointer
|
||||
unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b111) }
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
|
||||
/// Internal helper
|
||||
fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op {
|
||||
// The discriminant is stored in the unused bytes at the end of the union pointer
|
||||
let untagged = (pointer as usize) & (!0b111 as usize);
|
||||
let tagged = untagged | (discriminant as usize);
|
||||
|
||||
tagged as *mut union_Op
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
|
||||
/// Internal helper
|
||||
fn union_pointer(&self) -> *mut union_Op {
|
||||
// The discriminant is stored in the unused bytes at the end of the union pointer
|
||||
((self.pointer as usize) & (!0b111 as usize)) as *mut union_Op
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
|
||||
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
|
||||
let mut uninitialized = core::mem::MaybeUninit::uninit();
|
||||
let swapped = unsafe {
|
||||
core::mem::replace(
|
||||
&mut (*ptr).StderrWrite,
|
||||
core::mem::ManuallyDrop::new(uninitialized.assume_init()),
|
||||
)
|
||||
};
|
||||
|
||||
core::mem::forget(self);
|
||||
|
||||
core::mem::ManuallyDrop::into_inner(swapped)
|
||||
};
|
||||
|
||||
payload
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
|
||||
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
|
||||
|
||||
unsafe { &(*ptr).StderrWrite }
|
||||
};
|
||||
|
||||
&payload
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
|
||||
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
|
||||
let mut uninitialized = core::mem::MaybeUninit::uninit();
|
||||
let swapped = unsafe {
|
||||
core::mem::replace(
|
||||
&mut (*ptr).StdoutWrite,
|
||||
core::mem::ManuallyDrop::new(uninitialized.assume_init()),
|
||||
)
|
||||
};
|
||||
|
||||
core::mem::forget(self);
|
||||
|
||||
core::mem::ManuallyDrop::into_inner(swapped)
|
||||
};
|
||||
|
||||
payload
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
|
||||
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload.
|
||||
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
|
||||
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
|
||||
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
|
||||
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
|
||||
let payload = {
|
||||
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
|
||||
|
||||
unsafe { &(*ptr).StdoutWrite }
|
||||
};
|
||||
|
||||
&payload
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
fn drop(&mut self) {
|
||||
// We only need to do any work if there's actually a heap-allocated payload.
|
||||
if let Some(storage) = self.storage() {
|
||||
let mut new_storage = storage.get();
|
||||
|
||||
// Decrement the refcount
|
||||
let needs_dealloc = !new_storage.is_readonly() && new_storage.decrease();
|
||||
|
||||
if needs_dealloc {
|
||||
// Drop the payload first.
|
||||
match self.discriminant() {
|
||||
discriminant_Op::Done => {}
|
||||
discriminant_Op::StderrWrite => unsafe {
|
||||
core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StderrWrite)
|
||||
},
|
||||
discriminant_Op::StdoutWrite => unsafe {
|
||||
core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StdoutWrite)
|
||||
},
|
||||
}
|
||||
|
||||
// Dealloc the pointer
|
||||
let alignment =
|
||||
core::mem::align_of::<Self>().max(core::mem::align_of::<roc_std::Storage>());
|
||||
|
||||
unsafe {
|
||||
crate::roc_dealloc(storage.as_ptr().cast(), alignment as u32);
|
||||
}
|
||||
} else {
|
||||
// Write the storage back.
|
||||
storage.set(new_storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Op {}
|
||||
|
||||
impl PartialEq for Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.discriminant() != other.discriminant() {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
match self.discriminant() {
|
||||
discriminant_Op::Done => true,
|
||||
discriminant_Op::StderrWrite => {
|
||||
(&*self.union_pointer()).StderrWrite == (&*other.union_pointer()).StderrWrite
|
||||
}
|
||||
discriminant_Op::StdoutWrite => {
|
||||
(&*self.union_pointer()).StdoutWrite == (&*other.union_pointer()).StdoutWrite
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
match self.discriminant().partial_cmp(&other.discriminant()) {
|
||||
Some(core::cmp::Ordering::Equal) => {}
|
||||
not_eq => return not_eq,
|
||||
}
|
||||
|
||||
unsafe {
|
||||
match self.discriminant() {
|
||||
discriminant_Op::Done => Some(core::cmp::Ordering::Equal),
|
||||
discriminant_Op::StderrWrite => (&*self.union_pointer())
|
||||
.StderrWrite
|
||||
.partial_cmp(&(&*other.union_pointer()).StderrWrite),
|
||||
discriminant_Op::StdoutWrite => (&*self.union_pointer())
|
||||
.StdoutWrite
|
||||
.partial_cmp(&(&*other.union_pointer()).StdoutWrite),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
match self.discriminant().cmp(&other.discriminant()) {
|
||||
core::cmp::Ordering::Equal => {}
|
||||
not_eq => return not_eq,
|
||||
}
|
||||
|
||||
unsafe {
|
||||
match self.discriminant() {
|
||||
discriminant_Op::Done => core::cmp::Ordering::Equal,
|
||||
discriminant_Op::StderrWrite => (&*self.union_pointer())
|
||||
.StderrWrite
|
||||
.cmp(&(&*other.union_pointer()).StderrWrite),
|
||||
discriminant_Op::StdoutWrite => (&*self.union_pointer())
|
||||
.StdoutWrite
|
||||
.cmp(&(&*other.union_pointer()).StdoutWrite),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
fn clone(&self) -> Self {
|
||||
if let Some(storage) = self.storage() {
|
||||
let mut new_storage = storage.get();
|
||||
if !new_storage.is_readonly() {
|
||||
new_storage.increment_reference_count();
|
||||
storage.set(new_storage);
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
pointer: self.pointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::hash::Hash for Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
match self.discriminant() {
|
||||
discriminant_Op::Done => discriminant_Op::Done.hash(state),
|
||||
discriminant_Op::StderrWrite => unsafe {
|
||||
discriminant_Op::StderrWrite.hash(state);
|
||||
(&*self.union_pointer()).StderrWrite.hash(state);
|
||||
},
|
||||
discriminant_Op::StdoutWrite => unsafe {
|
||||
discriminant_Op::StdoutWrite.hash(state);
|
||||
(&*self.union_pointer()).StdoutWrite.hash(state);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Op {
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
))]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str("Op::")?;
|
||||
|
||||
unsafe {
|
||||
match self.discriminant() {
|
||||
discriminant_Op::Done => f.write_str("Done"),
|
||||
discriminant_Op::StderrWrite => f
|
||||
.debug_tuple("StderrWrite")
|
||||
// TODO HAS CLOSURE
|
||||
.finish(),
|
||||
discriminant_Op::StdoutWrite => f
|
||||
.debug_tuple("StdoutWrite")
|
||||
// TODO HAS CLOSURE
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -113,7 +113,7 @@ pub unsafe extern "C" fn roc_shm_open(
|
|||
///
|
||||
/// TODO
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_main() -> i32 {
|
||||
pub extern "C" fn main() -> i32 {
|
||||
let mut roc_str = RocStr::default();
|
||||
unsafe { roc_main(&mut roc_str) };
|
||||
|
||||
|
@ -126,6 +126,5 @@ pub extern "C" fn rust_main() -> i32 {
|
|||
panic!("Failed to flush stdout: {:?}", e);
|
||||
}
|
||||
|
||||
// Exit code
|
||||
0
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
std::process::exit(host::rust_main() as _);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue