将 Ruby 字符串转换为 Rust,然后再转回 Ruby 字符串

9

我正在尝试将一个字符串从Ruby传递给Rust可执行文件,对其进行操作并将操作后的字符串传回。

到目前为止,我已经成功地传递了字符串并将其返回,但是我不知道如何将其转换为Rust字符串、操作它,然后将其传回Ruby。以下是我的代码:

// lib.rs
use std::ffi::CStr;

#[no_mangle]
pub extern fn return_string(test_str: &CStr) -> &CStr {
    // working funciton
    test_str
}

#[no_mangle]
pub extern fn manipulate_and_return_string(mystr: &CStr) -> &CStr {
    // mystr type == &std::ffi::c_str::CStr
    // println!("{:?}", mystr); => std::ffi::c_str::CStr` cannot be formatted using `:?`
    let cstr = mystr.to_bytes_with_nul();
    // println!("{:?}", mystr); => []
    // cstr type == &[u8]
    let ptr = cstr.as_ptr();
    // ptr type == *const u8
    // println!("{:?}", mystr); => 0x7fd898edb520
    let str_slice: &str = std::str::from_utf8(cstr).unwrap();
    // str type == &str
    // println!("{:?}", mystr); => ""
    let str_buf: String = str_slice.to_owned();
    // str_bug == collections::string::String
    // println!("{:?}", mystr); => ""
}

# rust.rb
require 'ffi'

module Rust
  extend FFI::Library
  ffi_lib './bin/libembed.dylib'

  attach_function :return_string, [:string], :string
  attach_function :manipulate_and_return_string, [:string], :string
end

7
简评:这里存在两个直接问题。首先,CStr不是一个FFI安全类型,不能像这样使用。您应该使用*const libc::c_char。其次,答案完全取决于谁拥有生成的字符串。Ruby是否管理它?如果是这样,它是如何管理的?它需要在哪个堆上分配?Rust是否仍然拥有它?如果是这样,如何提供清理函数?我能建议的就是找出如何在C中做到这一点,然后用Rust以同样的方式实现。 - DK.
2
还可以查看https://dev59.com/6l0a5IYBdhLWcg3wS268,因为它涵盖了所有重要的部分。在那一点上将其适应Ruby很容易。 - Shepmaster
1
这篇文章 http://clalance.blogspot.ca/2011/01/writing-ruby-extensions-in-c-part-8.html 会很有帮助,还有 https://github.com/ruby/ruby/blob/trunk/doc/extension.rdoc - Steve Klabnik
mpiccolo解决方案的更新:根据这个讨论 https://github.com/rust-lang/rust/issues/27769,`into_ptr`现在被称为`into_raw`。我已经测试并使用`into_raw`成功。 - Sébastien Faure
1个回答

6

Steve KlabnikshepmasterDK 的指导下,我学会了如何在 Rust 中编写一个外部字符串连接函数,并在 Ruby 中使用它。

// lib.rs
#![feature(libc)]
#![feature(cstr_to_str)]
#![feature(cstr_memory)]
extern crate libc;
use std::ffi::{CStr,CString};

#[no_mangle]
pub extern fn concat(s1: *const libc::c_char, s2: *const libc::c_char) -> *const libc::c_char {
    let s1_cstr = unsafe { CStr::from_ptr(s1) };  // &std::ffi::c_str::CStr
    let s2_cstr = unsafe { CStr::from_ptr(s2) };  // &std::ffi::c_str::CStr
    let s1_and_str = s1_cstr.to_str().unwrap();  // &str
    let s2_and_str = s2_cstr.to_str().unwrap();  // &str

    let mut s1_string = s1_and_str.to_string();  // collections::string::String

    s1_string.push_str(s2_and_str);
    // s1_string + s2_and_str); // same thing

    let concated_string = CString::new(s1_string).unwrap();  // std::ffi::c_str::CString

    concated_string.into_ptr() // const i8
}

# rust.rb
require 'ffi'

module Rust
  extend FFI::Library
  ffi_lib './bin/libembed.dylib'

  attach_function :concat, [:string, :string], :string
end

#calling the function in Ruby

Rust.concat('This is a ', 'cohesive sentence') # => 'This is a cohesive sentence'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接