【问题标题】:Is it possible to call Rust's struct fields directly from Ruby code without implementing extern "C" getter to the corresponding fields是否可以直接从 Ruby 代码调用 Rust 的 struct 字段而不对相应的字段实现 extern "C" getter
【发布时间】:2014-10-17 06:03:08
【问题描述】:

我正在考虑用 Rust 编写一个 Ruby gem。假设我想在 Rust 中创建一些结构,这些结构返回到类似于示例here 的 Ruby 代码。在将 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 结构。当然,处理 rust 代码中的 ruby​​ 对象需要一个库。

【问题讨论】:

    标签: ruby rubygems rust


    【解决方案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
    

    【讨论】:

    • 这将是一个解决方案,但在这种情况下,我也可以使用我提到的 extern c 方法在 ruby​​ 中实现一个 Point 类。这会更快。我的问题更多是关于某种原生扩展。因此,给 ruby​​ 一个 rust 结构,它本身就表现得像一个 ruby​​ 结构。
    【解决方案2】:

    Rust 也为 struct 提供了原生 C 接口。如果你这样定义你的结构:

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

    它的行为类似于 C 结构

    struct Point
    {
        int32_t x;
        int32_t y;
    }
    

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

    我建议使用固定大小的 int 类型而不是普通的 int,因为你无法真正保证 Rust 的 int 与 C 的 int 大小相同。如果你真的需要使用它,你可能应该使用libc::c_int

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      • 2014-09-09
      • 2020-11-24
      相关资源
      最近更新 更多