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

作者: Neisseria (Neisseria)   2016-12-01 16:57:48
在最後一篇中,我們寫一個 matrix 的例子
我們仍然會使用 struct,但在 struct 中會再包 2D vector
[Update]
加入釋放記憶體相關程式碼,冏rz
想看程式碼的板友,可到以下 repo
https://github.com/cwchentw/libmatrix-rust-demo
首先,用 Rust 撰寫 library 部分程式碼
#[repr(C)]
pub struct Matrix {
m: Vec<Vec<f64>>,
}
#[no_mangle]
pub extern "C" fn matrix_new(nrow: usize, ncol: usize) -> *mut Matrix {
let mut m = Vec::new();
for j in 0..(nrow) {
let mut n = Vec::new();
for i in 0..(ncol) {
n.push(0.0);
}
m.push(n);
}
Box::into_raw(Box::new(Matrix { m: m }))
}
#[no_mangle]
pub extern "C" fn matrix_get_at(matrix: *const Matrix, row: usize, col: usize)
-> f64 {
unsafe { (*matrix).m[row][col] }
}
#[no_mangle]
pub extern "C" fn matrix_set_at(matrix: *mut Matrix, value: f64,
row: usize, col: usize) {
unsafe { (*matrix).m[row][col] = value; }
}
#[no_mangle]
pub extern "C" fn matrix_free(matrix: *mut Matrix) {
if matrix.is_null() {
return
}
unsafe { Box::from_raw(matrix); }
}
雖然,我們沒有真正實作 matrix 的處理,只寫了 getter/setter。
但是,這只是展示使用 2D vector 的程式,就請各位板友包涵
同樣地,加入釋放記憶體相關的程式碼
接著,撰寫相關的 C 程式碼
#include <stdio.h>
void* matrix_new(size_t, size_t);
double matrix_get_at(void*, size_t, size_t);
void matrix_set_at(void*, double, size_t, size_t);
void matrix_free(void*);
int main() {
void* m = matrix_new(3, 3);
printf("(1, 1) = %lf\n", matrix_get_at(m, 1, 1));
matrix_set_at(m, 99, 1, 1);
printf("(1, 1) = %lf\n", matrix_get_at(m, 1, 1));
matrix_free(m);
return 0;
}
同樣地,用 void* 接 Rust 的 struct
接著,撰寫相關的 Ruby 程式碼
require 'ffi'
require 'objspace'
module MyLib
extend FFI::Library
ffi_lib 'c'
ffi_lib 'target/release/libmatrix.so'
attach_function :matrix_new, [:int, :int], :pointer
attach_function :matrix_get_at, [:pointer, :int, :int], :double
attach_function :matrix_set_at, [:pointer, :double, :int, :int], :void
attach_function :matrix_free, [:pointer], :void
class Matrix
def initialize(row, col)
@m = MyLib::matrix_new(row, col)
ObjectSpace.define_finalizer(self, self.class.finalize)
end
def self.finalize
proc { MyLib::matrix_free @m }
end
def get_at(row, col)
MyLib::matrix_get_at(@m, row, col)
end
def set_at(value, row, col)
MyLib::matrix_set_at(@m, value, row, col)
end
end
end
m = MyLib::Matrix.new(3, 3)
puts "(1, 1) = #{m.get_at(1, 1)}"
m.set_at(99, 1, 1)
puts "(1, 1) = #{m.get_at(1, 1)}"
同樣地,稍微包裝函式庫,讓語法更接近 Ruby 的語法
透過以上數個範例,可知 Rust 的確有潛力用在 Rugy gem 的撰寫
不過 Rust 上手難度偏高,板工目前也還在跟 Rust 的編譯器奮戰中 Orz
而且,Rust 的能見度和相關資源仍然較少,也是需要考慮的點
是否要將 Rust 引入自己下一個專案中,就請各位板友自行判斷
作者: mars90226 (火星人)   2016-12-01 20:36:00
推!Rust真的很難啊
作者: lc85301 (pomelocandy)   2016-12-01 22:35:00
猛!
作者: danny8376 (釣到一隻猴子@_@)   2015-01-18 09:49:00
我是不是該來補一篇 用Crystal寫Ruby gem 啦XDDD畢竟crystal比rust年輕啊w

Links booklink

Contact Us: admin [ a t ] ucptt.com