Skip to content

Commit 51c377e

Browse files
committed
Add ruby/python ffi call rust dylib example
1 parent 0b673d5 commit 51c377e

File tree

4 files changed

+127
-1
lines changed

4 files changed

+127
-1
lines changed

c_call_rust_lib/main.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ typedef struct {
99
int x;
1010
int y;
1111
} Point;
12-
1312
void print_point(Point point);
1413

14+
// Rust:Box<T> -> C:opaque type(不透明数据类型)
15+
typedef struct OpaqueType Map;
16+
Map* map_new();
17+
void map_insert(Map* map, int k, int v);
18+
int map_get(Map* map, int k);
19+
void map_free(Map* map);
20+
1521
/*
1622
static link:
1723
cargo build && gcc main.c ../target/debug/libc_call_rust_lib.a && ./a.out
@@ -29,5 +35,11 @@ int main() {
2935
printf("sum = %d\n", sum);
3036
Point point = {.x=1, .y=2};
3137
print_point(point);
38+
39+
Map* map = map_new();
40+
map_insert(map, 1, 1);
41+
printf("map_get(map, 1) = %d\n", map_get(map, 1));
42+
printf("map_get(map, 2) = %d\n", map_get(map, 2));
43+
map_free(map);
3244
return 0;
3345
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/python3
2+
3+
import ctypes
4+
5+
6+
class MapPtr(ctypes.Structure):
7+
pass
8+
9+
10+
lib = ctypes.cdll.LoadLibrary("../target/debug/libc_call_rust_lib.dylib")
11+
lib.map_new.restype = ctypes.POINTER(MapPtr)
12+
lib.map_insert.argtypes = (ctypes.POINTER(MapPtr), ctypes.c_int, ctypes.c_int)
13+
lib.map_get.argtypes = (ctypes.POINTER(MapPtr), ctypes.c_int)
14+
lib.map_get.restype = ctypes.c_int
15+
lib.map_free.argtypes = (ctypes.POINTER(MapPtr),)
16+
17+
18+
class Map:
19+
def __init__(self):
20+
self.ptr: ctypes.POINTER(MapPtr) = lib.map_new()
21+
22+
def __enter__(self):
23+
return self
24+
25+
def __exit__(self, exc_type, exc_value, traceback):
26+
lib.map_free(self.ptr)
27+
28+
def insert(self, k: int, v: int):
29+
lib.map_insert(self.ptr, k, v)
30+
31+
def get(self, k: int) -> int:
32+
return lib.map_get(self.ptr, k)
33+
34+
35+
if __name__ == '__main__':
36+
with Map() as my_map:
37+
my_map.insert(1, 1)
38+
print(f"map.get(1) = {my_map.get(1)}")
39+
print(f"map.get(2) = {my_map.get(2)}")

c_call_rust_lib/ruby_call_rust_lib.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/ruby
2+
3+
require 'ffi'
4+
5+
module MyLib
6+
extend FFI::Library
7+
ffi_lib "/Users/wuaoxiang/workspace/my_repo_or_learn/rust_learn/target/debug/libc_call_rust_lib.dylib"
8+
attach_function :map_new, [], :pointer
9+
attach_function :map_insert, [:pointer, :int, :int], :int
10+
attach_function :map_get, [:pointer, :int], :int
11+
attach_function :map_free, [:pointer], :void
12+
end
13+
14+
map = MyLib.map_new
15+
MyLib.map_insert(map, 1, 1)
16+
p MyLib.map_get(map, 1)
17+
MyLib.map_free(map)

c_call_rust_lib/src/lib.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,61 @@ pub struct Point {
5656
pub extern "C" fn print_point(point: Point) {
5757
dbg!(point);
5858
}
59+
60+
use std::collections::HashMap;
61+
pub struct Map(HashMap<c_int, c_int>);
62+
63+
impl Map {
64+
fn new() -> Self {
65+
Self(HashMap::new())
66+
}
67+
68+
fn insert(&mut self, key: c_int, value: c_int) {
69+
self.0.insert(key, value);
70+
}
71+
72+
fn get(&self, key: c_int) -> c_int {
73+
return if let Some(&val) = self.0.get(&key) {
74+
val
75+
} else {
76+
c_int::from(-1)
77+
};
78+
}
79+
}
80+
81+
// Rust:Box<T> -> C:opaque type(不透明数据类型)
82+
#[no_mangle]
83+
pub extern "C" fn map_new() -> *mut Map {
84+
// Map::new() as *mut Map
85+
Box::into_raw(Box::new(Map::new()))
86+
}
87+
88+
#[no_mangle]
89+
pub extern "C" fn map_insert(map: *mut Map, k: c_int, v: c_int) {
90+
if map.is_null() {
91+
return;
92+
}
93+
let map_deref = unsafe {
94+
&mut *map
95+
};
96+
map_deref.insert(k, v);
97+
}
98+
99+
#[no_mangle]
100+
pub extern "C" fn map_get(map: *const Map, k: c_int) -> c_int {
101+
if map.is_null() {
102+
return c_int::from(-1);
103+
}
104+
let map_deref = unsafe {
105+
&*map
106+
};
107+
map_deref.get(k)
108+
}
109+
110+
#[no_mangle]
111+
pub extern "C" fn map_free(map: *mut Map) {
112+
if map.is_null() {
113+
return;
114+
}
115+
Box::from(map);
116+
}

0 commit comments

Comments
 (0)