~wahn/rs-blender#6: 
[blend_info] C bindings

Can the Rust crate blend_info be wrapped in a way that it can be used from within C?

Status
RESOLVED FIXED
Submitter
~wahn
Assigned to
Submitted
a month ago
Updated
26 days ago
Labels
task

~wahn a month ago

An example would be this Rust library (crate):

https://github.com/greyblake/whatlang-rs

And the C bindings for it:

https://github.com/greyblake/whatlang-ffi

More information about how this was done can be found here:

https://www.greyblake.com/blog/exposing-rust-library-to-c/

Daniel Henry Mantilla a month ago · edit

safer-ffi (https://getditto.github.io/safer_ffi/) is a library made precisely for this very purpose: to be able to expose Rust functions to C ("to the FFI") without having to use unsafe / with the framework performing checks for you.

For instance, those input char const * parameters which represent short-lived borrows to C strings can simply be expressed by using the char_p::Ref<'_> type (https://docs.rs/safer-ffi/latest/safer_ffi/prelude/char_p/index.html):

use ::safer_ffi::prelude::*;

#[ffi_export]
fn extract_struct(
    fn_ptr: char_p::Ref<'_>,
    sn_ptr: char_p::Ref<'_>,
)
{
    let fn_ptr: &str = fn_ptr.to_str();
    let sn_ptr: &str = sn_ptr.to_str();
    // …
}

// if you wanted to define and use a data structure usable from within
C (same native native endianness):
#[derive_ReprC]
#[repr(C)]
struct StructData {
     // …
}

~wahn 27 days ago

Jan Walter referenced this ticket in commit eed43cb.

~wahn REPORTED FIXED 26 days ago

I'm going to close this ticket. I did write a blog post describing the problem and a start how to attack it here:

https://www.janwalter.org/jekyll/rust/libblendinfo/2022/05/10/libblendinfo.html

I linked to that blog post in the Rust user community:

https://users.rust-lang.org/t/libblendinfo-return-information-from-rust-crate-to-c-library/76082

And finally I talked about the problem and how to solve it on Reddit:

https://www.reddit.com/r/rust/comments/uxdcrg/libblendinfo_return_information_from_rust_crate/

https://www.reddit.com/r/rust/comments/uxm6e8/how_to_return_bytes_from_a_rust_crate_to_cc/

So, the C bindings will be in this git repository:

https://git.sr.ht/~wahn/libblendinfo

The current state is:

From C (see example folder) you can ask e.g. for the bytes of a Camera struct, Rust will deal with reading the .blend file and returns a bunch of bytes (in a way that you can query the length of the returned vector of u8 values). The standalone blend_info program can be used to create a C struct in a header file:

https://git.sr.ht/~wahn/blend_info

Another header file (for the C bindings) can be created via the Rust crate safer-ffi:

https://crates.io/crates/safer-ffi

Have a look at the example code (camera.c):

#include <stdio.h>
#include "blendinfo.h"
#include "camera_v279.h"

int main(void) {
  char* filename = "blend/factory_v279.blend";
  char* camera = "Camera";
  // call Rust function                                                                                                                                       
  Vec_uint8_t bytes_read = extract_struct(filename, camera);
  // print returned bytes information                                                                                                                         
  printf("########################################\n");
  printf("%d bytes received from Rust\n", bytes_read.len);
  int i;
  for (i = 0; i < bytes_read.len; i++) {
    uint8_t byte_read = bytes_read.ptr[i];
    if (byte_read) {
      printf("bytes_read[%d] = %d\n", i, byte_read);
    }
  }
  // blend_info -n Camera blend/factory_v279.blend > examples/camera_v279.h                                                                                   
  // 1. replace unknown types/structs by char some_name[byte_count];                                                                                          
  // 2. replace pointers by void* pointers                                                                                                                    
  // 3. cast pointer to struct defined in header                                                                                                              
  struct Camera_v279* cam_v279 = (struct Camera_v279*) bytes_read.ptr;
  // print some float values from Camera struct (for Blender v2.79)                                                                                           
  printf("########################################\n");
  printf("Camera.clipsta = %f\n", cam_v279->clipsta);
  printf("Camera.clipend = %f\n", cam_v279->clipend);
  printf("Camera.lens = %f\n", cam_v279->lens);
}

The C bindings are not done (yet), but the git repository exists and there is a clear path for further development, therefore:

Ticket closed

Register here or Log in to comment, or comment via email.