mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 15:59:20 +03:00
Merge pull request #3128 from rtfeldman/multi-arch-bindgen
Multi-arch bindgen
This commit is contained in:
commit
8bcc815661
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -3459,6 +3459,7 @@ dependencies = [
|
|||||||
"cli_utils",
|
"cli_utils",
|
||||||
"ctor",
|
"ctor",
|
||||||
"dircpy",
|
"dircpy",
|
||||||
|
"indexmap",
|
||||||
"indoc",
|
"indoc",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
@ -3473,6 +3474,8 @@ dependencies = [
|
|||||||
"roc_target",
|
"roc_target",
|
||||||
"roc_test_utils",
|
"roc_test_utils",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
@ -4113,6 +4116,8 @@ dependencies = [
|
|||||||
name = "roc_target"
|
name = "roc_target"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ roc_error_macros = { path = "../error_macros" }
|
|||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
target-lexicon = "0.12.3"
|
target-lexicon = "0.12.3"
|
||||||
clap = { version = "3.1.15", default-features = false, features = ["std", "color", "suggestions", "derive"] }
|
clap = { version = "3.1.15", default-features = false, features = ["std", "color", "suggestions", "derive"] }
|
||||||
|
strum = "0.24.0"
|
||||||
|
strum_macros = "0.24"
|
||||||
|
indexmap = "1.8.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.0.0"
|
pretty_assertions = "1.0.0"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,15 +8,17 @@ use roc_can::{
|
|||||||
use roc_load::{LoadedModule, Threading};
|
use roc_load::{LoadedModule, Threading};
|
||||||
use roc_mono::layout::LayoutCache;
|
use roc_mono::layout::LayoutCache;
|
||||||
use roc_reporting::report::RenderTarget;
|
use roc_reporting::report::RenderTarget;
|
||||||
|
use roc_target::Architecture;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
pub fn load_types(
|
pub fn load_types(
|
||||||
full_file_path: PathBuf,
|
full_file_path: PathBuf,
|
||||||
dir: &Path,
|
dir: &Path,
|
||||||
threading: Threading,
|
threading: Threading,
|
||||||
) -> Result<Types, io::Error> {
|
) -> Result<Vec<(Architecture, Types)>, io::Error> {
|
||||||
// TODO: generate both 32-bit and 64-bit #[cfg] macros if structs are different
|
// TODO: generate both 32-bit and 64-bit #[cfg] macros if structs are different
|
||||||
// depending on 32-bit vs 64-bit targets.
|
// depending on 32-bit vs 64-bit targets.
|
||||||
let target_info = (&Triple::host()).into();
|
let target_info = (&Triple::host()).into();
|
||||||
@ -56,7 +58,10 @@ pub fn load_types(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut layout_cache = LayoutCache::new(target_info);
|
let mut answer = Vec::with_capacity(Architecture::iter().size_hint().0);
|
||||||
|
|
||||||
|
for architecture in Architecture::iter() {
|
||||||
|
let mut layout_cache = LayoutCache::new(architecture.into());
|
||||||
let mut env = Env {
|
let mut env = Env {
|
||||||
arena,
|
arena,
|
||||||
layout_cache: &mut layout_cache,
|
layout_cache: &mut layout_cache,
|
||||||
@ -65,27 +70,24 @@ pub fn load_types(
|
|||||||
enum_names: Default::default(),
|
enum_names: Default::default(),
|
||||||
subs,
|
subs,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut types = Types::default();
|
let mut types = Types::default();
|
||||||
|
|
||||||
for decl in decls.into_iter() {
|
for decl in decls.iter() {
|
||||||
let defs = match decl {
|
let defs = match decl {
|
||||||
Declaration::Declare(def) => {
|
Declaration::Declare(def) => {
|
||||||
vec![def]
|
vec![def.clone()]
|
||||||
}
|
}
|
||||||
Declaration::DeclareRec(defs, cycle_mark) => {
|
Declaration::DeclareRec(defs, cycle_mark) => {
|
||||||
if cycle_mark.is_illegal(subs) {
|
if cycle_mark.is_illegal(subs) {
|
||||||
vec![]
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
defs
|
defs.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Declaration::Builtin(..) => {
|
Declaration::Builtin(..) => {
|
||||||
unreachable!("Builtin decl in userspace module?")
|
unreachable!("Builtin decl in userspace module?")
|
||||||
}
|
}
|
||||||
Declaration::InvalidCycle(..) => {
|
Declaration::InvalidCycle(..) => Vec::new(),
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for Def {
|
for Def {
|
||||||
@ -107,5 +109,8 @@ pub fn load_types(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(types)
|
answer.push((architecture, types));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(answer)
|
||||||
}
|
}
|
||||||
|
@ -57,30 +57,21 @@ pub fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match load_types(input_path.clone(), &cwd, Threading::AllAvailable) {
|
match load_types(input_path.clone(), &cwd, Threading::AllAvailable) {
|
||||||
Ok(types) => {
|
Ok(types_by_architecture) => {
|
||||||
let mut buf;
|
let mut buf;
|
||||||
|
|
||||||
let result = match output_type {
|
match output_type {
|
||||||
OutputType::Rust => {
|
OutputType::Rust => {
|
||||||
buf = std::str::from_utf8(bindgen_rs::HEADER).unwrap().to_string();
|
buf = std::str::from_utf8(bindgen_rs::HEADER).unwrap().to_string();
|
||||||
|
let body = bindgen_rs::emit(&types_by_architecture);
|
||||||
|
|
||||||
bindgen_rs::write_types(&types, &mut buf)
|
buf.push_str(&body);
|
||||||
}
|
}
|
||||||
OutputType::C => todo!("TODO: Generate bindings for C"),
|
OutputType::C => todo!("TODO: Generate bindings for C"),
|
||||||
OutputType::Zig => todo!("TODO: Generate bindings for Zig"),
|
OutputType::Zig => todo!("TODO: Generate bindings for Zig"),
|
||||||
OutputType::Json => todo!("TODO: Generate bindings for JSON"),
|
OutputType::Json => todo!("TODO: Generate bindings for JSON"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = result {
|
|
||||||
eprintln!(
|
|
||||||
"Unable to generate binding string {} - {:?}",
|
|
||||||
output_path.display(),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut file = File::create(output_path.clone()).unwrap_or_else(|err| {
|
let mut file = File::create(output_path.clone()).unwrap_or_else(|err| {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Unable to create output file {} - {:?}",
|
"Unable to create output file {} - {:?}",
|
||||||
|
@ -9,7 +9,7 @@ use std::convert::TryInto;
|
|||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct TypeId(usize);
|
pub struct TypeId(usize);
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct Types {
|
pub struct Types {
|
||||||
by_id: Vec<RocType>,
|
by_id: Vec<RocType>,
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
mod bindings;
|
mod bindings;
|
||||||
|
|
||||||
|
use bindings::NonRecursive;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "roc__mainForHost_1_exposed_generic"]
|
#[link_name = "roc__mainForHost_1_exposed_generic"]
|
||||||
fn roc_main(_: *mut bindings::NonRecursive);
|
fn roc_main(_: *mut NonRecursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -11,8 +13,7 @@ pub extern "C" fn rust_main() -> i32 {
|
|||||||
use std::collections::hash_set::HashSet;
|
use std::collections::hash_set::HashSet;
|
||||||
|
|
||||||
let tag_union = unsafe {
|
let tag_union = unsafe {
|
||||||
let mut ret: core::mem::MaybeUninit<bindings::NonRecursive> =
|
let mut ret: core::mem::MaybeUninit<NonRecursive> = core::mem::MaybeUninit::uninit();
|
||||||
core::mem::MaybeUninit::uninit();
|
|
||||||
|
|
||||||
roc_main(ret.as_mut_ptr());
|
roc_main(ret.as_mut_ptr());
|
||||||
|
|
||||||
@ -30,11 +31,11 @@ pub extern "C" fn rust_main() -> i32 {
|
|||||||
println!(
|
println!(
|
||||||
"tag_union was: {:?}\n`Foo \"small str\"` is: {:?}\n`Foo \"A long enough string to not be small\"` is: {:?}\n`Bar 123` is: {:?}\n`Baz` is: {:?}\n`Blah 456` is: {:?}",
|
"tag_union was: {:?}\n`Foo \"small str\"` is: {:?}\n`Foo \"A long enough string to not be small\"` is: {:?}\n`Bar 123` is: {:?}\n`Baz` is: {:?}\n`Blah 456` is: {:?}",
|
||||||
tag_union,
|
tag_union,
|
||||||
bindings::NonRecursive::Foo("small str".into()),
|
NonRecursive::Foo("small str".into()),
|
||||||
bindings::NonRecursive::Foo("A long enough string to not be small".into()),
|
NonRecursive::Foo("A long enough string to not be small".into()),
|
||||||
bindings::NonRecursive::Bar(123.into()),
|
NonRecursive::Bar(123.into()),
|
||||||
bindings::NonRecursive::Baz,
|
NonRecursive::Baz,
|
||||||
bindings::NonRecursive::Blah(456),
|
NonRecursive::Blah(456),
|
||||||
); // Debug
|
); // Debug
|
||||||
|
|
||||||
let mut set = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
|
@ -27,6 +27,13 @@ mod test_gen_rs {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct MyRcd {
|
pub struct MyRcd {
|
||||||
@ -57,6 +64,10 @@ mod test_gen_rs {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "aarch64"
|
||||||
|
))]
|
||||||
#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Outer {
|
pub struct Outer {
|
||||||
@ -65,12 +76,32 @@ mod test_gen_rs {
|
|||||||
pub x: Inner,
|
pub x: Inner,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Inner {
|
pub struct Inner {
|
||||||
pub b: f32,
|
pub b: f32,
|
||||||
pub a: u16,
|
pub a: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Outer {
|
||||||
|
pub x: Inner,
|
||||||
|
pub y: roc_std::RocStr,
|
||||||
|
pub z: roc_std::RocList<u8>,
|
||||||
|
}
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -86,6 +117,13 @@ mod test_gen_rs {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct R1 {
|
pub struct R1 {
|
||||||
@ -107,6 +145,10 @@ mod test_gen_rs {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "aarch64"
|
||||||
|
))]
|
||||||
#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct R1 {
|
pub struct R1 {
|
||||||
@ -115,311 +157,32 @@ mod test_gen_rs {
|
|||||||
pub x: R2,
|
pub x: R2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct R2 {
|
pub struct R2 {
|
||||||
pub b: f32,
|
pub b: f32,
|
||||||
pub a: u16,
|
pub a: u16,
|
||||||
}
|
}
|
||||||
"#
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn tag_union_aliased() {
|
|
||||||
let module = indoc!(
|
|
||||||
r#"
|
|
||||||
NonRecursive : [Foo Str, Bar U128, Blah I32, Baz]
|
|
||||||
|
|
||||||
main : NonRecursive
|
|
||||||
main = Foo "blah"
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
generate_bindings(module)
|
|
||||||
.strip_prefix('\n')
|
|
||||||
.unwrap_or_default(),
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
#[derive(Clone, Copy, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum tag_NonRecursive {
|
|
||||||
Bar = 0,
|
|
||||||
Baz = 1,
|
|
||||||
Blah = 2,
|
|
||||||
Foo = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Debug for tag_NonRecursive {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Bar => f.write_str("tag_NonRecursive::Bar"),
|
|
||||||
Self::Baz => f.write_str("tag_NonRecursive::Baz"),
|
|
||||||
Self::Blah => f.write_str("tag_NonRecursive::Blah"),
|
|
||||||
Self::Foo => f.write_str("tag_NonRecursive::Foo"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub union NonRecursive {
|
pub struct R1 {
|
||||||
Bar: roc_std::U128,
|
pub x: R2,
|
||||||
Blah: i32,
|
pub y: roc_std::RocStr,
|
||||||
Foo: core::mem::ManuallyDrop<roc_std::RocStr>,
|
pub z: roc_std::RocList<u8>,
|
||||||
_size_with_discriminant: [u8; 32],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonRecursive {
|
|
||||||
pub fn tag(&self) -> tag_NonRecursive {
|
|
||||||
unsafe {
|
|
||||||
let bytes = core::mem::transmute::<&Self, &[u8; core::mem::size_of::<Self>()]>(self);
|
|
||||||
|
|
||||||
core::mem::transmute::<u8, tag_NonRecursive>(*bytes.as_ptr().add(24))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Internal helper
|
|
||||||
fn set_discriminant(&mut self, tag: tag_NonRecursive) {
|
|
||||||
let discriminant_ptr: *mut tag_NonRecursive = (self as *mut NonRecursive).cast();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
*(discriminant_ptr.add(24)) = tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a tag named Bar, with the appropriate payload
|
|
||||||
pub fn Bar(payload: roc_std::U128) -> Self {
|
|
||||||
let mut answer = Self {
|
|
||||||
Bar: payload
|
|
||||||
};
|
|
||||||
|
|
||||||
answer.set_discriminant(tag_NonRecursive::Bar);
|
|
||||||
|
|
||||||
answer
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given NonRecursive has a .tag() of Bar and convert it to Bar's payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Bar.
|
|
||||||
pub unsafe fn into_Bar(self) -> roc_std::U128 {
|
|
||||||
debug_assert_eq!(self.tag(), tag_NonRecursive::Bar);
|
|
||||||
self.Bar
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given NonRecursive has a .tag() of Bar and return its payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Bar.
|
|
||||||
pub unsafe fn as_Bar(&self) -> roc_std::U128 {
|
|
||||||
debug_assert_eq!(self.tag(), tag_NonRecursive::Bar);
|
|
||||||
self.Bar
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A tag named Baz, which has no payload.
|
|
||||||
pub const Baz: Self = unsafe {
|
|
||||||
let mut bytes = [0; core::mem::size_of::<NonRecursive>()];
|
|
||||||
|
|
||||||
bytes[24] = tag_NonRecursive::Baz as u8;
|
|
||||||
|
|
||||||
core::mem::transmute::<[u8; core::mem::size_of::<NonRecursive>()], NonRecursive>(bytes)
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Other `into_` methods return a payload, but since the Baz tag
|
|
||||||
/// has no payload, this does nothing and is only here for completeness.
|
|
||||||
pub fn into_Baz(self) {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Other `as` methods return a payload, but since the Baz tag
|
|
||||||
/// has no payload, this does nothing and is only here for completeness.
|
|
||||||
pub unsafe fn as_Baz(&self) {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a tag named Blah, with the appropriate payload
|
|
||||||
pub fn Blah(payload: i32) -> Self {
|
|
||||||
let mut answer = Self {
|
|
||||||
Blah: payload
|
|
||||||
};
|
|
||||||
|
|
||||||
answer.set_discriminant(tag_NonRecursive::Blah);
|
|
||||||
|
|
||||||
answer
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given NonRecursive has a .tag() of Blah and convert it to Blah's payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Blah.
|
|
||||||
pub unsafe fn into_Blah(self) -> i32 {
|
|
||||||
debug_assert_eq!(self.tag(), tag_NonRecursive::Blah);
|
|
||||||
self.Blah
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given NonRecursive has a .tag() of Blah and return its payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Blah.
|
|
||||||
pub unsafe fn as_Blah(&self) -> i32 {
|
|
||||||
debug_assert_eq!(self.tag(), tag_NonRecursive::Blah);
|
|
||||||
self.Blah
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a tag named Foo, with the appropriate payload
|
|
||||||
pub fn Foo(payload: roc_std::RocStr) -> Self {
|
|
||||||
let mut answer = Self {
|
|
||||||
Foo: core::mem::ManuallyDrop::new(payload)
|
|
||||||
};
|
|
||||||
|
|
||||||
answer.set_discriminant(tag_NonRecursive::Foo);
|
|
||||||
|
|
||||||
answer
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given NonRecursive has a .tag() of Foo and convert it to Foo's payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Foo.
|
|
||||||
pub unsafe fn into_Foo(mut self) -> roc_std::RocStr {
|
|
||||||
debug_assert_eq!(self.tag(), tag_NonRecursive::Foo);
|
|
||||||
core::mem::ManuallyDrop::take(&mut self.Foo)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given NonRecursive has a .tag() of Foo and return its payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Foo.
|
|
||||||
pub unsafe fn as_Foo(&self) -> &roc_std::RocStr {
|
|
||||||
debug_assert_eq!(self.tag(), tag_NonRecursive::Foo);
|
|
||||||
&self.Foo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for NonRecursive {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
match self.tag() {
|
|
||||||
tag_NonRecursive::Bar => {}
|
|
||||||
tag_NonRecursive::Baz => {}
|
|
||||||
tag_NonRecursive::Blah => {}
|
|
||||||
tag_NonRecursive::Foo => unsafe { core::mem::ManuallyDrop::drop(&mut self.Foo) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for NonRecursive {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
if self.tag() != other.tag() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
match self.tag() {
|
|
||||||
tag_NonRecursive::Bar => self.Bar == other.Bar,
|
|
||||||
tag_NonRecursive::Baz => true,
|
|
||||||
tag_NonRecursive::Blah => self.Blah == other.Blah,
|
|
||||||
tag_NonRecursive::Foo => self.Foo == other.Foo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for NonRecursive {}
|
|
||||||
|
|
||||||
impl PartialOrd for NonRecursive {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
|
||||||
match self.tag().partial_cmp(&other.tag()) {
|
|
||||||
Some(core::cmp::Ordering::Equal) => {}
|
|
||||||
not_eq => return not_eq,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
match self.tag() {
|
|
||||||
tag_NonRecursive::Bar => self.Bar.partial_cmp(&other.Bar),
|
|
||||||
tag_NonRecursive::Baz => Some(core::cmp::Ordering::Equal),
|
|
||||||
tag_NonRecursive::Blah => self.Blah.partial_cmp(&other.Blah),
|
|
||||||
tag_NonRecursive::Foo => self.Foo.partial_cmp(&other.Foo),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for NonRecursive {
|
|
||||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
|
||||||
match self.tag().cmp(&other.tag()) {
|
|
||||||
core::cmp::Ordering::Equal => {}
|
|
||||||
not_eq => return not_eq,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
match self.tag() {
|
|
||||||
tag_NonRecursive::Bar => self.Bar.cmp(&other.Bar),
|
|
||||||
tag_NonRecursive::Baz => core::cmp::Ordering::Equal,
|
|
||||||
tag_NonRecursive::Blah => self.Blah.cmp(&other.Blah),
|
|
||||||
tag_NonRecursive::Foo => self.Foo.cmp(&other.Foo),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for NonRecursive {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let mut answer = unsafe {
|
|
||||||
match self.tag() {
|
|
||||||
tag_NonRecursive::Bar => Self {
|
|
||||||
Bar: self.Bar.clone(),
|
|
||||||
},
|
|
||||||
tag_NonRecursive::Baz => core::mem::transmute::<
|
|
||||||
core::mem::MaybeUninit<NonRecursive>,
|
|
||||||
NonRecursive,
|
|
||||||
>(core::mem::MaybeUninit::uninit()),
|
|
||||||
tag_NonRecursive::Blah => Self {
|
|
||||||
Blah: self.Blah.clone(),
|
|
||||||
},
|
|
||||||
tag_NonRecursive::Foo => Self {
|
|
||||||
Foo: self.Foo.clone(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
answer.set_discriminant(self.tag());
|
|
||||||
|
|
||||||
answer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::hash::Hash for NonRecursive {
|
|
||||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
match self.tag() {
|
|
||||||
tag_NonRecursive::Bar => unsafe {
|
|
||||||
tag_NonRecursive::Bar.hash(state);
|
|
||||||
self.Bar.hash(state);
|
|
||||||
},
|
|
||||||
tag_NonRecursive::Baz => tag_NonRecursive::Baz.hash(state),
|
|
||||||
tag_NonRecursive::Blah => unsafe {
|
|
||||||
tag_NonRecursive::Blah.hash(state);
|
|
||||||
self.Blah.hash(state);
|
|
||||||
},
|
|
||||||
tag_NonRecursive::Foo => unsafe {
|
|
||||||
tag_NonRecursive::Foo.hash(state);
|
|
||||||
self.Foo.hash(state);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Debug for NonRecursive {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.write_str("NonRecursive::")?;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
match self.tag() {
|
|
||||||
tag_NonRecursive::Bar => f.debug_tuple("Bar").field(&self.Bar).finish(),
|
|
||||||
tag_NonRecursive::Baz => f.write_str("Baz"),
|
|
||||||
tag_NonRecursive::Blah => f.debug_tuple("Blah").field(&self.Blah).finish(),
|
|
||||||
tag_NonRecursive::Foo => f.debug_tuple("Foo").field(&*self.Foo).finish(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -442,6 +205,13 @@ mod test_gen_rs {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
#[derive(Clone, Copy, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Enumeration {
|
pub enum Enumeration {
|
||||||
@ -481,12 +251,28 @@ mod test_gen_rs {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "aarch64"
|
||||||
|
))]
|
||||||
#[derive(Clone, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct UserId {
|
pub struct UserId {
|
||||||
pub f1: roc_std::RocStr,
|
pub f1: roc_std::RocStr,
|
||||||
pub f0: u32,
|
pub f0: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
|
#[derive(Clone, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct UserId {
|
||||||
|
pub f0: u32,
|
||||||
|
pub f1: roc_std::RocStr,
|
||||||
|
}
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -509,6 +295,13 @@ mod test_gen_rs {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
#[cfg(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "wasm32"
|
||||||
|
))]
|
||||||
#[derive(Clone, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct UserId(roc_std::RocStr);
|
pub struct UserId(roc_std::RocStr);
|
||||||
@ -516,276 +309,4 @@ mod test_gen_rs {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cons_list_of_strings() {
|
|
||||||
let module = indoc!(
|
|
||||||
r#"
|
|
||||||
StrConsList : [Nil, Cons Str StrConsList]
|
|
||||||
|
|
||||||
main : StrConsList
|
|
||||||
main = Cons "Hello, " (Cons "World!" Nil)
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
generate_bindings(module)
|
|
||||||
.strip_prefix('\n')
|
|
||||||
.unwrap_or_default(),
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
#[derive(Clone, Copy, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum tag_StrConsList {
|
|
||||||
Cons = 0,
|
|
||||||
Nil = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Debug for tag_StrConsList {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Cons => f.write_str("tag_StrConsList::Cons"),
|
|
||||||
Self::Nil => f.write_str("tag_StrConsList::Nil"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct StrConsList {
|
|
||||||
pointer: *mut core::mem::ManuallyDrop<roc_std::RocStr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StrConsList {
|
|
||||||
pub fn tag(&self) -> tag_StrConsList {
|
|
||||||
if self.pointer.is_null() {
|
|
||||||
tag_StrConsList::Nil
|
|
||||||
} else {
|
|
||||||
tag_StrConsList::Cons
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a tag named Cons, with the appropriate payload
|
|
||||||
pub fn Cons(payload: roc_std::RocStr) -> Self {
|
|
||||||
let size = core::mem::size_of::<roc_std::RocStr>();
|
|
||||||
let align = core::mem::align_of::<roc_std::RocStr>();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let pointer = crate::roc_alloc(size, align as u32) as *mut core::mem::ManuallyDrop<roc_std::RocStr>;
|
|
||||||
|
|
||||||
*pointer = core::mem::ManuallyDrop::new(payload);
|
|
||||||
|
|
||||||
Self { pointer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given StrConsList has a .tag() of Cons and convert it to Cons's payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Cons.
|
|
||||||
pub unsafe fn into_Cons(self) -> roc_std::RocStr {
|
|
||||||
debug_assert_eq!(self.tag(), tag_StrConsList::Cons);
|
|
||||||
|
|
||||||
let payload = core::mem::ManuallyDrop::take(&mut *self.pointer);
|
|
||||||
let align = core::mem::align_of::<roc_std::RocStr>() as u32;
|
|
||||||
|
|
||||||
crate::roc_dealloc(self.pointer as *mut core::ffi::c_void, align);
|
|
||||||
|
|
||||||
payload
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given StrConsList has a .tag() of Cons and return its payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Cons.
|
|
||||||
pub unsafe fn as_Cons(&self) -> &roc_std::RocStr {
|
|
||||||
debug_assert_eq!(self.tag(), tag_StrConsList::Cons);
|
|
||||||
&*self.pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a tag named Nil
|
|
||||||
pub fn Nil() -> Self {
|
|
||||||
Self {
|
|
||||||
pointer: core::ptr::null_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Other `into_` methods return a payload, but since the Nil tag
|
|
||||||
/// has no payload, this does nothing and is only here for completeness.
|
|
||||||
pub fn into_Nil(self) {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Other `as` methods return a payload, but since the Nil tag
|
|
||||||
/// has no payload, this does nothing and is only here for completeness.
|
|
||||||
pub unsafe fn as_Nil(&self) {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for StrConsList {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if !self.pointer.is_null() {
|
|
||||||
let payload = unsafe { &*self.pointer };
|
|
||||||
let align = core::mem::align_of::<roc_std::RocStr>() as u32;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
crate::roc_dealloc(self.pointer as *mut core::ffi::c_void, align);
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Debug for StrConsList {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
if self.pointer.is_null() {
|
|
||||||
f.write_str("StrConsList::Nil")
|
|
||||||
} else {
|
|
||||||
f.write_str("StrConsList::")?;
|
|
||||||
|
|
||||||
unsafe { f.debug_tuple("Cons").field(&**self.pointer).finish() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"#
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cons_list_of_ints() {
|
|
||||||
let module = indoc!(
|
|
||||||
r#"
|
|
||||||
IntConsList : [Empty, Prepend U16 IntConsList]
|
|
||||||
|
|
||||||
main : IntConsList
|
|
||||||
main = Prepend 42 (Prepend 26 Empty)
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
generate_bindings(module)
|
|
||||||
.strip_prefix('\n')
|
|
||||||
.unwrap_or_default(),
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
#[derive(Clone, Copy, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum tag_IntConsList {
|
|
||||||
Empty = 0,
|
|
||||||
Prepend = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Debug for tag_IntConsList {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Empty => f.write_str("tag_IntConsList::Empty"),
|
|
||||||
Self::Prepend => f.write_str("tag_IntConsList::Prepend"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct IntConsList {
|
|
||||||
pointer: *mut u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntConsList {
|
|
||||||
pub fn tag(&self) -> tag_IntConsList {
|
|
||||||
if self.pointer.is_null() {
|
|
||||||
tag_IntConsList::Empty
|
|
||||||
} else {
|
|
||||||
tag_IntConsList::Prepend
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a tag named Prepend, with the appropriate payload
|
|
||||||
pub fn Prepend(payload: u16) -> Self {
|
|
||||||
let size = core::mem::size_of::<u16>();
|
|
||||||
let align = core::mem::align_of::<u16>();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let pointer = crate::roc_alloc(size, align as u32) as *mut u16;
|
|
||||||
|
|
||||||
*pointer = payload;
|
|
||||||
|
|
||||||
Self { pointer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given IntConsList has a .tag() of Prepend and convert it to Prepend's payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Prepend.
|
|
||||||
pub unsafe fn into_Prepend(self) -> u16 {
|
|
||||||
debug_assert_eq!(self.tag(), tag_IntConsList::Prepend);
|
|
||||||
|
|
||||||
let payload = *self.pointer;
|
|
||||||
let align = core::mem::align_of::<u16>() as u32;
|
|
||||||
|
|
||||||
crate::roc_dealloc(self.pointer as *mut core::ffi::c_void, align);
|
|
||||||
|
|
||||||
payload
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsafely assume the given IntConsList has a .tag() of Prepend and return its payload.
|
|
||||||
/// (Always examine .tag() first to make sure this is the correct variant!)
|
|
||||||
/// Panics in debug builds if the .tag() doesn't return Prepend.
|
|
||||||
pub unsafe fn as_Prepend(&self) -> u16 {
|
|
||||||
debug_assert_eq!(self.tag(), tag_IntConsList::Prepend);
|
|
||||||
*self.pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a tag named Empty
|
|
||||||
pub fn Empty() -> Self {
|
|
||||||
Self {
|
|
||||||
pointer: core::ptr::null_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Other `into_` methods return a payload, but since the Empty tag
|
|
||||||
/// has no payload, this does nothing and is only here for completeness.
|
|
||||||
pub fn into_Empty(self) {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Other `as` methods return a payload, but since the Empty tag
|
|
||||||
/// has no payload, this does nothing and is only here for completeness.
|
|
||||||
pub unsafe fn as_Empty(&self) {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for IntConsList {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if !self.pointer.is_null() {
|
|
||||||
let payload = unsafe { &*self.pointer };
|
|
||||||
let align = core::mem::align_of::<u16>() as u32;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
crate::roc_dealloc(self.pointer as *mut core::ffi::c_void, align);
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Debug for IntConsList {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
if self.pointer.is_null() {
|
|
||||||
f.write_str("IntConsList::Empty")
|
|
||||||
} else {
|
|
||||||
f.write_str("IntConsList::")?;
|
|
||||||
|
|
||||||
unsafe { f.debug_tuple("Prepend").field(&*self.pointer).finish() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"#
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ pub fn generate_bindings(decl_src: &str) -> String {
|
|||||||
|
|
||||||
src.push_str(decl_src);
|
src.push_str(decl_src);
|
||||||
|
|
||||||
let types = {
|
let pairs = {
|
||||||
let dir = tempdir().expect("Unable to create tempdir");
|
let dir = tempdir().expect("Unable to create tempdir");
|
||||||
let filename = PathBuf::from("Package-Config.roc");
|
let filename = PathBuf::from("Package-Config.roc");
|
||||||
let file_path = dir.path().join(filename);
|
let file_path = dir.path().join(filename);
|
||||||
@ -40,13 +40,7 @@ pub fn generate_bindings(decl_src: &str) -> String {
|
|||||||
result.expect("had problems loading")
|
result.expect("had problems loading")
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reuse the `src` allocation since we're done with it.
|
bindgen_rs::emit(&pairs)
|
||||||
let mut buf = src;
|
|
||||||
buf.clear();
|
|
||||||
|
|
||||||
bindgen_rs::write_types(&types, &mut buf).expect("I/O error when writing bindgen string");
|
|
||||||
|
|
||||||
buf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -60,11 +60,8 @@ impl FloatWidth {
|
|||||||
match self {
|
match self {
|
||||||
F32 => 4,
|
F32 => 4,
|
||||||
F64 | F128 => match target_info.architecture {
|
F64 | F128 => match target_info.architecture {
|
||||||
Architecture::X86_64
|
Architecture::X86_64 | Architecture::Aarch64 | Architecture::Wasm32 => 8,
|
||||||
| Architecture::Aarch64
|
Architecture::X86_32 | Architecture::Aarch32 => 4,
|
||||||
| Architecture::Arm
|
|
||||||
| Architecture::Wasm32 => 8,
|
|
||||||
Architecture::X86_32 => 4,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +126,7 @@ impl IntWidth {
|
|||||||
U64 | I64 => match target_info.architecture {
|
U64 | I64 => match target_info.architecture {
|
||||||
Architecture::X86_64
|
Architecture::X86_64
|
||||||
| Architecture::Aarch64
|
| Architecture::Aarch64
|
||||||
| Architecture::Arm
|
| Architecture::Aarch32
|
||||||
| Architecture::Wasm32 => 8,
|
| Architecture::Wasm32 => 8,
|
||||||
Architecture::X86_32 => 4,
|
Architecture::X86_32 => 4,
|
||||||
},
|
},
|
||||||
|
@ -7,3 +7,5 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
target-lexicon = "0.12.3"
|
target-lexicon = "0.12.3"
|
||||||
|
strum = "0.24.0"
|
||||||
|
strum_macros = "0.24"
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
|
|
||||||
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TargetInfo {
|
pub struct TargetInfo {
|
||||||
pub architecture: Architecture,
|
pub architecture: Architecture,
|
||||||
@ -50,6 +52,12 @@ impl From<&target_lexicon::Triple> for TargetInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Architecture> for TargetInfo {
|
||||||
|
fn from(architecture: Architecture) -> Self {
|
||||||
|
Self { architecture }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum PtrWidth {
|
pub enum PtrWidth {
|
||||||
@ -57,12 +65,12 @@ pub enum PtrWidth {
|
|||||||
Bytes8 = 8,
|
Bytes8 = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumIter)]
|
||||||
pub enum Architecture {
|
pub enum Architecture {
|
||||||
X86_64,
|
X86_64,
|
||||||
X86_32,
|
X86_32,
|
||||||
Aarch64,
|
Aarch64,
|
||||||
Arm,
|
Aarch32,
|
||||||
Wasm32,
|
Wasm32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +79,8 @@ impl Architecture {
|
|||||||
use Architecture::*;
|
use Architecture::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
X86_64 | Aarch64 | Arm => PtrWidth::Bytes8,
|
X86_64 | Aarch64 => PtrWidth::Bytes8,
|
||||||
X86_32 | Wasm32 => PtrWidth::Bytes4,
|
X86_32 | Aarch32 | Wasm32 => PtrWidth::Bytes4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +95,7 @@ impl From<target_lexicon::Architecture> for Architecture {
|
|||||||
target_lexicon::Architecture::X86_64 => Architecture::X86_64,
|
target_lexicon::Architecture::X86_64 => Architecture::X86_64,
|
||||||
target_lexicon::Architecture::X86_32(_) => Architecture::X86_32,
|
target_lexicon::Architecture::X86_32(_) => Architecture::X86_32,
|
||||||
target_lexicon::Architecture::Aarch64(_) => Architecture::Aarch64,
|
target_lexicon::Architecture::Aarch64(_) => Architecture::Aarch64,
|
||||||
target_lexicon::Architecture::Arm(_) => Architecture::Arm,
|
target_lexicon::Architecture::Arm(_) => Architecture::Aarch32,
|
||||||
target_lexicon::Architecture::Wasm32 => Architecture::Wasm32,
|
target_lexicon::Architecture::Wasm32 => Architecture::Wasm32,
|
||||||
_ => unreachable!("unsupported architecture"),
|
_ => unreachable!("unsupported architecture"),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user