Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP demo nicer FFI types #229

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions rust/src/util/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::sync::Once;

use ffi_toolkit::{catch_panic_response, raw_ptr, rust_str_to_c_str, FCPResponseStatus};

use super::types::{fil_GpuDeviceResponse, fil_InitLogFdResponse};
use super::types::{fil_Bytes, fil_GpuDeviceResponse, fil_InitLogFdResponse};

/// Protects the init off the logger.
static LOG_INIT: Once = Once::new();
Expand Down Expand Up @@ -38,20 +38,8 @@ pub unsafe extern "C" fn fil_get_gpu_devices() -> *mut fil_GpuDeviceResponse {
let devices = rust_gpu_tools::Device::all();
let n = devices.len();

let devices: Vec<*const libc::c_char> = devices
.iter()
.map(|d| d.name())
.map(|d| {
CString::new(d)
.unwrap_or_else(|_| CString::new("Unknown").unwrap())
.into_raw() as *const libc::c_char
})
.collect();

let dyn_array = Box::into_raw(devices.into_boxed_slice());

response.devices_len = n;
response.devices_ptr = dyn_array as *const *const libc::c_char;
let devices: Vec<fil_Bytes> = devices.iter().map(|d| d.name().into()).collect();
response.devices = devices.into();

raw_ptr(response)
})
Expand Down
106 changes: 98 additions & 8 deletions rust/src/util/types.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,115 @@
use std::ptr;
use std::{ops::Deref, ptr};

use drop_struct_macro_derive::DropStructMacro;
// `CodeAndMessage` is the trait implemented by `code_and_message_impl
use ffi_toolkit::{code_and_message_impl, free_c_str, CodeAndMessage, FCPResponseStatus};

#[repr(C)]
#[derive(DropStructMacro)]
pub struct fil_Array<T: Sized> {
ptr: *mut T,
len: usize,
}

impl<T> Default for fil_Array<T> {
fn default() -> Self {
Self {
ptr: ptr::null_mut(),
len: 0,
}
}
}

pub type fil_Bytes = fil_Array<u8>;

impl<T> From<Vec<T>> for fil_Array<T> {
fn from(buf: Vec<T>) -> Self {
if buf.is_empty() {
return Default::default();
}
buf.into_boxed_slice().into()
}
}

impl<T> From<Box<[T]>> for fil_Array<T> {
fn from(buf: Box<[T]>) -> Self {
if buf.is_empty() {
return Default::default();
}
let len = buf.len();
let ptr = buf.as_mut_ptr();
Box::leak(buf);
Comment on lines +39 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are those to lines the same as let ptr = Box::into_raw(buf)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite. Box::into_raw(buf) will return *const [T] instead of *const T.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I knew I must have missed something.


Self { ptr, len }
}
}

impl<T> Drop for fil_Array<T> {
fn drop(&mut self) {
unsafe {
if !self.ptr.is_null() && self.len != 0 {
let _ = Vec::from_raw_parts(self.ptr, self.len, self.len);
}
}
}
}

impl<T> Deref for fil_Array<T> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe {
if self.ptr.is_null() {
std::slice::from_raw_parts(ptr::NonNull::dangling().as_ptr(), 0)
} else {
std::slice::from_raw_parts(self.ptr, self.len)
}
}
}
}

impl From<&str> for fil_Bytes {
fn from(s: &str) -> Self {
if s.is_empty() {
return Default::default();
}
Box::<str>::from(s).into()
}
}

impl From<String> for fil_Bytes {
fn from(s: String) -> Self {
if s.is_empty() {
return Default::default();
}
s.into_boxed_str().into()
}
}

impl From<Box<str>> for fil_Bytes {
fn from(s: Box<str>) -> Self {
if s.is_empty() {
return Default::default();
}
let len = s.len();
let ptr = s.as_mut_ptr();
Box::leak(s);

Self { ptr, len }
}
}

#[repr(C)]
pub struct fil_GpuDeviceResponse {
pub status_code: FCPResponseStatus,
pub error_msg: *const libc::c_char,
pub devices_len: libc::size_t,
pub devices_ptr: *const *const libc::c_char,
pub error_msg: fil_Bytes,
pub devices: fil_Array<fil_Bytes>,
}
Comment on lines 101 to 105
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be:

#[repr(C)]
struct fil_Result<T: Sized> {
    pub status_code: FCPResponseStatus,
    pub error_msg: fil_Bytes,
    pub value: T,
}

impl<T> From<Result<T, E>> for fil_Result<T>
where
    T: Sized + Default,
    E: Display,
{
    fn from(r: Result<T, E>) -> Self {
        match r {
            Ok(value) => Self {
                status_code: FCPResponseStatus::FCPNoError,
                error_msg: Default::default(),
                value: value,
            },
            Err(e) => Self {
                status_code: FCPResponseStatus::FCPUnclassifiedError,
                error_msg: e.to_string().into(),
                value: Default::default(),
            },
        }
    }
}


impl Default for fil_GpuDeviceResponse {
fn default() -> Self {
Self {
error_msg: ptr::null(),
error_msg: Default::default(),
status_code: FCPResponseStatus::FCPNoError,
devices_len: 0,
devices_ptr: ptr::null(),
devices: Default::default(),
}
}
}
Expand Down