[心得] 用 Rust 撰寫 Ruby gem (2)

作者: Neisseria (Neisseria)   2016-12-01 16:37:38
承接上一篇,這次展示傳遞 struct
[Update]
修正 memory leak 相關 bug,歹勢 Orz
想直接看程式碼的話,可到以下 repo
https://github.com/cwchentw/libpoint-rust-demo
首先,以 Rust 實作 library 部分程式碼
#[repr(C)]
pub struct Point {
x: f64,
y: f64,
}
#[no_mangle]
pub extern "C" fn point_new(x: f64, y: f64) -> *const Point {
Box::into_raw(Box::new(Point { x: x, y: y }))
}
#[no_mangle]
pub extern "C" fn point_get_x(p: *const Point) -> f64 {
unsafe { (*p).x }
}
#[no_mangle]
pub extern "C" fn point_get_y(p: *const Point) -> f64 {
unsafe { (*p).y }
}
#[no_mangle]
pub extern "C" fn point_free(p: *mut Point) {
if p.is_null() {
return
}
unsafe { Box::from_raw(p); }
}
仔細觀看程式碼,可以發現充滿 C-style 的物件導向寫法
另外可以注意的點,在於用 Box 包裝 pointer to struct
加入釋放記憶體相關程式碼
接著,撰寫相關的 C 程式碼
#include <stdio.h>
void* point_new(double, double);
double point_get_x(void*);
double point_get_y(void*);
void point_free(void*);
int main() {
void* p = point_new(6, 4);
printf("(%lf, %lf)\n", point_get_x(p), point_get_y(p));
point_free(p);
return 0;
}
由以上程式碼可看出,在 C 的層級,就是用萬用的 void* 去接 Rust 的 struct
已加入釋放記憶體相關程式碼
接著,撰寫相關的 Ruby 程式碼
require 'ffi'
require 'objspace'
module MyLib
extend FFI::Library
ffi_lib 'c'
ffi_lib 'target/release/libpoint.so'
attach_function :point_new, [:double, :double], :pointer
attach_function :point_get_x, [:pointer], :double
attach_function :point_get_y, [:pointer], :double
attach_function :point_free, [:pointer], :void
class Point
def initialize(x, y)
@p = MyLib::point_new x, y
ObjectSpace.define_finalizer(self, self.class.finalize)
end
def self.finalize
proc { MyLib::point_free @p }
end
def x
MyLib::point_get_x @p
end
def y
MyLib::point_get_y @p
end
end
end
p = MyLib::Point.new(6, 4)
puts "(#{p.x}, #{p.y})"
在這裡,我們稍微包裝一下函式庫,使得語法較接近 Ruby 的慣用語法
由以上範例可觀察出,Rust 可傳遞 struct,使得可應用的範圍就廣得多
在下一個範例中,會展示另一個用 struct 的例子

Links booklink

Contact Us: admin [ a t ] ucptt.com