是否可以直接从Ruby代码调用Rust的struct字段而不实现extern" C" getter到相应的字段

时间:2014-10-17 06:03:08

标签: ruby rubygems rust

我正在考虑用Rust编写Ruby gem。让我们假设我想在Rust中创建一些结构,这些结构返回到Ruby代码,类似于示例here。在将Point结构添加到我的Ruby代码中时,我想直接调用它的属性。目前我必须做类似的事情:

point.rb:

require "fiddle"
require "fiddle/import"

module RustPoint
  extend Fiddle::Importer

  dlload "./libmain.dylib"

  extern "Point* make_point(int, int)"
  extern "double get_distance(Point*, Point*)"
  extern "int y(Point*)"
  extern "int x(Point*)"

end

main.rs:

use std::num::pow;

pub struct Point { x: int, y: int }

#[no_mangle]
pub extern "C" fn make_point(x: int, y: int) -> Box<Point> {
  box Point { x: x, y: y }
}

#[no_mangle]
pub extern "C" fn x(p: &Point) -> int {
  p.x
}

#[no_mangle]
pub extern "C" fn y(p: &Point) -> int {
  p.y
}

并在Ruby中使用它:

point = RustPoint::make_point(0, 42)
# To get x:
x = RustPoint::x(point)

获取x值。我更喜欢这样的东西:

point = RustPoint::make_point(0, 42)
# To get x:
x = point.x

有没有人知道一个库或一种方法来简化这个实现。我认为如果我从红宝石方面看不出有关点对象的话会更好。我不应该有所作为天气这是一个C扩展,一个Ruby对象或用Rust编写。

编辑:我希望Rust代码的行为类似于原生扩展。因此返回的结构应该可以从Ruby端调用,类似于使用ruby对象作为值的C结构。当然,有一个库可以处理生锈代码中的ruby对象。

2 个答案:

答案 0 :(得分:1)

您可以将整个事物包装在自定义委托人中:

class RustDelegator
  attr_accessor :__delegate_class__, :__delegate__

  def method_missing(method_name, *arguments, &block)
    __delegate_class__.public_send(method_name, *__rust_arguments__(arguments), &block)
  end

  def respond_to_missing(name, include_private = false)
    __delegate_class__.respond_to?(name, include_private)
  end

  private

  def __rust_arguments__(arguments)
    arguments.unshift(__delegate__)
  end
end

class Point < RustDelegator
  def initialize(x, y)
    self.__delegate_class__ = RustPoint
    self.__delegate__ = RustPoint::make_point(0, 42)
  end
end

p = Point.new(0, 42)
#=> #<Point:0x007fb4a4b5b9d0 @__delegate__=[0, 42], @__delegate_class__=RustPoint>

p.x
#=> 0

p.y
#=> 42

答案 1 :(得分:0)

Rust也为struct提供了本机C接口。如果您像这样定义结构:

#[repr(C)]
pub struct Point {
    pub x: i32,
    pub y: i32
}

它的行为类似于C struct

struct Point
{
    int32_t x;
    int32_t y;
}

然后,您可以像在任何其他C结构中一样在Ruby中使用它。

我建议使用固定大小的int类型而不是普通的int,因为你没有真正的担保Rust&#39; int与C&{39}的int大小相同}。如果您确实需要使用它,则应该使用libc::c_int