feat: impl C ffi

This commit is contained in:
leeeon233 2023-01-28 19:59:37 +08:00 committed by Leonzhao
parent a26d4b0122
commit 95309db710
5 changed files with 70 additions and 33 deletions

2
crates/loro-ffi/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
examples/cpp/loro
examples/cpp/*.a

View file

@ -1,35 +1,8 @@
extern crate cbindgen;
use cbindgen::Config;
use std::env;
use std::path::PathBuf;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let package_name = env::var("CARGO_PKG_NAME").unwrap();
let output_file = target_dir()
.join(format!("{}.hpp", package_name))
.display()
.to_string();
let config = Config {
namespace: Some(String::from("loro_ffi")),
..Default::default()
};
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let config = cbindgen::Config::from_file("cbindgen.toml")
.expect("Unable to find cbindgen.toml configuration file");
cbindgen::generate_with_config(&crate_dir, config)
.unwrap()
.write_to_file(&output_file);
}
/// Find the location of the `target/` directory. Note that this may be
/// overridden by `cmake`, so we also need to check the `CARGO_TARGET_DIR`
/// variable.
fn target_dir() -> PathBuf {
if let Ok(target) = env::var("CARGO_TARGET_DIR") {
PathBuf::from(target)
} else {
PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("target")
}
.write_to_file("target/loro_ffi.h");
}

View file

@ -1,3 +1,7 @@
include_guard = "libloro_ffi_h"
header = """
typedef struct LoroCore {} LoroCore;
typedef struct Text {} Text;
"""
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
language = "C"

View file

@ -0,0 +1,14 @@
#include <stdio.h>
extern "C" {
#include "../../target/loro_ffi.h"
};
int main(void) {
LoroCore* loro = loro_new();
Text* text = loro_get_text(loro, "text");
text_insert(text, loro, 0, "abc");
char* str = text_value(text);
printf("%s", str);
text_free(text);
loro_free(loro);
}

View file

@ -1,4 +1,9 @@
use loro_core::LoroCore;
use std::ffi::{c_char, c_uint, CStr, CString};
pub type LoroCore = loro_core::LoroCore;
pub type Text = loro_core::Text;
pub type List = loro_core::List;
pub type Map = loro_core::Map;
/// create Loro with a random unique client id
#[no_mangle]
@ -13,3 +18,42 @@ pub unsafe extern "C" fn loro_free(loro: *mut LoroCore) {
drop(Box::from_raw(loro));
}
}
#[no_mangle]
pub unsafe extern "C" fn loro_get_text(loro: *mut LoroCore, id: *const c_char) -> *mut Text {
assert!(!loro.is_null());
assert!(!id.is_null());
let id = CStr::from_ptr(id).to_str().unwrap();
let text = loro.as_mut().unwrap().get_text(id);
Box::into_raw(Box::new(text))
}
#[no_mangle]
pub unsafe extern "C" fn text_free(text: *mut Text) {
if !text.is_null() {
drop(Box::from_raw(text));
}
}
#[no_mangle]
pub unsafe extern "C" fn text_insert(
text: *mut Text,
ctx: *const LoroCore,
pos: *const c_uint,
value: *const c_char,
) {
assert!(!text.is_null());
assert!(!ctx.is_null());
let text = text.as_mut().unwrap();
let ctx = ctx.as_ref().unwrap();
let value = CStr::from_ptr(value).to_str().unwrap();
text.insert(ctx, pos as usize, value).unwrap();
}
#[no_mangle]
pub unsafe extern "C" fn text_value(text: *mut Text) -> *mut c_char {
assert!(!text.is_null());
let text = text.as_mut().unwrap();
let value = text.get_value().as_string().unwrap().to_string();
CString::new(value).unwrap().into_raw()
}