Skip to content

Commit 1097961

Browse files
authored
Merge pull request #3111 from Skgland/ffi-non-fixed-sized-integers
add support for non-fixed-width integers types for ffi
2 parents 476c171 + f8b9944 commit 1097961

File tree

2 files changed

+95
-19
lines changed

2 files changed

+95
-19
lines changed

src/ffi.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,49 @@ enum FfiType {
399399
Struct(Atom),
400400
}
401401

402+
trait ToFfiType {
403+
const TYPE: FfiType;
404+
}
405+
406+
macro_rules! impl_to_ffi_type {
407+
($($t:ty => $v:ident);*$(;)?) => {
408+
$(
409+
impl ToFfiType for $t {
410+
const TYPE: FfiType = FfiType::$v;
411+
}
412+
)*
413+
};
414+
}
415+
416+
impl_to_ffi_type!(
417+
u8 => U8;
418+
i8 => I8;
419+
u16 => U16;
420+
i16 => I16;
421+
u32 => U32;
422+
i32 => I32;
423+
u64 => U64;
424+
i64 => I64;
425+
f32 => F32;
426+
f64 => F64;
427+
);
428+
402429
impl FfiType {
403430
fn from_atom(atom: &Atom) -> Self {
404431
match atom {
432+
atom!("char") => <core::ffi::c_char as ToFfiType>::TYPE,
433+
atom!("uchar") => <core::ffi::c_uchar as ToFfiType>::TYPE,
434+
atom!("schar") => <core::ffi::c_schar as ToFfiType>::TYPE,
435+
atom!("short") => <core::ffi::c_short as ToFfiType>::TYPE,
436+
atom!("ushort") => <core::ffi::c_ushort as ToFfiType>::TYPE,
437+
atom!("int") => <core::ffi::c_int as ToFfiType>::TYPE,
438+
atom!("uint") => <core::ffi::c_uint as ToFfiType>::TYPE,
439+
atom!("long") => <core::ffi::c_long as ToFfiType>::TYPE,
440+
atom!("ulong") => <core::ffi::c_ulong as ToFfiType>::TYPE,
441+
atom!("longlong") => <core::ffi::c_longlong as ToFfiType>::TYPE,
442+
atom!("ulonglong") => <core::ffi::c_ulonglong as ToFfiType>::TYPE,
443+
atom!("float") => <core::ffi::c_float as ToFfiType>::TYPE,
444+
atom!("double") => <core::ffi::c_double as ToFfiType>::TYPE,
405445
atom!("sint64") | atom!("i64") => Self::I64,
406446
atom!("sint32") | atom!("i32") => Self::I32,
407447
atom!("sint16") | atom!("i16") => Self::I16,
@@ -693,7 +733,7 @@ impl ForeignFunctionTable {
693733
match FfiType::from_atom(&kind) {
694734
FfiType::Void => Err(FfiError::VoidArgumentType),
695735
FfiType::Bool => {
696-
let val = args.as_int::<u8>()?;
736+
let val = args.as_int::<i8>()?;
697737
let init = match val {
698738
0 => false,
699739
1 => true,
@@ -756,8 +796,8 @@ impl ForeignFunctionTable {
756796

757797
match FfiType::from_atom(&kind) {
758798
FfiType::Void => Err(FfiError::VoidArgumentType),
759-
FfiType::Bool | FfiType::U8 => Ok(unsafe { read_int::<u8>(ptr, arena) }),
760-
FfiType::I8 => Ok(unsafe { read_int::<i8>(ptr, arena) }),
799+
FfiType::U8 => Ok(unsafe { read_int::<u8>(ptr, arena) }),
800+
FfiType::Bool | FfiType::I8 => Ok(unsafe { read_int::<i8>(ptr, arena) }),
761801
FfiType::U16 => Ok(unsafe { read_int::<u16>(ptr, arena) }),
762802
FfiType::I16 => Ok(unsafe { read_int::<i16>(ptr, arena) }),
763803
FfiType::U32 => Ok(unsafe { read_int::<u32>(ptr, arena) }),

src/lib/ffi.pl

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,70 @@
1111
operating system could be a `.so`, `.dylib` or `.dll` file). and a list of functions. Each
1212
function is defined by its name, a list of the type of the arguments, and the return argument.
1313
14-
Types available are: `sint8`/`i8`, `uint8`/`u8`, `sint16`/`i16`, `uint16`/`u16`, `sint32`/`i32`, `uint32`/`u32`, `sint64`/`i64`,
15-
`uint64`/`u64`, `f32`, `f64`, `cstr`, `void`, `bool`, `ptr` and custom structs, which can be defined
16-
with `foreign_struct/2`.
17-
18-
After that, each function on the lists maps to a predicate created in the ffi module which
19-
are used to call the native code.
20-
The predicate takes the functor name after the function name. Then, the arguments are the input
21-
arguments followed by a return argument. However, functions with return type `void` or `bool`
22-
don't have that return argument. Predicates with `void` always succeed and `bool` predicates depend
23-
on the return value on the native side.
14+
For each function in the list a predicate of the same name is generated in the ffi module which
15+
can then be used to call the native code.
16+
The predicates arguments are the input arguments of the foreign function and depending on the return type an extra argument for the return value.
17+
Functions with return type `void` or `bool` don't have this extra argument.
18+
Predicates for functions with return type `void` always succeed.
19+
Predicates for functions with retun type `bool` succeed iff the return value is 1.
2420
2521
```
2622
ffi:FUNCTION_NAME(+InputArg1, ..., +InputArgN, -ReturnArg). % for all return types except void and bool
2723
ffi:FUNCTION_NAME(+InputArg1, ..., +InputArgN). % for void and bool
2824
```
2925
30-
## Notes regarding cstr
26+
## Available types are
27+
28+
### Basic C Types
29+
30+
[C Types Reference](https://en.cppreference.com/w/c/language/types.html)
31+
32+
- `void`,
33+
- `char`, `uchar`, `schar`
34+
- `short`, `ushort`
35+
- `int`, `uint`
36+
- `long`, `ulong`,
37+
- `longlong`, `ulonglong`,
38+
- `float`, `double`
39+
40+
### Fixed Width Integer Types
41+
42+
[C Fixed With Integer Types Reference](https://en.cppreference.com/w/c/types/integer.html)
43+
44+
- `sint8`/`i8`, `uint8`/`u8`,
45+
- `sint16`/`i16`, `uint16`/`u16`,
46+
- `sint32`/`i32`, `uint32`/`u32`,
47+
- `sint64`/`i64`, `uint64`/`u64`,
48+
49+
### Fixed Width Floating-Point Types
50+
51+
[C++ Fixed Width Floating-Point Types Reference](https://en.cppreference.com/w/cpp/types/floating-point.html)
52+
53+
- `f32`, `f64`
54+
55+
### Other Types
56+
57+
- `cstr`,
58+
- `ptr`,
59+
- `bool` and,
60+
- custom structs, which can be defined with `foreign_struct/2`.
61+
62+
### Notes regarding bool
63+
64+
- Not necessarily compatible with the fundamental C type bool.
65+
- Same as `i8` but only values 0 and 1 are valid values.
66+
67+
### Notes regarding cstr
3168
3269
- When using `cstr` as an argument type the string will be deallocated once the function returns.
3370
- When using `cstr` as a return type the string will be copied and won't be deallocated.
3471
35-
3672
## Example
3773
3874
For example, let's see how to define a function from the [raylib](https://www.raylib.com/) library.
3975
4076
```
41-
?- use_foreign_module("./libraylib.so", ['InitWindow'([sint32, sint32, cstr], void)]).
77+
?- use_foreign_module("./libraylib.so", ['InitWindow'([int, int, cstr], void)]).
4278
```
4379
4480
This creates a `'InitWindow'` predicate under the ffi module. Now, we can call it:
@@ -143,7 +179,7 @@
143179
%
144180
% Read a value of Type from the pointer Ptr and unify the read value with Value
145181
%
146-
% For type cstr take read a nul-terminated utf-8 string starting at Ptr.
182+
% For type cstr read a nul-terminated utf-8 string starting at Ptr.
147183
%
148184
read_ptr(Type, Ptr, Value) :-
149185
must_be(atom, Type),
@@ -163,7 +199,7 @@
163199

164200
%% array_type(+ElemType, +Len, -ArrayType)
165201
%
166-
% unify the ffi type for an array of lenth Len with element type ElemType with ArrayType
202+
% unify the ffi type for an array of length Len with element type ElemType with ArrayType
167203
%
168204
array_type(ElemType, Len, ArrayType) :-
169205
(Len =< 0 -> domain_error(greater_than_zero, Len, array_type/3); true),
@@ -183,7 +219,7 @@
183219
% Allocate the Locals, evaluate the Goal and deallocate the Locals.
184220
% The Locals will also be cleandup when Goal fails or throws an error.
185221
%
186-
% Locals is a list of local variable definitions let(-Ptr, +Type, +Args).
222+
% Locals is a list of local variable definitions `let(-Ptr, +Type, +Args)`.
187223
% Ptr will be unified with the pointer to the local of Type initialized with Args.
188224
%
189225
with_locals(Locals, Goal) :-

0 commit comments

Comments
 (0)