Per the Rust FFI Omnibus the following should work.
This is a rust cdylib lib.rs named "foo" made with cargo build...
use std::convert::From;
// Rust FFI Omnibus: Tuples
// http://jakegoulding.com/rust-ffi-omnibus/tuples/
// A Rust function that accepts a tuple
fn flip_things_around_rust(tup: (u32, u32)) -> (u32, u32) {
let (a, b) = tup;
(b + 1, a - 1)
}
// A struct that can be passed between C and Rust
#[repr(C)]
pub struct Tuple {
x: u32,
y: u32,
}
// Conversion functions
impl From<(u32, u32)> for Tuple {
fn from(tup: (u32, u32)) -> Tuple {
Tuple { x: tup.0, y: tup.1 }
}
}
impl From<Tuple> for (u32, u32) {
fn from(tup: Tuple) -> (u32, u32) {
(tup.x, tup.y)
}
}
// The exported C method - ORIG
//#[no_mangle]
//pub extern "C" fn flip_things_around(tup: Tuple) -> Tuple {
// flip_things_around_rust(tup.into()).into()
//}
// The exported C method - EDIT per Christoph
#[no_mangle]
pub extern "C" fn flip_things_around(tup: Tuple) -> *const Tuple {
&flip_things_around_rust(tup.into()).into()
}
And this is the raku script ffi-omnibus.raku that consumes the library via Nativecall
use NativeCall;
constant $n-path = './ffi-omnibus/target/debug/foo';
## Rust FFI Omnibus: Tuples
## http:##jakegoulding.com/rust-ffi-omnibus/tuples/
class Tuple is repr('CStruct') {
has uint32 $.x;
has uint32 $.y;
}
sub flip_things_around(Tuple) returns Tuple is native($n-path) { * }
my \initial = Tuple.new( x => 10, y => 20 );
my \result = flip_things_around(initial);
dd result;
say result.x, result.y;
There are 6 types of examples in the Rust FFI Omnibus and this is the only one that I cannot debug. It kinda works if you remove the returns Tuple and just have a Tuple argument, but no return type.
I have made a DRAFT raku module over here that has simple guidance of how to set this up (Dockerfile, cargo new ...) so you can just git clone https://github.com/p6steve/raku-Inline-Rust.git and uncomment the failing code in these two files.
Oh, and the error is Segmentation fault (core dumped) (on ubuntu)
Welcome to Rakudo™ v2022.04.
Implementing the Raku® Programming Language v6.d.
Built on MoarVM version 2022.04.
Any help / guidance much appreciated!
EDIT - Thanks to Christoph comment the segfault is now fixed.
BUT - I now have a new issue, the result is jumbled like this:
Tuple.new(x => 4252849424, y => 65535) #I added a dd
425284942465535
So looks like there is some error still ;-(
As before any help much appreciated!
Related
I was experimenting with const generics when this strange error came out: error: unconstrained generic constant. What does it mean?
Maybe I should describe what was I tried to do before actual code - I wanted to treat types as numbers, using Lisp-like Cons and Nil.
Here's an example:
use core::marker::PhantomData;
struct Nil;
struct Cons <N> (PhantomData <N>);
So '1' is Cons <Nil>, '2' - Cons <Cons <Nil>>, etc.
Then I tried to implement extracting normal number from this.
trait Len {
const N: usize;
}
impl <N: Len> Len for Cons <N> {
const N: usize = 1 + N::N;
}
impl Len for Nil {
const N: usize = 0;
}
And it works.
Then I started doing actual job: my true task was not to just experiment with generic types, but to implement mathematical vecs, just like(maybe you know) in shaders.
So I tried to implement such powerful constructor:
vec3 i = vec3(1.0, 1.0, 1);
vec4 v = vec4(i);
I have decided to treat any value as 'Piece' and then just compound pieces together.
trait Piece <T> {
type Size: Len;
fn construct(self) -> [T; Self::Size::N];
}
No problems so far. Next step is to define few auxiliary traits(since rust does not yet support negative bounds):
pub auto trait NotTuple {}
impl <T> !NotTuple for (T,) {}
pub auto trait NotList {}
impl <T, const N: usize> !NotList for [T; N] {}
I am using nightly rust, so few #![feature]-s is not a problem.
Then, we can use it:
type One = Cons <Nil>;
impl <T: Copy + From <U>, U: Copy + NotTuple + NotList> Piece <T> for U {
type Size = One;
fn construct(self) -> [T; Self::Size::N] {
[T::from(self)]
}
}
This one constructs piece from an argument.
Everything is still good.
impl <T: Copy, U: Piece <T>> Piece <T> for (U,) {
type Size = U::Size;
fn construct(self) -> [T; Self::Size::N] {
self.0.construct()
}
}
And this is where problem occurs. Compiler says that Self::Size::N is an unconstrained generic constant, and tries to help with this: try adding a 'where' bound using this expression: 'where [(); Self::Size::N]:', but this is just useless.
Can anyone explain me what is going on and how to fix this issue?
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm writing a function to fix the float precision problem in rust (among other languages). I need to choose to .floor() or .ceil() within the function based on the passed parameter. Whats the best way to approach this problem. If something other than a function serves the propose better, by all means! Thank you for your help!
fn main() {
to_round(7.987, "floor");
}
fn to_round(n: f64, floor_or_ceil: &str) -> f64 {
fn test(diff_n: f64) -> f64 {
if floor_or_ceil == "floor" {
diff_n.floor()
} else {
diff_n.ceil()
}
}
test(n)
}
If you replace your inner fn function with a closure, then the code you have will compile. Closures can refer to variables from the enclosing scope, whereas fns cannot.
fn main() {
to_round(7.987, "floor");
}
fn to_round(n: f64, floor_or_ceil: &str) -> f64 {
let test = |diff_n: f64| -> f64 {
if floor_or_ceil == "floor" {
diff_n.floor()
} else {
diff_n.ceil()
}
};
test(n)
}
However, closures do come with some caveats; in particular, they can't be generic functions, and can't be used where function pointers can be (unless they don't mention ("close over") any variables from the enclosing scope and are merely using closure syntax instead of fn syntax).
The most general-purpose clean solution to this class of problem is to explicitly pass the needed parameters, but you can minimize the clutter of it by such means as using a struct (especially if there is more than one value needed) and making the functions methods of that struct:
fn main() {
let c = MathContext { rounding_mode: "floor" };
c.to_round(7.987);
}
struct MathContext {
rounding_mode: &'static str, // Side note: this should really be an enum, not a string
// And you can add more fields here for any other parameters needed.
}
impl MathContext {
fn to_round(&self, n: f64) -> f64 {
self.test(n)
}
fn test(&self, diff_n: f64) -> f64 {
if self.rounding_mode == "floor" {
diff_n.floor()
} else {
diff_n.ceil()
}
}
}
Whether exactly this set of methods fits depends on what you're actually doing; if test is very specific to to_round then it doesn't make sense to pull it out this way. But it seems likely that this pattern might be useful elsewhere in your code, at least, if you're doing things like picking which way to round numbers.
First, you should eliminate the use of &strs as enums. Just declare an enum:
#[derive(Clone, Copy)]
enum Round {
Floor,
Ceil,
}
use ::Round::{Floor, Ceil};
fn round(n: f64, setting: Round) -> f64 {
match setting {
Floor => n.floor(),
Ceil => n.ceil(),
}
}
The second variant is using closures.
fn round_func(setting: Round) -> impl Fn(f64) -> f64 {
move |n| match setting {
Floor => n.floor(),
Ceil => n.ceil(),
}
}
This will take as input your setting and return a closure that will calculate either the floor or ceiling for you. EG you could do something like
let closure = round_func(setting);
println!("{}", closure(5.5));
println!("{}", closure(5.5));
This will take as input the configuration and return a closure that serves as a function.
In this particular case, we can actually do even better by directly returning a function pointer. The code looks like this:
fn round_func_pointer(setting: Round) -> fn(f64) -> f64 {
match setting {
Floor => f64::floor,
Ceil => f64::ceil,
}
}
The code could also be written
fn round_func_pointer(setting: Round) -> fn(f64) -> f64 {
match setting {
Floor => |n| n.floor(),
Ceil => |n| n.ceil(),
}
}
This works because the "closure" |n| n.floor() actually doesn't capture anything at all (no move keyword necessary), and therefore is compiled to a function pointer.
Class variable w/ precision and rounding mode
Rust doesn't have syntax for declaring a field in a struct as static like C++, Java, and other languages. However, it is still possible to declare a static variable that for all intents and purposes is a "class variable".
In the implementation below, the scope of the static variable CONFIG is restricted to the file it's declared in; so, in that sense it isn't a "global" variable. The struct declared within the same file has exclusive access to it, and all instances of that struct access the same variable.
To ensure that the "class variable" doesn't get clobbered by simultaneous writes from separate threads, RwLock is used to synchronize it. This incurs a small cost in performance over implementations that don't synchronize access in single-threaded environments.
The lazy_static macro sets up the "class variable" to delay initialization until the variable is actually needed at runtime.
use std::sync::RwLock;
#[macro_use]
extern crate lazy_static;
lazy_static! {
// The tuple holds (rounding-mode, precision).
static ref CONFIG: RwLock<(RoundMode, u32)> = {
RwLock::new((RoundMode::Auto, 3))
};
}
#[derive(Clone, Copy)]
pub enum RoundMode { Ceil, Floor, Auto }
The struct implementation below provides a way for client code to set the rounding mode (Auto, Ceil, and Floor) and precision (number of decimal positions to round to) for all instances of HasValue.
pub struct HasValue { value: f64 }
impl HasValue {
pub fn new(value: f64) -> Self
{
HasValue { value }
}
pub fn config() -> (RoundMode, u32)
{
*CONFIG.read().unwrap()
}
pub fn set_config(mode: RoundMode, precision: u32)
{
*CONFIG.write().unwrap() = (mode, precision);
}
pub fn round(&self) -> f64
{
use RoundMode::*;
let (mode, prec) = HasValue::config();
let base = 10_f64.powf(prec as f64);
match mode {
Auto => (self.value * base).round() / base,
Ceil => (self.value * base).ceil() / base,
Floor => (self.value * base).floor() / base,
}
}
}
Creating, configuring, printing...
fn main()
{
let v = HasValue::new(7.98555);
let r = v.round();
println!("r={:?}", r);
HasValue::set_config(RoundMode::Floor, 4);
let r = v.round();
println!("r={:?}", r);
}
I have a struct returned to C code from Rust. I have no idea if it's a good way to do things, but it does work for rebuilding the struct and freeing memory without leaks.
#[repr(C)]
pub struct s {
// ...
}
#[repr(C)]
#[allow(clippy::box_vec)]
pub struct s_arr {
arr: *const s,
n: i8,
vec: Box<Vec<s>>,
}
/// Frees memory that was returned to C code
pub unsafe extern "C" fn free_s_arr(a: *mut s_arr) {
Box::from_raw(s_arr);
}
/// Generates an array for the C code
pub unsafe extern "C" fn gen_s_arr() -> *mut s_arr {
let many_s: Vec<s> = Vec::new();
// ... logic here
Box::into_raw(Box::new(s_arr {
arr: many_s.as_mut_ptr(),
n: many_s.len() as i8,
vec: many_s,
}))
}
The C header is currently written by hand, but I wanted to try out cbindgen. The manual C definition for s_arr is:
struct s_arr {
struct s *arr;
int8_t n;
void *_;
};
cbindgen generates the following for s_arr:
typedef struct Box_Vec_s Box_Vec_s;
typedef struct s_arr {
const s *arr;
int8_t n;
Box_Vec_s vec;
} s_arr;
This doesn't work since struct Box_Vec_s is not defined. Ideally I would just want to override the cbindgen type generated for vec to make it void * since it requires no code changes and thus no additional testing, but I am open to other suggestions.
I have looked through the cbindgen documentation, though not the examples, and couldn't find anything.
Your question is a bit unclear, but I think that if I understood you right, you're confusing two things and being led down a dark alley as a result.
In C, a dynamically-sized array, as you probably know, is identified by two things:
Its starting position, as a pointer
Its length
Rust follows the same convention - a Vec<_>, below the hood, shares the same structure (well, almost. It has a capacity as well, but that's beside the point).
Passing the boxed vector on top of a pointer is not only overkill, but extremely unwise. FFI bindings may be smart, but they're not smart enough to deal with a boxed complex type most of the time.
To solve this, we're going to simplify your bindings. I've added a single element in struct S to show you how it works. I've also cleaned up your FFI boundary:
#[repr(C)]
#[no_mangle]
pub struct S {
foo: u8
}
#[repr(C)]
pub struct s_arr {
arr: *mut S,
n: usize,
cap: usize
}
// Retrieve the vector back
pub unsafe extern "C" fn recombine_s_arr(ptr: *mut S, n: usize, cap: usize) -> Vec<S> {
Vec::from_raw_parts(ptr, n, cap)
}
#[no_mangle]
pub unsafe extern "C" fn gen_s_arr() -> s_arr {
let mut many_s: Vec<S> = Vec::new();
let output = s_arr {
arr: many_s.as_mut_ptr(),
n: many_s.len(),
cap: many_s.capacity()
};
std::mem::forget(many_s);
output
}
With this, cbindgen returns the expected header definitions:
typedef struct {
uint8_t foo;
} so58311426S;
typedef struct {
so58311426S *arr;
uintptr_t n;
uintptr_t cap;
} so58311426s_arr;
so58311426s_arr gen_s_arr(void);
This allows us to call gen_s_arr() from either C or Rust and retrieve a struct that is usable across both parts of the FFI boundary (so58311426s_arr). This struct contains all we need to be able to modify our array of S (well, so58311426S according to cbindgen).
When passing through FFI, you need to make sure of a few simple things:
You cannot pass raw boxes or non-primitive types; you will almost universally need to convert down to a set of pointers or change your definitions to accomodate (as I have done here)
You most definitely do not pass raw vectors. At most, you pass a slice, as that is a primitive type (see the point above).
You make sure to std::mem::forget() whatever you do not want to deallocate, and make sure to remember to deallocate it or reform it somewhere else.
I will edit this question in an hour; I have a plane to get on to. Let me know if any of this needs clarifications and I'll get to it once I'm in the right country :-)
Context: I'm trying to parametrize a function by another function, and get it statically resolved. At a glance, the Fn trait bound seem to match my need.
What I expected to be the "wrapper" seems fine (up to now), I'm however badly stuck at just designating the method I'd like to pass on:
fn binop<T,Op:Fn<(T,T),T>>(op: Op, a:T, b:T) -> T {
// [...]
op.call((a,b))
}
fn addx(a: f64, b: f64) -> f64 {
binop(f64::add, a, b)
// ^~~~~~~~ error: unresolved name `f64::add`.
}
fn main() {
addx(1.0, 2.0);
}
I've been looking for hints in the UFCS RFC, and "randomly" tried a bunch of designation variants (up to referencing std::ops::Add::add and hopping for some magic inference to do the job), but admitedly can't get it right. Any help about (/ pointers to) the resolution mechanism would be much appreciated..
Thanks!
Fn is the new unboxed closures stuff. There’s also just straight fn(…) -> …, the simple function type. This sort of thing (bearing in mind that add takes its arguments by reference, not by value):
fn binop<T>(op: fn(&T, &T) -> T, a: &T, b: &T) -> T {
// [...]
op(a, b)
}
fn addx(a: f64, b: f64) -> f64 {
binop(Add::add, &a, &b)
}
fn main() {
addx(1.0, 2.0);
}
Run this through rustc and you get this:
error: internal compiler error: unexpected failure
note: the compiler hit an unexpected failure path. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
task 'rustc' failed at 'assertion failed: `(left == right) && (right == left)` (left: `3`, right: `0`)', /home/chris/rust/src/librustc/middle/trans/callee.rs:528
… hmm, maybe not so good in this particular case. It’s probably something to do with the trait type inference, but I couldn’t say what.
Fn* traits are unboxed closures traits, and unboxed closures are in active development right now. Some conveniences like automatic conversion from functions to their instances do not work yet, though I believe as unboxed closures are going to replace current boxed ones, something like this will work in future.
There is another problem, however. UFCS is not implemented yet, and I think they aren't going to be implemented for 1.0, so you can't specify trait methods generically now. You have to use explicit closure construction, for example:
#![feature(unboxed_closures, unboxed_closure_sugar, overloaded_calls)]
fn binop<T, Op: Fn(T, T) -> T>(op: Op, a: T, b: T) -> T {
// [...]
op(a, b)
}
fn addx(a: f64, b: f64) -> f64 {
binop(|&: a: f64, b: f64| a + b, a, b)
}
fn main() {
println!("{}", addx(1.0, 2.0));
}
(try it here)
I'm currently playing around with DynamicLibrary.
The code of my dynamic library (compiled with rustc --crate-type dylib dylib.rs):
// dylib.rs
#[no_mangle]
pub fn minicall() -> u8 {
3u8
}
And the code to call it:
// caller.rs
use std::dynamic_lib::DynamicLibrary;
fn main() {
let mut v = Vec::new();
DynamicLibrary::prepend_search_path(&::std::os::getcwd());
match DynamicLibrary::open(Some("./libdylib.so")) {
Err(e) => panic!("ERROR: {}", e),
Ok(lib) => {
println!("Unsafe bloc !");
let func = unsafe {
match lib.symbol::< fn() -> u8 >("minicall") {
Err(e) => { panic!("ERROR: {}", e) },
Ok(f) => { *f },
}
};
println!("call func !");
let new_value = func();
println!("extend vec !");
v.push(new_value);
}
}
println!("v is: {}", v);
}
I have this output :
~> ./caller
Unsafe bloc !
call func !
Illegal instruction
And here I'm quite lost. What am I doing wrong ?
The problem here is how the symbol function works. It has signature:
unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String>
A loaded library is basically a big array in memory with certain addresses labelled with a name (the symbol names). Querying for a symbol looks up the address and returns a pointer straight to it. A function in a library is a long sequence of instructions, so querying for a function's name returns a (function) pointer directly to the start. This can then be called as a normal function pointer. The Rust DynamicLibrary API is returning this pointer, that is, *mut T points directly to the chunk of memory in the dynamic library (which is supposedly/hopefully of type T).
The type fn(...) -> ... is a function pointer itself, that is, it is 8 bytes (or 4 bytes) storing the address of the start of the function it represents. Hence, calling lib.symbol::< fn() -> u8 >("minicall") is saying "find me the address of the thing called minicall (which is a pointer to a function)", it is not saying "find me the address of the thing called minicall (which is a function)". The return value of *mut (fn() -> u8) is then doubly-indirect, and dereferencing it to call it is interpreting the first 8 (or 4) bytes of the function code as a pointer (i.e. random machine instructions/function prelude), it is not executing them.
(Side-note: it would probably work if you had #[no_mangle] pub static minicall: fn() -> u8 = the_real_minicall; in your library, but you probably don't want this.)
The call to lib.symbol::<T>("minicall") is returning the exact function pointer we want (that is, it is returning a pointer to the start of the code of minicall), so it just becomes a question of expressing this to the compiler. Unfortunately, there is currently no type T that makes *mut T a function pointer, so one must first set T = u8 (i.e. lib.symbol::<u8>("minicall")) and then cast the return value to the appropriate function pointer type via transmute::<_, fn() -> u8>(pointer).
(I'm answering this even after the other answer was accepted because I don't think it explained the cause very well, just gave the solution.)
Last thing, this isn't a problem in this case, but it trips people a lot: the Rust ABI (the calling convention used for functions of type fn(...) -> ...) is not the same as the C ABI, so functions loaded from C dynamic libraries should be given type extern "C" fn(...) -> ..., not fn(...) -> ....
I think the problem stems from the fact that you are casting between incompatible types. Specifically, the dereference *f is going to point to the wrong place. I looked in the Rust code to see how the library is supposed to be used and found an example in src/librustc/plugin/load.rs. I adapted that code to your example:
let func = unsafe {
// Let this return a `*mut u8`, a very generic pointer
match lib.symbol("minicall") {
Err(e) => { fail!("ERROR: {}", e) },
// And then cast that pointer a function
Ok(f) => { std::mem::transmute::<*mut u8, fn() -> u8>(f) },
}
};
println!("call func !");
let new_value = func();
The output:
$ ./caller
Unsafe bloc !
call func !
extend vec !
v is: [3]
Since this question/answer, the std::dynamic_lib API seems to have gone away. As of this writing it looks like libloading is the most popular way of dynamically loading libraries on crates.io.