mirror of
https://github.com/lune-org/lune.git
synced 2025-04-10 21:40:54 +01:00
Add Data:copyFrom, tests and annotation (#243)
This commit is contained in:
parent
34a5b39277
commit
154c68a64e
12 changed files with 514 additions and 35 deletions
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -7,6 +7,6 @@
|
||||||
# Ensure all txt files within tests use LF
|
# Ensure all txt files within tests use LF
|
||||||
tests/**/*.txt eol=lf
|
tests/**/*.txt eol=lf
|
||||||
|
|
||||||
# Remove test c, typescript from language list
|
# Remove test c and typescript from language list
|
||||||
tests/ffi/**/*.c linguist-vendored
|
tests/ffi/**/*.c linguist-vendored
|
||||||
tests/ffi/**/*.ts linguist-vendored
|
tests/ffi/**/*.ts linguist-vendored
|
||||||
|
|
|
@ -6,6 +6,10 @@ See [tests/ffi](../../tests/ffi/README.md)
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
|
- Deref
|
||||||
|
|
||||||
|
- Big endianness / Little endianness variable (On process.endianness)
|
||||||
|
|
||||||
- CString
|
- CString
|
||||||
|
|
||||||
- Add buffer for owned data support
|
- Add buffer for owned data support
|
||||||
|
@ -25,6 +29,8 @@ See [tests/ffi](../../tests/ffi/README.md)
|
||||||
|
|
||||||
- Add varargs support
|
- Add varargs support
|
||||||
|
|
||||||
|
- Array argument in cfn
|
||||||
|
|
||||||
## Code structure
|
## Code structure
|
||||||
|
|
||||||
### /c
|
### /c
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
use std::{alloc, alloc::Layout, boxed::Box, mem::ManuallyDrop, ptr};
|
use std::{
|
||||||
|
alloc::{self, Layout},
|
||||||
|
boxed::Box,
|
||||||
|
mem::ManuallyDrop,
|
||||||
|
ptr,
|
||||||
|
};
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
|
use super::helper::method_provider;
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{association_names::REF_INNER, RefBounds, RefData, RefFlag},
|
data::{association_names::REF_INNER, RefBounds, RefData, RefFlag},
|
||||||
ffi::{association, bit_mask::*, FfiData},
|
ffi::{association, bit_mask::*, FfiData},
|
||||||
|
@ -148,6 +154,7 @@ impl LuaUserData for BoxData {
|
||||||
fields.add_field_method_get("size", |_, this| Ok(this.size()));
|
fields.add_field_method_get("size", |_, this| Ok(this.size()));
|
||||||
}
|
}
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
method_provider::provide_copy_from(methods);
|
||||||
// For convenience, :zero returns self.
|
// For convenience, :zero returns self.
|
||||||
methods.add_function_mut("zero", |_, this: LuaAnyUserData| {
|
methods.add_function_mut("zero", |_, this: LuaAnyUserData| {
|
||||||
this.borrow_mut::<BoxData>()?.zero();
|
this.borrow_mut::<BoxData>()?.zero();
|
||||||
|
|
41
crates/lune-std-ffi/src/data/helper.rs
Normal file
41
crates/lune-std-ffi/src/data/helper.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use mlua::prelude::*;
|
||||||
|
|
||||||
|
use super::{FfiData, GetFfiData};
|
||||||
|
|
||||||
|
pub mod method_provider {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub fn provide_copy_from<'lua, Target, M>(methods: &mut M)
|
||||||
|
where
|
||||||
|
Target: FfiData,
|
||||||
|
M: LuaUserDataMethods<'lua, Target>,
|
||||||
|
{
|
||||||
|
methods.add_method(
|
||||||
|
"copyFrom",
|
||||||
|
|_lua,
|
||||||
|
this,
|
||||||
|
(src, length, dst_offset, src_offset): (
|
||||||
|
LuaAnyUserData,
|
||||||
|
usize,
|
||||||
|
Option<isize>,
|
||||||
|
Option<isize>,
|
||||||
|
)| unsafe {
|
||||||
|
let dst_offset = dst_offset.unwrap_or(0);
|
||||||
|
let src_offset = src_offset.unwrap_or(0);
|
||||||
|
let src = src.get_ffi_data()?;
|
||||||
|
|
||||||
|
if !src.check_inner_boundary(src_offset, length) {
|
||||||
|
return Err(LuaError::external("Source boundary check failed"));
|
||||||
|
}
|
||||||
|
if !this.check_inner_boundary(dst_offset, length) {
|
||||||
|
return Err(LuaError::external("Self boundary check failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.copy_from(&src, length, dst_offset, src_offset);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ use mlua::prelude::*;
|
||||||
mod box_data;
|
mod box_data;
|
||||||
mod callable_data;
|
mod callable_data;
|
||||||
mod closure_data;
|
mod closure_data;
|
||||||
|
mod helper;
|
||||||
mod lib_data;
|
mod lib_data;
|
||||||
mod ref_data;
|
mod ref_data;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::{mem::ManuallyDrop, ptr};
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
|
use super::helper::method_provider;
|
||||||
use crate::{
|
use crate::{
|
||||||
data::association_names::REF_INNER,
|
data::association_names::REF_INNER,
|
||||||
ffi::{association, bit_mask::*, FfiData},
|
ffi::{association, bit_mask::*, FfiData},
|
||||||
|
@ -91,6 +92,10 @@ impl RefData {
|
||||||
(**self.ptr) as usize == 0
|
(**self.ptr) as usize == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn leak(&mut self) {
|
||||||
|
self.flags = u8_set(self.flags, RefFlag::Leaked.value(), true);
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn offset(&self, offset: isize) -> LuaResult<Self> {
|
pub unsafe fn offset(&self, offset: isize) -> LuaResult<Self> {
|
||||||
u8_test(self.flags, RefFlag::Offsetable.value())
|
u8_test(self.flags, RefFlag::Offsetable.value())
|
||||||
.then_some(())
|
.then_some(())
|
||||||
|
@ -147,6 +152,8 @@ impl FfiData for RefData {
|
||||||
|
|
||||||
impl LuaUserData for RefData {
|
impl LuaUserData for RefData {
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
method_provider::provide_copy_from(methods);
|
||||||
|
|
||||||
// FIXME:
|
// FIXME:
|
||||||
methods.add_function("deref", |lua, this: LuaAnyUserData| {
|
methods.add_function("deref", |lua, this: LuaAnyUserData| {
|
||||||
let inner = association::get(lua, REF_INNER, &this)?;
|
let inner = association::get(lua, REF_INNER, &this)?;
|
||||||
|
@ -171,10 +178,12 @@ impl LuaUserData for RefData {
|
||||||
|
|
||||||
Ok(userdata)
|
Ok(userdata)
|
||||||
});
|
});
|
||||||
// FIXME:
|
methods.add_function_mut("leak", |lua, this: LuaAnyUserData| {
|
||||||
|
this.borrow_mut::<RefData>()?.leak();
|
||||||
|
RefData::luaref(lua, this)
|
||||||
|
});
|
||||||
methods.add_function("ref", |lua, this: LuaAnyUserData| {
|
methods.add_function("ref", |lua, this: LuaAnyUserData| {
|
||||||
let ffiref = RefData::luaref(lua, this)?;
|
RefData::luaref(lua, this)
|
||||||
Ok(ffiref)
|
|
||||||
});
|
});
|
||||||
methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr()));
|
methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,17 @@ pub trait FfiData {
|
||||||
unsafe fn get_inner_pointer(&self) -> *mut ();
|
unsafe fn get_inner_pointer(&self) -> *mut ();
|
||||||
fn is_writable(&self) -> bool;
|
fn is_writable(&self) -> bool;
|
||||||
fn is_readable(&self) -> bool;
|
fn is_readable(&self) -> bool;
|
||||||
|
unsafe fn copy_from(
|
||||||
|
&self,
|
||||||
|
src: &Ref<dyn FfiData>,
|
||||||
|
length: usize,
|
||||||
|
dst_offset: isize,
|
||||||
|
src_offset: isize,
|
||||||
|
) {
|
||||||
|
self.get_inner_pointer()
|
||||||
|
.byte_offset(dst_offset)
|
||||||
|
.copy_from(src.get_inner_pointer().byte_offset(src_offset), length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FfiArg {
|
pub struct FfiArg {
|
||||||
|
|
53
tests/ffi/read_boundary.luau
Normal file
53
tests/ffi/read_boundary.luau
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
local ffi = require("@lune/ffi")
|
||||||
|
|
||||||
|
local ok
|
||||||
|
|
||||||
|
-- Case1: Success
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.u8:box(1)
|
||||||
|
ffi.u8:readData(box)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case1 should success")
|
||||||
|
|
||||||
|
-- Case2: Fail
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.u8:box(1)
|
||||||
|
ffi.u16:readData(box)
|
||||||
|
end)
|
||||||
|
assert(not ok, "assersion failed, Case2 should fail")
|
||||||
|
|
||||||
|
-- Case3: Success
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(ffi.u8.size * 2)
|
||||||
|
ffi.u16:readData(box)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case3 should success")
|
||||||
|
|
||||||
|
-- Case4: Success
|
||||||
|
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(ffi.u8.size * 2)
|
||||||
|
ffi.u8:readData(box, ffi.u8.size)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case4 should success")
|
||||||
|
|
||||||
|
-- Case5: Fail
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.u8:box(1):ref()
|
||||||
|
ffi.u16:readData(box)
|
||||||
|
end)
|
||||||
|
assert(not ok, "assersion failed, Case5 should fail")
|
||||||
|
|
||||||
|
-- Case6: Success
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(ffi.u8.size * 2):ref()
|
||||||
|
ffi.u16:readData(box)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case6 should success")
|
||||||
|
|
||||||
|
-- Case7: Fail
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(ffi.u8.size * 2):ref(ffi.u16.size)
|
||||||
|
ffi.u16:readData(box)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case7 should fail")
|
46
tests/ffi/write_boundary.luau
Normal file
46
tests/ffi/write_boundary.luau
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
local ffi = require("@lune/ffi")
|
||||||
|
local c = ffi.c
|
||||||
|
|
||||||
|
local ok
|
||||||
|
|
||||||
|
-- Case1: Fail
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(c.int.size - 1)
|
||||||
|
c.int:writeData(box, 10)
|
||||||
|
end)
|
||||||
|
assert(not ok, "assersion failed, Case1 should fail")
|
||||||
|
|
||||||
|
-- Case2: Success
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(c.int.size)
|
||||||
|
c.int:writeData(box, 10)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case2 should success")
|
||||||
|
|
||||||
|
-- Case3: Success
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(c.int.size * 2)
|
||||||
|
c.int:writeData(box, 10, c.int.size)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case3 should success")
|
||||||
|
|
||||||
|
-- Case4: Fail
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(c.int.size * 2)
|
||||||
|
c.int:writeData(box, 10, c.int.size * 2)
|
||||||
|
end)
|
||||||
|
assert(not ok, "assersion failed, Case4 should fail")
|
||||||
|
|
||||||
|
-- Case5: Success
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(c.int.size * 2):ref()
|
||||||
|
c.int:writeData(box, 10, c.int.size)
|
||||||
|
end)
|
||||||
|
assert(ok, "assersion failed, Case5 should success")
|
||||||
|
|
||||||
|
-- Case6: Fail
|
||||||
|
ok = pcall(function()
|
||||||
|
local box = ffi.box(c.int.size * 2):ref()
|
||||||
|
c.int:writeData(box, 10, c.int.size * 2)
|
||||||
|
end)
|
||||||
|
assert(not ok, "assersion failed, Case6 should fail")
|
361
types/ffi.luau
361
types/ffi.luau
|
@ -1,11 +1,41 @@
|
||||||
--[=[
|
--[=[
|
||||||
@class FFI
|
@class FFI
|
||||||
|
|
||||||
Built-in library for foreign function interface
|
Built-in library for foreign function interface.
|
||||||
|
|
||||||
### Example usage
|
### Example usage
|
||||||
|
lib.c:
|
||||||
|
```c
|
||||||
|
int add(int a, int b) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
init.luau:
|
||||||
```lua
|
```lua
|
||||||
|
local ffi = require("@lune/ffi")
|
||||||
|
|
||||||
|
-- Create function signature
|
||||||
|
local addSignature = ffi.c.fn({ ffi.c.int, ffi.c.int }, ffi.c.int)
|
||||||
|
|
||||||
|
-- Load library
|
||||||
|
local lib = ffi.open("./lib.so")
|
||||||
|
|
||||||
|
-- Get symbol from library
|
||||||
|
local addSymbol = lib:find("add")
|
||||||
|
|
||||||
|
-- Create CallableData
|
||||||
|
local add = addSignature:callable(addSymbol)
|
||||||
|
|
||||||
|
-- Create result box and arguments
|
||||||
|
local result = ffi.box(ffi.c.int.size)
|
||||||
|
local a = ffi.c.int:box(1)
|
||||||
|
local b = ffi.c.int:box(2)
|
||||||
|
|
||||||
|
-- Call external function
|
||||||
|
add(result, a:ref(), b:ref())
|
||||||
|
|
||||||
|
-- Get number from result
|
||||||
|
print(ffi.c.int:readData(result))
|
||||||
```
|
```
|
||||||
]=]
|
]=]
|
||||||
local ffi = {}
|
local ffi = {}
|
||||||
|
@ -24,19 +54,83 @@ ffi.c = c
|
||||||
--[=[
|
--[=[
|
||||||
@class RefData
|
@class RefData
|
||||||
|
|
||||||
A user manageable memory reference
|
A user manageable memory reference.
|
||||||
]=]
|
]=]
|
||||||
export type RefData = {
|
export type RefData = {
|
||||||
|
--[=[
|
||||||
|
@within RefData
|
||||||
|
@tag Method
|
||||||
|
@method deref
|
||||||
|
|
||||||
|
Get a RefData by dereference this reference.
|
||||||
|
|
||||||
|
@return A dereferenced `RefData`
|
||||||
|
]=]
|
||||||
deref: (self: RefData) -> RefData,
|
deref: (self: RefData) -> RefData,
|
||||||
|
--[=[
|
||||||
|
@within RefData
|
||||||
|
@tag Method
|
||||||
|
@method offset
|
||||||
|
|
||||||
|
Create a reference with specific offset from this reference.
|
||||||
|
|
||||||
|
@param offset Create a reference at the given offset
|
||||||
|
@return A offseted reference
|
||||||
|
]=]
|
||||||
offset: (self: RefData, offset: number) -> RefData,
|
offset: (self: RefData, offset: number) -> RefData,
|
||||||
|
--[=[
|
||||||
|
@within RefData
|
||||||
|
@tag Method
|
||||||
|
@method ref
|
||||||
|
|
||||||
|
Create a reference of this reference.
|
||||||
|
|
||||||
|
The created reference keeps the box from being garbage collected until the reference itself is collected.
|
||||||
|
|
||||||
|
@return A reference of this reference
|
||||||
|
]=]
|
||||||
ref: (self: RefData) -> RefData,
|
ref: (self: RefData) -> RefData,
|
||||||
|
--[=[
|
||||||
|
@within RefData
|
||||||
|
@tag Method
|
||||||
|
@method leak
|
||||||
|
|
||||||
|
Create a reference of this reference after leaking it.
|
||||||
|
|
||||||
|
GC doesn't manage destruction after this action. You must free it later.
|
||||||
|
|
||||||
|
@return A reference of this reference
|
||||||
|
]=]
|
||||||
|
leak: (self: RefData) -> RefData,
|
||||||
|
--[=[
|
||||||
|
@within RefData
|
||||||
|
@tag Method
|
||||||
|
@method isNull
|
||||||
|
|
||||||
|
Check reference is null or not.
|
||||||
|
|
||||||
|
@return Whether reference is null or not
|
||||||
|
]=]
|
||||||
isNull: (self: RefData) -> boolean,
|
isNull: (self: RefData) -> boolean,
|
||||||
|
--[=[
|
||||||
|
@within RefData
|
||||||
|
@tag Method
|
||||||
|
@method copyFrom
|
||||||
|
|
||||||
|
Copy content from another data.
|
||||||
|
|
||||||
|
@param src The source data
|
||||||
|
@param len The amount of data to copy, in bytes
|
||||||
|
@param dst_offset The offset in the destination where the data will be pasted
|
||||||
|
@param src_offset The offset in the source data from where the data will be copied
|
||||||
|
]=]
|
||||||
|
copyFrom: (self: RefData, src: (BoxData|RefData), length: number, dst_offset: number, src_offset: number)->();
|
||||||
}
|
}
|
||||||
|
|
||||||
--[=[
|
--[=[
|
||||||
@class BoxData
|
@class BoxData
|
||||||
|
|
||||||
A user manageable heap memory
|
A user manageable heap memory.
|
||||||
]=]
|
]=]
|
||||||
export type BoxData = {
|
export type BoxData = {
|
||||||
--[=[
|
--[=[
|
||||||
|
@ -44,7 +138,7 @@ export type BoxData = {
|
||||||
@tag Field
|
@tag Field
|
||||||
@field size
|
@field size
|
||||||
|
|
||||||
Size of the box.
|
The size of the box.
|
||||||
]=]
|
]=]
|
||||||
size: number,
|
size: number,
|
||||||
|
|
||||||
|
@ -65,8 +159,9 @@ export type BoxData = {
|
||||||
|
|
||||||
Create a reference of the box after leaking it.
|
Create a reference of the box after leaking it.
|
||||||
|
|
||||||
GC doesn't manage destruction after this action. You must free it later
|
GC doesn't manage destruction after this action. You must free it later.
|
||||||
|
|
||||||
|
@param offset Create a reference at the given offset
|
||||||
@return A reference of the box
|
@return A reference of the box
|
||||||
]=]
|
]=]
|
||||||
leak: (self: BoxData, offset: number?) -> RefData,
|
leak: (self: BoxData, offset: number?) -> RefData,
|
||||||
|
@ -77,15 +172,31 @@ export type BoxData = {
|
||||||
|
|
||||||
Create a reference of the box.
|
Create a reference of the box.
|
||||||
|
|
||||||
|
The created reference keeps the box from being garbage collected until the reference itself is collected.
|
||||||
|
|
||||||
|
@param offset Create a reference at the given offset
|
||||||
@return A reference of the box
|
@return A reference of the box
|
||||||
]=]
|
]=]
|
||||||
ref: (self: BoxData, offset: number?) -> RefData,
|
ref: (self: BoxData, offset: number?) -> RefData,
|
||||||
|
--[=[
|
||||||
|
@within BoxData
|
||||||
|
@tag Method
|
||||||
|
@method copyFrom
|
||||||
|
|
||||||
|
Copy content from another data.
|
||||||
|
|
||||||
|
@param src The source data
|
||||||
|
@param len The amount of data to copy, in bytes
|
||||||
|
@param dst_offset The offset in the destination where the data will be pasted
|
||||||
|
@param src_offset The offset in the source data from where the data will be copied
|
||||||
|
]=]
|
||||||
|
copyFrom: (self: BoxData, src: (BoxData|RefData), length: number, dst_offset: number, src_offset: number)->();
|
||||||
}
|
}
|
||||||
|
|
||||||
--[=[
|
--[=[
|
||||||
@class LibData
|
@class LibData
|
||||||
|
|
||||||
A dynamic opened library handle
|
A dynamic opened library handle.
|
||||||
]=]
|
]=]
|
||||||
export type LibData = {
|
export type LibData = {
|
||||||
--[=[
|
--[=[
|
||||||
|
@ -105,9 +216,12 @@ export type LibData = {
|
||||||
|
|
||||||
--[=[
|
--[=[
|
||||||
@class CallableData
|
@class CallableData
|
||||||
@tag unsafe
|
|
||||||
|
|
||||||
A callable external function
|
A callable external function.
|
||||||
|
|
||||||
|
To call external function, you should provide memory for the return value and references for the arguments.
|
||||||
|
|
||||||
|
If return type is `void`, pass `nil`.
|
||||||
]=]
|
]=]
|
||||||
export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & {
|
export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & {
|
||||||
-- apply: (self: Callable, args: Args)->AppliedCallable,
|
-- apply: (self: Callable, args: Args)->AppliedCallable,
|
||||||
|
@ -116,7 +230,9 @@ export type CallableData = (ret: (RefData|BoxData)?, ...RefData)->() & {
|
||||||
--[=[
|
--[=[
|
||||||
@class ClosureData
|
@class ClosureData
|
||||||
|
|
||||||
A lua function wrapper for function pointer
|
A lua function wrapper for the function pointer.
|
||||||
|
|
||||||
|
To return some data, write value into ret reference.
|
||||||
]=]
|
]=]
|
||||||
export type ClosureData = {
|
export type ClosureData = {
|
||||||
--[=[
|
--[=[
|
||||||
|
@ -124,7 +240,9 @@ export type ClosureData = {
|
||||||
@tag Method
|
@tag Method
|
||||||
@method ref
|
@method ref
|
||||||
|
|
||||||
Create a reference of the closure. usually can be used for passing function pointer as argument
|
Create a reference of the closure. usually can be used for passing function pointer as argument.
|
||||||
|
|
||||||
|
The created reference keeps the closure from being garbage collected until the reference itself is collected.
|
||||||
|
|
||||||
@return A reference of the closure
|
@return A reference of the closure
|
||||||
]=]
|
]=]
|
||||||
|
@ -137,7 +255,21 @@ export type ClosureData = {
|
||||||
|
|
||||||
-- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type.
|
-- NOTE: T is a unique identifier for the `CType` and R is the closest Lua type.
|
||||||
export type CTypeInfo<T, R> = {
|
export type CTypeInfo<T, R> = {
|
||||||
|
--[=[
|
||||||
|
@within CTypeInfo
|
||||||
|
@tag Field
|
||||||
|
@field size
|
||||||
|
|
||||||
|
The size of the type in bytes.
|
||||||
|
]=]
|
||||||
size: number,
|
size: number,
|
||||||
|
--[=[
|
||||||
|
@within CTypeInfo
|
||||||
|
@tag Field
|
||||||
|
@field signedness
|
||||||
|
|
||||||
|
The signedness of the type.
|
||||||
|
]=]
|
||||||
signedness: boolean,
|
signedness: boolean,
|
||||||
|
|
||||||
-- subtype
|
-- subtype
|
||||||
|
@ -156,7 +288,23 @@ export type CTypeInfo<T, R> = {
|
||||||
type NumCType<T> = CTypeInfo<T, (number|any)>
|
type NumCType<T> = CTypeInfo<T, (number|any)>
|
||||||
|
|
||||||
export type CPtrInfo<T> = {
|
export type CPtrInfo<T> = {
|
||||||
|
--[=[
|
||||||
|
@within CPtrInfo
|
||||||
|
@tag Field
|
||||||
|
@field size
|
||||||
|
|
||||||
|
The size of a pointer. should be the same for all pointers.
|
||||||
|
|
||||||
|
Equivalent to `ffi.c.usize.size`.
|
||||||
|
]=]
|
||||||
size: number,
|
size: number,
|
||||||
|
--[=[
|
||||||
|
@within CPtrInfo
|
||||||
|
@tag Field
|
||||||
|
@field inner
|
||||||
|
|
||||||
|
The inner type of the pointer.
|
||||||
|
]=]
|
||||||
inner: T,
|
inner: T,
|
||||||
|
|
||||||
-- subtype
|
-- subtype
|
||||||
|
@ -169,9 +317,35 @@ export type CPtrInfo<T> = {
|
||||||
writeRef: (self: CPtrInfo<T>, target: (RefData|BoxData), value: (RefData|BoxData), offset: number?) -> (),
|
writeRef: (self: CPtrInfo<T>, target: (RefData|BoxData), value: (RefData|BoxData), offset: number?) -> (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
@class CArrInfo
|
||||||
|
|
||||||
|
A c sized array type information.
|
||||||
|
]=]
|
||||||
export type CArrInfo<T, R> = {
|
export type CArrInfo<T, R> = {
|
||||||
|
--[=[
|
||||||
|
@within CArrInfo
|
||||||
|
@tag Field
|
||||||
|
@field size
|
||||||
|
|
||||||
|
The total size of the array in bytes.
|
||||||
|
]=]
|
||||||
size: number,
|
size: number,
|
||||||
|
--[=[
|
||||||
|
@within CArrInfo
|
||||||
|
@tag Field
|
||||||
|
@field length
|
||||||
|
|
||||||
|
The length of the array.
|
||||||
|
]=]
|
||||||
length: number,
|
length: number,
|
||||||
|
--[=[
|
||||||
|
@within CArrInfo
|
||||||
|
@tag Field
|
||||||
|
@field inner
|
||||||
|
|
||||||
|
The inner element type of the array.
|
||||||
|
]=]
|
||||||
inner: T,
|
inner: T,
|
||||||
|
|
||||||
-- subtype
|
-- subtype
|
||||||
|
@ -186,15 +360,62 @@ export type CArrInfo<T, R> = {
|
||||||
offset: (self: CArrInfo<T, R>, index: number) -> number,
|
offset: (self: CArrInfo<T, R>, index: number) -> number,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
@class CFnInfo
|
||||||
|
|
||||||
|
A c function signature type information.
|
||||||
|
]=]
|
||||||
export type CFnInfo = {
|
export type CFnInfo = {
|
||||||
|
--[=[
|
||||||
|
@within CFnInfo
|
||||||
|
@tag Method
|
||||||
|
@method callable
|
||||||
|
|
||||||
|
Create a callable from reference.
|
||||||
|
|
||||||
|
@return Struct array type
|
||||||
|
]=]
|
||||||
callable: (self: CFnInfo, functionRef: RefData) -> CallableData,
|
callable: (self: CFnInfo, functionRef: RefData) -> CallableData,
|
||||||
|
--[=[
|
||||||
|
@within CFnInfo
|
||||||
|
@tag Method
|
||||||
|
@method closure
|
||||||
|
|
||||||
|
Create a closure from lua function.
|
||||||
|
|
||||||
|
@return A closure.
|
||||||
|
]=]
|
||||||
closure: (self: CFnInfo, (ret: RefData, ...RefData)->()) -> ClosureData,
|
closure: (self: CFnInfo, (ret: RefData, ...RefData)->()) -> ClosureData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
@class CStructInfo
|
||||||
|
|
||||||
|
A c struct type information.
|
||||||
|
]=]
|
||||||
export type CStructInfo = {
|
export type CStructInfo = {
|
||||||
size: number,
|
size: number,
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
@within CSturctInfo
|
||||||
|
@tag Method
|
||||||
|
@method arr
|
||||||
|
|
||||||
|
Create a struct array type.
|
||||||
|
|
||||||
|
@param len The length of the array
|
||||||
|
@return A struct array type
|
||||||
|
]=]
|
||||||
arr: (self: CStructInfo, len: number) -> CArrInfo<CStructInfo, {any}>,
|
arr: (self: CStructInfo, len: number) -> CArrInfo<CStructInfo, {any}>,
|
||||||
|
--[=[
|
||||||
|
@within CSturctInfo
|
||||||
|
@tag Method
|
||||||
|
@method ptr
|
||||||
|
|
||||||
|
Create a struct pointer type.
|
||||||
|
|
||||||
|
@return A struct pointer type
|
||||||
|
]=]
|
||||||
ptr: (self: CStructInfo) -> CPtrInfo<CStructInfo>,
|
ptr: (self: CStructInfo) -> CPtrInfo<CStructInfo>,
|
||||||
|
|
||||||
box: (self: CStructInfo, table: { any }) -> BoxData,
|
box: (self: CStructInfo, table: { any }) -> BoxData,
|
||||||
|
@ -217,9 +438,9 @@ export type CVoidInfo = {
|
||||||
@tag Method
|
@tag Method
|
||||||
@method ptr
|
@method ptr
|
||||||
|
|
||||||
Create a generic pointer type
|
Create a generic pointer type.
|
||||||
|
|
||||||
@return Generic pointer type
|
@return Generic pointer type, equivalent to `*void` in C.
|
||||||
]=]
|
]=]
|
||||||
ptr: (self: CVoidInfo) -> CPtrInfo<CVoidInfo>,
|
ptr: (self: CVoidInfo) -> CPtrInfo<CVoidInfo>,
|
||||||
}
|
}
|
||||||
|
@ -233,7 +454,7 @@ c.void = {} :: CVoidInfo
|
||||||
@class u8
|
@class u8
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 8-bit sized unsigned integer, Equivalent to `uint8_t` in `stdint`
|
A 8-bit sized unsigned integer, Equivalent to `uint8_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.u8 = {} :: u8
|
ffi.u8 = {} :: u8
|
||||||
export type u8 = NumCType<"u8">
|
export type u8 = NumCType<"u8">
|
||||||
|
@ -241,7 +462,7 @@ export type u8 = NumCType<"u8">
|
||||||
@class u16
|
@class u16
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 16-bit sized unsigned integer, Equivalent to `uint16_t` in `stdint`
|
A 16-bit sized unsigned integer, Equivalent to `uint16_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.u16 = {} :: u16
|
ffi.u16 = {} :: u16
|
||||||
export type u16 = NumCType<"u16">
|
export type u16 = NumCType<"u16">
|
||||||
|
@ -249,7 +470,7 @@ export type u16 = NumCType<"u16">
|
||||||
@class u32
|
@class u32
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 32-bit sized unsigned integer, Equivalent to `uint32_t` in `stdint`
|
A 32-bit sized unsigned integer, Equivalent to `uint32_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.u32 = {} :: u32
|
ffi.u32 = {} :: u32
|
||||||
export type u32 = NumCType<"u32">
|
export type u32 = NumCType<"u32">
|
||||||
|
@ -257,7 +478,7 @@ export type u32 = NumCType<"u32">
|
||||||
@class u64
|
@class u64
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 64-bit sized unsigned integer, Equivalent to `uint64_t` in `stdint`
|
A 64-bit sized unsigned integer, Equivalent to `uint64_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.u64 = {} :: u64
|
ffi.u64 = {} :: u64
|
||||||
export type u64 = NumCType<"u64">
|
export type u64 = NumCType<"u64">
|
||||||
|
@ -265,7 +486,7 @@ export type u64 = NumCType<"u64">
|
||||||
@class u128
|
@class u128
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 128-bit sized unsigned integer, Equivalent to `uint128_t` in `stdint`
|
A 128-bit sized unsigned integer, Equivalent to `uint128_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.u128 = {} :: u128
|
ffi.u128 = {} :: u128
|
||||||
export type u128 = NumCType<"u128">
|
export type u128 = NumCType<"u128">
|
||||||
|
@ -273,7 +494,7 @@ export type u128 = NumCType<"u128">
|
||||||
@class i8
|
@class i8
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 8-bit sized signed integer, Equivalent to `int8_t` in `stdint`
|
A 8-bit sized signed integer, Equivalent to `int8_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.i8 = {} :: i8
|
ffi.i8 = {} :: i8
|
||||||
export type i8 = NumCType<"i8">
|
export type i8 = NumCType<"i8">
|
||||||
|
@ -281,7 +502,7 @@ export type i8 = NumCType<"i8">
|
||||||
@class i16
|
@class i16
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 16-bit sized signed integer, Equivalent to `int16_t` in `stdint`
|
A 16-bit sized signed integer, Equivalent to `int16_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.i16 = {} :: i16
|
ffi.i16 = {} :: i16
|
||||||
export type i16 = NumCType<"i16">
|
export type i16 = NumCType<"i16">
|
||||||
|
@ -289,7 +510,7 @@ export type i16 = NumCType<"i16">
|
||||||
@class i32
|
@class i32
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 32-bit sized signed integer, Equivalent to `int32_t` in `stdint`
|
A 32-bit sized signed integer, Equivalent to `int32_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.i32 = {} :: i32
|
ffi.i32 = {} :: i32
|
||||||
export type i32 = NumCType<"i32">
|
export type i32 = NumCType<"i32">
|
||||||
|
@ -297,7 +518,7 @@ export type i32 = NumCType<"i32">
|
||||||
@class i64
|
@class i64
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 64-bit sized signed integer, Equivalent to `int64_t` in `stdint`
|
A 64-bit sized signed integer, Equivalent to `int64_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.i64 = {} :: i64
|
ffi.i64 = {} :: i64
|
||||||
export type i64 = NumCType<"i64">
|
export type i64 = NumCType<"i64">
|
||||||
|
@ -305,7 +526,7 @@ export type i64 = NumCType<"i64">
|
||||||
@class i128
|
@class i128
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A 128-bit sized signed integer, Equivalent to `int128_t` in `stdint`
|
A 128-bit sized signed integer, Equivalent to `int128_t` in `stdint`.
|
||||||
]=]
|
]=]
|
||||||
ffi.i128 = {} :: i128
|
ffi.i128 = {} :: i128
|
||||||
export type i128 = NumCType<"i128">
|
export type i128 = NumCType<"i128">
|
||||||
|
@ -313,7 +534,7 @@ export type i128 = NumCType<"i128">
|
||||||
@class f32
|
@class f32
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A single-precision 32-bit sized floating-point, Almost always equivalent to `float` in C
|
A single-precision 32-bit sized floating-point, Almost always equivalent to `float` in C.
|
||||||
]=]
|
]=]
|
||||||
ffi.f32 = {} :: f32
|
ffi.f32 = {} :: f32
|
||||||
export type f32 = NumCType<"f32">
|
export type f32 = NumCType<"f32">
|
||||||
|
@ -321,7 +542,7 @@ export type f32 = NumCType<"f32">
|
||||||
@class f64
|
@class f64
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A double-precision 64-bit sized floating-point, Almost always equivalent to `double` in C
|
A double-precision 64-bit sized floating-point, Almost always equivalent to `double` in C.
|
||||||
]=]
|
]=]
|
||||||
ffi.f64 = {} :: f64
|
ffi.f64 = {} :: f64
|
||||||
export type f64 = NumCType<"f64">
|
export type f64 = NumCType<"f64">
|
||||||
|
@ -329,7 +550,7 @@ export type f64 = NumCType<"f64">
|
||||||
@class usize
|
@class usize
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A machine specific pointer sized unsigned integer,
|
A machine specific pointer sized unsigned integer.
|
||||||
]=]
|
]=]
|
||||||
ffi.usize = {} :: usize
|
ffi.usize = {} :: usize
|
||||||
export type usize = NumCType<"usize">
|
export type usize = NumCType<"usize">
|
||||||
|
@ -337,7 +558,7 @@ export type usize = NumCType<"usize">
|
||||||
@class isize
|
@class isize
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
A machine specific pointer sized signed integer,
|
A machine specific pointer sized signed integer.
|
||||||
]=]
|
]=]
|
||||||
ffi.isize = {} :: isize
|
ffi.isize = {} :: isize
|
||||||
export type isize = NumCType<"isize">
|
export type isize = NumCType<"isize">
|
||||||
|
@ -345,36 +566,120 @@ export type isize = NumCType<"isize">
|
||||||
--#endregion Fixed size Rust-style types --
|
--#endregion Fixed size Rust-style types --
|
||||||
|
|
||||||
--#region Variable size C-style types --
|
--#region Variable size C-style types --
|
||||||
|
--[=[
|
||||||
|
@class char
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `char` type.
|
||||||
|
|
||||||
|
The signedness may differ depending on the compiler and platform.
|
||||||
|
|
||||||
|
You can get signedness by `signedness` field.
|
||||||
|
]=]
|
||||||
c.char = {} :: char
|
c.char = {} :: char
|
||||||
export type char = NumCType<"char">
|
export type char = NumCType<"char">
|
||||||
-- c.float = {} :: float
|
-- c.float = {} :: float
|
||||||
-- export type float = NumCType<"float">
|
-- export type float = NumCType<"float">
|
||||||
-- c.double = {} :: double
|
-- c.double = {} :: double
|
||||||
-- export type double = NumCType<"double">
|
-- export type double = NumCType<"double">
|
||||||
|
--[=[
|
||||||
|
@class uchar
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `unsigned char` type.
|
||||||
|
|
||||||
|
Mostly equivalent to `u8`.
|
||||||
|
]=]
|
||||||
c.uchar = {} :: uchar
|
c.uchar = {} :: uchar
|
||||||
export type uchar = NumCType<"uchar">
|
export type uchar = NumCType<"uchar">
|
||||||
|
--[=[
|
||||||
|
@class schar
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `signed char` type.
|
||||||
|
]=]
|
||||||
c.schar = {} :: schar
|
c.schar = {} :: schar
|
||||||
export type schar = NumCType<"schar">
|
export type schar = NumCType<"schar">
|
||||||
|
--[=[
|
||||||
|
@class short
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `short` type.
|
||||||
|
]=]
|
||||||
c.short = {} :: short
|
c.short = {} :: short
|
||||||
export type short = NumCType<"short">
|
export type short = NumCType<"short">
|
||||||
|
--[=[
|
||||||
|
@class ushort
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `unsigned short` type.
|
||||||
|
]=]
|
||||||
c.ushort = {} :: ushort
|
c.ushort = {} :: ushort
|
||||||
export type ushort = NumCType<"ushort">
|
export type ushort = NumCType<"ushort">
|
||||||
|
--[=[
|
||||||
|
@class int
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `int` type.
|
||||||
|
|
||||||
|
The side may differ depending on the compiler and platform.
|
||||||
|
]=]
|
||||||
c.int = {} :: int
|
c.int = {} :: int
|
||||||
export type int = NumCType<"int">
|
export type int = NumCType<"int">
|
||||||
|
--[=[
|
||||||
|
@class uint
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `unsigned int` type.
|
||||||
|
|
||||||
|
The side may differ depending on the compiler and platform.
|
||||||
|
]=]
|
||||||
c.uint = {} :: uint
|
c.uint = {} :: uint
|
||||||
export type uint = NumCType<"uint">
|
export type uint = NumCType<"uint">
|
||||||
|
--[=[
|
||||||
|
@class long
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `long` type.
|
||||||
|
|
||||||
|
The side may differ depending on the compiler and platform.
|
||||||
|
]=]
|
||||||
c.long = {} :: long
|
c.long = {} :: long
|
||||||
export type long = NumCType<"long">
|
export type long = NumCType<"long">
|
||||||
|
--[=[
|
||||||
|
@class ulong
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `unsigned long` type.
|
||||||
|
|
||||||
|
The side may differ depending on the compiler and platform.
|
||||||
|
]=]
|
||||||
c.ulong = {} :: ulong
|
c.ulong = {} :: ulong
|
||||||
export type ulong = NumCType<"ulong">
|
export type ulong = NumCType<"ulong">
|
||||||
|
--[=[
|
||||||
|
@class longlong
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `unsigned longlong` type.
|
||||||
|
]=]
|
||||||
c.longlong = {} :: longlong
|
c.longlong = {} :: longlong
|
||||||
export type longlong = NumCType<"longlong">
|
export type longlong = NumCType<"longlong">
|
||||||
|
--[=[
|
||||||
|
@class longlong
|
||||||
|
@within C
|
||||||
|
|
||||||
|
Compiler defined C `unsigned longlong` type.
|
||||||
|
]=]
|
||||||
c.ulonglong = {} :: ulonglong
|
c.ulonglong = {} :: ulonglong
|
||||||
export type ulonglong = NumCType<"ulonglong">
|
export type ulonglong = NumCType<"ulonglong">
|
||||||
|
|
||||||
--#endregion Variable size C-style types --
|
--#endregion Variable size C-style types --
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
@class CTypes
|
||||||
|
|
||||||
|
All possible C types.
|
||||||
|
]=]
|
||||||
export type CTypes =
|
export type CTypes =
|
||||||
| u8
|
| u8
|
||||||
| u16
|
| u16
|
||||||
|
@ -474,7 +779,7 @@ end
|
||||||
--[=[
|
--[=[
|
||||||
@within FFI
|
@within FFI
|
||||||
|
|
||||||
Return `true` if the second argument is an integer (i32)
|
Return `true` if the second argument is an integer (i32).
|
||||||
|
|
||||||
@param val A lua value to check
|
@param val A lua value to check
|
||||||
@return Whether val is an integer or not
|
@return Whether val is an integer or not
|
||||||
|
|
Loading…
Add table
Reference in a new issue