Skip to content

Commit

Permalink
Merge pull request #5684 from roc-lang/fix-glue
Browse files Browse the repository at this point in the history
RustGlue.roc improvements
  • Loading branch information
ayazhafiz committed Jul 24, 2023
2 parents dca5526 + d39711c commit b71c901
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 45 deletions.
13 changes: 11 additions & 2 deletions crates/compiler/builtins/roc/List.roc
Original file line number Diff line number Diff line change
Expand Up @@ -1182,8 +1182,17 @@ mapTry = \list, toResult ->
Result.map (toResult elem) \ok ->
List.append state ok

## This is the same as `iterate` but with [Result] instead of `[Continue, Break]`.
## Using `Result` saves a conditional in `mapTry`.
## Same as [List.walk], except you can stop walking early by returning `Err`.
##
## ## Performance Details
##
## Compared to [List.walk], this can potentially visit fewer elements (which can
## improve performance) at the cost of making each step take longer.
## However, the added cost to each step is extremely small, and can easily
## be outweighed if it results in skipping even a small number of elements.
##
## As such, it is typically better for performance to use this over [List.walk]
## if returning `Break` earlier than the last element is expected to be common.
walkTry : List elem, state, (state, elem -> Result state err) -> Result state err
walkTry = \list, init, func ->
walkTryHelp list init func 0 (List.len list)
Expand Down
110 changes: 72 additions & 38 deletions crates/glue/src/RustGlue.roc
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,11 @@ generateEntryPoint = \buf, types, name, id ->
when Types.shape types id is
Function rocFn ->
arguments =
rocFn.args
|> List.mapWithIndex \argId, i ->
toArgStr rocFn.args types \argId, _shape, index ->
type = typeName types argId
c = Num.toStr i
"arg\(c): \(type)"
|> Str.joinWith ", "
indexStr = Num.toStr index

"arg\(indexStr): \(type)"

ret = typeName types rocFn.ret

Expand All @@ -154,16 +153,13 @@ generateEntryPoint = \buf, types, name, id ->
when Types.shape types id is
Function rocFn ->
arguments =
rocFn.args
|> List.map \argId ->
shape = Types.shape types argId
toArgStr rocFn.args types \argId, shape, _index ->
type = typeName types argId

if canDeriveCopy types shape then
"_: \(type)"
else
"_: &mut core::mem::ManuallyDrop<\(type)>"
|> Str.joinWith ", "

ret = typeName types rocFn.ret
"(_: *mut \(ret), \(arguments))"
Expand All @@ -175,16 +171,13 @@ generateEntryPoint = \buf, types, name, id ->
externArguments =
when Types.shape types id is
Function rocFn ->
rocFn.args
|> List.mapWithIndex \argId, index ->
toArgStr rocFn.args types \_argId, shape, index ->
indexStr = Num.toStr index
shape = Types.shape types argId

if canDeriveCopy types shape then
"arg\(indexStr)"
else
"&mut core::mem::ManuallyDrop::new(arg\(indexStr))"
|> Str.joinWith ", "

_ ->
""
Expand Down Expand Up @@ -215,29 +208,40 @@ generateFunction = \buf, types, rocFn ->
lambdaSet = typeName types rocFn.lambdaSet

publicArguments =
rocFn.args
|> List.mapWithIndex \argId, i ->
toArgStr rocFn.args types \argId, _shape, index ->
type = typeName types argId
c = Num.toStr i
"arg\(c): \(type)"
|> Str.joinWith ", "
indexStr = Num.toStr index

"arg\(indexStr): \(type)"

externDefArguments =
rocFn.args
|> List.mapWithIndex \argId, i ->
type = typeName types argId
c = Num.toStr i
"arg\(c): *const \(type)"
|> Str.joinWith ", "
withoutUnit =
toArgStr rocFn.args types \argId, _shape, index ->
type = typeName types argId
indexStr = Num.toStr index

"arg\(indexStr): *const \(type)"

if Str.isEmpty withoutUnit then
# These always have a first argument that's a pointer, even if it's to nothing.
"arg0: *const ()"
else
withoutUnit

externCallArguments =
rocFn.args
|> List.mapWithIndex \_, i ->
c = Num.toStr i
"&arg\(c)"
|> Str.joinWith ", "
withoutUnit =
toArgStr rocFn.args types \_argId, _shape, index ->
indexStr = Num.toStr index

"&arg\(indexStr)"

externComma = if Str.isEmpty publicArguments then "" else ", "
if Str.isEmpty withoutUnit then
# These always have a first argument that's a pointer, even if it's to nothing.
"&()"
else
withoutUnit

publicComma = if Str.isEmpty publicArguments then "" else ", "

ret = typeName types rocFn.ret

Expand All @@ -251,20 +255,20 @@ generateFunction = \buf, types, rocFn ->
}
impl \(name) {
pub fn force_thunk(mut self, \(publicArguments)) -> \(ret) {
pub fn force_thunk(self\(publicComma)\(publicArguments)) -> \(ret) {
extern "C" {
fn \(externName)(\(externDefArguments)\(externComma) closure_data: *mut u8, output: *mut \(ret));
fn \(externName)(\(externDefArguments), closure_data: *mut u8, output: *mut \(ret));
}
let mut output = core::mem::MaybeUninit::uninit();
let ptr = &mut self.closure_data as *mut _ as *mut u8;
let closure_ptr =
(&mut core::mem::ManuallyDrop::new(self.closure_data)) as *mut _ as *mut u8;
unsafe { \(externName)(\(externCallArguments)\(externComma) ptr, output.as_mut_ptr(), ) };
// ownership of the closure is transferred back to roc
core::mem::forget(self.closure_data);
unsafe {
\(externName)(\(externCallArguments), closure_ptr, output.as_mut_ptr());
unsafe { output.assume_init() }
output.assume_init()
}
}
}
"""
Expand Down Expand Up @@ -2065,3 +2069,33 @@ nextMultipleOf = \lhs, rhs ->
when lhs % rhs is
0 -> lhs
r -> lhs + (rhs - r)


isUnit : Shape -> Bool
isUnit = \shape ->
when shape is
Unit -> Bool.true
_ -> Bool.false

toArgStr : List TypeId, Types, (TypeId, Shape, Nat -> Str) -> Str
toArgStr = \args, types, fmt ->
answer = List.walk args { state: "", index: 0 } \{ state, index }, argId ->
newState =
shape = Types.shape types argId

# Drop `()` args; they aren't FFI-safe, and nothing will get passed anyway.
if isUnit shape then
state
else
argStr = fmt argId shape index

if Str.isEmpty state then
argStr # Don't prepend a comma if this is the first one
else
state
|> Str.concat ", "
|> Str.concat argStr

{ state: newState, index: index + 1 }

answer.state
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub extern "C" fn rust_main() -> i32 {
use std::cmp::Ordering;
use std::collections::hash_set::HashSet;

let tag_union = roc_app::mainForHost(());
let tag_union = roc_app::mainForHost();

// Verify that it has all the expected traits.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub extern "C" fn rust_main() -> i32 {
use std::cmp::Ordering;
use std::collections::hash_set::HashSet;

let tag_union = roc_app::mainForHost(());
let tag_union = roc_app::mainForHost();

// Verify that it has all the expected traits.

Expand Down
2 changes: 1 addition & 1 deletion crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub extern "C" fn rust_main() -> i32 {
use std::cmp::Ordering;
use std::collections::hash_set::HashSet;

let tag_union = roc_app::mainForHost(());
let tag_union = roc_app::mainForHost();

// Eq
assert!(StrFingerTree::Empty() == StrFingerTree::Empty());
Expand Down
2 changes: 1 addition & 1 deletion crates/glue/tests/fixtures/union-with-padding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub extern "C" fn rust_main() -> i32 {
use std::cmp::Ordering;
use std::collections::hash_set::HashSet;

let tag_union = roc_app::mainForHost(());
let tag_union = roc_app::mainForHost();

// Verify that it has all the expected traits.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub extern "C" fn rust_main() -> i32 {
use std::cmp::Ordering;
use std::collections::hash_set::HashSet;

let tag_union = roc_app::mainForHost(());
let tag_union = roc_app::mainForHost();

// Verify that it has all the expected traits.

Expand Down

0 comments on commit b71c901

Please sign in to comment.