Skip to content

Commit

Permalink
Add Data:copyFrom, tests and annotation (lune-org#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
qwreey committed Oct 24, 2024
1 parent 34a5b39 commit 154c68a
Show file tree
Hide file tree
Showing 12 changed files with 514 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
# Ensure all txt files within tests use 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/**/*.ts linguist-vendored
6 changes: 6 additions & 0 deletions crates/lune-std-ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ See [tests/ffi](../../tests/ffi/README.md)

## TODO

- Deref

- Big endianness / Little endianness variable (On process.endianness)

- CString

- Add buffer for owned data support
Expand All @@ -25,6 +29,8 @@ See [tests/ffi](../../tests/ffi/README.md)
- Add varargs support

- Array argument in cfn

## Code structure

### /c
Expand Down
9 changes: 8 additions & 1 deletion crates/lune-std-ffi/src/data/box_data/mod.rs
Original file line number Diff line number Diff line change
@@ -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 super::helper::method_provider;
use crate::{
data::{association_names::REF_INNER, RefBounds, RefData, RefFlag},
ffi::{association, bit_mask::*, FfiData},
Expand Down Expand Up @@ -148,6 +154,7 @@ impl LuaUserData for BoxData {
fields.add_field_method_get("size", |_, this| Ok(this.size()));
}
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
method_provider::provide_copy_from(methods);
// For convenience, :zero returns self.
methods.add_function_mut("zero", |_, this: LuaAnyUserData| {
this.borrow_mut::<BoxData>()?.zero();
Expand Down
41 changes: 41 additions & 0 deletions crates/lune-std-ffi/src/data/helper.rs
Original file line number Diff line number Diff line change
@@ -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(())
},
);
}
}
1 change: 1 addition & 0 deletions crates/lune-std-ffi/src/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use mlua::prelude::*;
mod box_data;
mod callable_data;
mod closure_data;
mod helper;
mod lib_data;
mod ref_data;

Expand Down
15 changes: 12 additions & 3 deletions crates/lune-std-ffi/src/data/ref_data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{mem::ManuallyDrop, ptr};

use mlua::prelude::*;

use super::helper::method_provider;
use crate::{
data::association_names::REF_INNER,
ffi::{association, bit_mask::*, FfiData},
Expand Down Expand Up @@ -91,6 +92,10 @@ impl RefData {
(**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> {
u8_test(self.flags, RefFlag::Offsetable.value())
.then_some(())
Expand Down Expand Up @@ -147,6 +152,8 @@ impl FfiData for RefData {

impl LuaUserData for RefData {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
method_provider::provide_copy_from(methods);

// FIXME:
methods.add_function("deref", |lua, this: LuaAnyUserData| {
let inner = association::get(lua, REF_INNER, &this)?;
Expand All @@ -171,10 +178,12 @@ impl LuaUserData for RefData {

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| {
let ffiref = RefData::luaref(lua, this)?;
Ok(ffiref)
RefData::luaref(lua, this)
});
methods.add_method("isNull", |_, this, ()| Ok(this.is_nullptr()));
}
Expand Down
11 changes: 11 additions & 0 deletions crates/lune-std-ffi/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ pub trait FfiData {
unsafe fn get_inner_pointer(&self) -> *mut ();
fn is_writable(&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 {
Expand Down
Empty file removed tests/ffi/from_boundary.luau
Empty file.
Empty file removed tests/ffi/into_boundary.luau
Empty file.
53 changes: 53 additions & 0 deletions tests/ffi/read_boundary.luau
Original file line number Diff line number Diff line change
@@ -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 changes: 46 additions & 0 deletions tests/ffi/write_boundary.luau
Original file line number Diff line number Diff line change
@@ -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")
Loading

0 comments on commit 154c68a

Please sign in to comment.