Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rust + Ruby/mruby

Rust + Ruby/mruby

Gosuke Miyashita
PRO

November 25, 2017
Tweet

More Decks by Gosuke Miyashita

Other Decks in Technology

Transcript

  1. RustͰॻ͍ͨϥΠϒϥϦ
    ΛRuby/mruby͔Βݺ
    ͼग़࣮͢ફతͳํ๏
    ෱ԬRubyձٞ02 1

    View Slide

  2. ࣗݾ঺հ
    • ٶԼ ߶ี
    • ߹ಉձࣾServerspec Operations୅ද
    • ϑϦʔϥϯεͷιϑτ΢ΣΞΤϯδχΞ
    • http://mizzy.org/
    • mizzy@github, gosukenator@twitter
    ෱ԬRubyձٞ02 2

    View Slide

  3. ஶॻɾ؂༁ॻ
    ෱ԬRubyձٞ02 3

    View Slide

  4. ࠓ೔ͷൃදʹࢸΔܦҢ
    • libspecinfraͱ͍͏OSSϓϩδΣΫτΛ΍͍ͬͯΔ
    • ͜ͷϓϩδΣΫτ͸ҎԼͷߏ੒ཁૉΛ࣋ͭ
    • RustͰ࣮૷ͨ͠ڞ༗ϥΠϒϥϦ
    • ڞ༗ϥΠϒϥϦΛར༻͢ΔͨΊͷ֤छݴޠόΠϯσΟϯά
    ෱ԬRubyձٞ02 4

    View Slide

  5. ࠓ೔ͷൃදʹࢸΔܦҢʢ͖ͭͮʣ
    • Ruby/mrubyόΠϯσΟϯάΛ։ൃ͢ΔͨΊͷํ๏Λௐ΂ͨ
    • ॳาతͳ৘ใ͸ͨ͘͞Μ͋Δ͕࣮ફతͳ৘ใ͸Ҋ֎গͳ͍
    • ৭ʑࢼߦࡨޡͨ͠ͷͰ·ͱΊ͓ͯ͜͏ͱࢥͬͨ
    • ؒҧ͍΍ΑΓྑ͍΍Γํ͕͋Ε͹ࣝऀ͕ࢦఠͯ͘͠Εͦ͏
    • ٱʑʹ෱Ԭʹߦ͘ޱ࣮͕ཉ͔ͬͨ͠
    ෱ԬRubyձٞ02 5

    View Slide

  6. ΞδΣϯμ
    • RustͱFFI
    • ೖ໳Rust + Ruby/mruby
    • ࣮ફRust + Ruby/mruby
    • libspecinfraϓϩδΣΫτͷ֓ཁʢ͕࣌ؒ͋Ε͹ʣ
    • ※Rust౳ͷݴޠ࢓༷తͳ࿩͸͠·ͤΜ
    ෱ԬRubyձٞ02 6

    View Slide

  7. RustͱFFI
    ෱ԬRubyձٞ02 7

    View Slide

  8. FFIͱ͸
    • Foreign Function Interface
    • ͋Δϓϩάϥϛϯάݴޠ͔ΒଞͷϓϩάϥϛϯάݴޠͰఆٛ
    ͞Εͨؔ਺ͳͲΛར༻͢ΔͨΊͷػߏ
    • RustɺRubyɺmrubyʹݶΒͳ͍
    ෱ԬRubyձٞ02 8

    View Slide

  9. RustͱFFI
    • Rustʹ͸FFI͕૊Έࠐ·Ε͓ͯΓެࣜυΩϡϝϯτ΋͋Δ
    • ओͳػೳ͸େ͖͘2ͭ
    • ଞݴޠͰॻ͔ΕͨϥΠϒϥϦͷؔ਺ΛݺͿػೳ
    • ଞݴޠʢओʹCʣ͔Βؔ਺Λݺ΂ΔΑ͏ʹ͢Δػೳ
    ෱ԬRubyձٞ02 9

    View Slide

  10. ଞݴޠͰॻ͔ΕͨϥΠϒϥϦؔ਺ΛݺͿ
    #[link(name = "snappy")]
    extern {
    fn snappy_max_compressed_length(source_length: size_t) -> size_t;
    }
    fn main() {
    let x = unsafe { snappy_max_compressed_length(100) };
    println!("max compressed length of a 100 byte buffer: {}", x);
    }
    https://doc.rust-lang.org/book/first-edition/ffi.html#calling-
    foreign-functions
    ෱ԬRubyձٞ02 10

    View Slide

  11. ଞݴޠ͔Βؔ਺Λݺ΂ΔΑ͏ʹ͢Δ
    #[no_mangle]
    pub extern "C" fn hello_rust() -> *const u8 {
    "Hello, world!\0".as_ptr()
    }
    https://doc.rust-lang.org/book/first-edition/ffi.html#calling-rust-
    code-from-c
    ෱ԬRubyձٞ02 11

    View Slide

  12. hello_rust()ΛC͔Βݺͼग़͢
    #include
    extern char *hello_rust(void);
    int main() {
    printf("%s\n", hello_rust());
    }
    cc hello.c -L. -lhello
    LD_LIBRARY_PATH=. ./a.out
    Hello, world!
    ෱ԬRubyձٞ02 12

    View Slide

  13. RustͱFFI·ͱΊ
    • FFI = Foreign Function Interface
    • ͋Δϓϩάϥϛϯάݴޠ͔ΒଞͷϓϩάϥϛϯάݴޠͰఆٛ
    ͞Εͨؔ਺ͳͲΛར༻͢ΔͨΊͷػߏ
    • Rustʹ͸FFI͕૊Έࠐ·Ε͍ͯͯɺଞͷݴޠͰॻ͔ΕͨϥΠϒ
    ϥϦͷؔ਺Λݺͼग़ͨ͠Γɺଞͷݴޠ͔ΒRustͰॻ͍ͨϥΠ
    ϒϥϦͷؔ਺Λݺͼग़ͨ͠ΓͰ͖Δ
    ෱ԬRubyձٞ02 13

    View Slide

  14. ೖ໳Rust
    +
    Ruby/mruby
    ෱ԬRubyձٞ02 14

    View Slide

  15. RustͰॻ͔ΕͨϥΠϒϥϦΛͲ͏ݺͿ͔
    • Ruby
    • native extension
    • ffi gemΛར༻ͯ͠libffiܦ༝Ͱݺͼग़͢
    • mruby
    • CͰ֦ு(mrbgem)Λॻ͘
    ෱ԬRubyձٞ02 15

    View Slide

  16. ೖ໳Rust + Ruby/mruby
    • RustͱRuby/mrubyΛͲ͏ܨ͙͔۩ମతͳίʔυͰࣔ͠·͢
    • ࣗ෼͕libspecinfraͷόΠϯσΟϯά։ൃͷͨΊʹֶΜͩͷͱಉ͡εςοϓΛḷ
    ͬͯΈ·͢
    • จࣈΛେ͖ͯ͘͠εϥΠυΛݟ΍͘͢͢ΔͨΊίʔυΛলུͨ͠Γਪ঑͞Εͳ
    ͍ॻ͖ํΛͯ͠Δ෦෼΋͋Γ·͢
    • ׬શͳίʔυ͸GitHubʹஔ͍ͯ͋Γ·͢
    • https://github.com/mizzy/fukuokark02_code_examples
    • εϥΠυͱඍົʹҧ͏෦෼΋͋Γ·͕͢
    ෱ԬRubyձٞ02 16

    View Slide

  17. ੔਺
    ෱ԬRubyձٞ02 17

    View Slide

  18. ੔਺ͷ଍͠ࢉΛߦ͏Rustίʔυ
    extern crate libc;
    use libc::uint32_t;
    #[no_mangle]
    pub extern "C" fn addition(a: uint32_t, b: uint32_t)
    -> uint32_t {
    a + b
    }
    ෱ԬRubyձٞ02 18

    View Slide

  19. Rustͷؔ਺Λݺͼग़͢Rubyίʔυ
    require 'ffi'
    module Integers
    extend FFI::Library
    ffi_lib 'addition'
    attach_function :addition, [:uint32, :uint32], :uint32
    end
    puts Integers.addition(1, 2)
    ෱ԬRubyձٞ02 19

    View Slide

  20. Rustͷؔ਺Λݺͼग़͢mrbgemίʔυ
    extern uint32_t addition(uint32_t, uint32_t);
    static mrb_value addition_(mrb_state *mrb, mrb_value self)
    {
    mrb_int a, b;
    mrb_get_args(mrb, "ii", &a, &b);
    return mrb_fixnum_value(addition(a, b));
    }
    void mrb_mruby_addition_gem_init(mrb_state *mrb)
    {
    struct RClass *i = mrb_define_module(mrb, "Integers");
    mrb_define_class_method(
    mrb, i, "addition", addition_, MRB_ARGS_REQ(2)
    );
    }
    ෱ԬRubyձٞ02 20

    View Slide

  21. mrbgemΛར༻ͨ͠mrubyίʔυ
    puts Integers.addition(1, 2)
    ෱ԬRubyձٞ02 21

    View Slide

  22. จࣈྻ
    ෱ԬRubyձٞ02 22

    View Slide

  23. จࣈྻʹ!!!Λ෇Ճ͢ΔRustίʔυ
    pub extern "C" fn emphasize(ptr: *const c_char)
    -> *const c_char {
    let s = unsafe {
    assert!(!ptr.is_null());
    CStr::from_ptr(ptr)
    }.to_str().unwrap();
    let str = s.to_owned() + "!!!";
    CString::new(str).unwrap().into_raw()
    }
    ෱ԬRubyձٞ02 23

    View Slide

  24. Rustͷؔ਺Λݺͼग़͢Rubyίʔυ
    module Strings
    extend FFI::Library
    ffi_lib 'emphasize'
    attach_function :emphasize, [:string], :string
    end
    puts Strings.emphasize("Hello")
    ෱ԬRubyձٞ02 24

    View Slide

  25. Rustͷؔ਺Λݺͼग़͢mrbgemίʔυ
    extern char *emphasize(char *);
    static mrb_value emphasize_(mrb_state *mrb, mrb_value self)
    {
    char *arg, *ret;
    mrb_int len;
    mrb_value str;
    mrb_get_args(mrb, "s", &arg, &len);
    ret = emphasize(arg);
    str = mrb_str_buf_new(mrb, sizeof(ret));
    return mrb_str_cat_cstr(mrb, str, ret);
    }
    ෱ԬRubyձٞ02 25

    View Slide

  26. mrbgemΛར༻ͨ͠mrubyίʔυ
    puts Strings.emphasize("Hello")
    ෱ԬRubyձٞ02 26

    View Slide

  27. ߏ଄ମ
    ෱ԬRubyձٞ02 27

    View Slide

  28. ߏ଄ମ
    • ͜Ε͸লུ
    • ҰԠॻ͖͔͚ͷίʔυ͸αϯϓϧϦϙδτϦʹ͋Γ·͢
    • ҎԼͷهࣄ͕ࢀߟʹͳΓ·͢
    • Ruby-FFIʹ͍ͭͯௐ΂ͯΈͨɻʢͦͷ2ʣ - ͍΋ͷ΍·ɻ
    • http://yamaimo.hatenablog.jp/entry/2015/05/22/200000
    • mruby Ͱ C ݴޠͷߏ଄ମΛϥοϓͨ͠ΦϒδΣΫτΛ࡞Δਖ਼͍͠ํ๏ - Qiita
    • https://qiita.com/tsahara@github/items/86610a696f8ca792db45
    ෱ԬRubyձٞ02 28

    View Slide

  29. ߏ଄ମ
    • ׂͱ໘౗͍͘͞
    • RustଆͱRuby/mrubyͰಉ͡ߏ଄ମΛఆٛ͢Δඞཁ͕͋Δ
    • ߏ଄ମͷத਎͸Ruby/mruby͔ΒݟΕ͹Ͳ͏Ͱ΋͍͍ʢࣗ෼͕։ൃ͠
    ͯΔlibspecinfraͰ͸ʣ
    • ΦϒδΣΫτͱͯ͠ѻ͍͍ͨ
    • RustଆͷstructΛࣔ͢ϙΠϯλͱͦΕΛѻ͏ؔ਺͚ͩ͋Ε͹े෼Ͱ
    ͸ʁ
    ෱ԬRubyձٞ02 29

    View Slide

  30. ೖ໳Rust + Ruby/mruby·ͱΊ
    • ੔਺Ҿ਺ͱฦΓ஋ɺจࣈྻҾ਺ͱฦΓ஋Λѻ͏ίʔυྫΛࣔͨ͠
    • ߏ଄ମʹ͍ͭͯ͸ɺlibspecinfra։ൃͷͨΊʹௐ΂ͯΔ్தͰɺ
    ͜Ε͸ࣗ෼ͷ΍Γ͍ͨ͜ͱͱ͸ҧ͏ɺͱࢥͬͨͷͰུ
    • ߏ଄ମ(Rustͷstruct)Λߏ଄ମͱͯ͠ѻ͍͍ͨͷͰ͸ͳ͘ɺΦϒδ
    ΣΫτͱͯ͠ѻ͍͍ͨ
    • ͦͷ΍Γํ͸࣍Ͱղઆ͠·͢
    ෱ԬRubyձٞ02 30

    View Slide

  31. ࣮ફRust
    +
    Ruby/mruby
    ෱ԬRubyձٞ02 31

    View Slide

  32. ࣮ફRust + Ruby/mruby
    • ͔͜͜Β͸࣮ࡍͷlibspecinfraͷίʔυΛϕʔεͱͨ͠ղઆΛ
    ͠·͢
    • ׬શʹಉ͡ίʔυͰ͸ͳ͘؆ུԽͯ͋͠Γ·͢
    • ͪ͜Βͷίʔυ΋GitHubʹ͋Γ·͢
    • https://github.com/mizzy/fukuokark02_code_examples
    ෱ԬRubyձٞ02 32

    View Slide

  33. ΦϒδΣΫτ
    ෱ԬRubyձٞ02 33

    View Slide

  34. ΦϒδΣΫτΛѻ͏ίʔυ(Rust)
    ͜Μͳײ͡ͰϑΝΠϧͷύʔϛογϣϯΛऔಘ͍ͨ͠
    let s = Specinfra::new();
    let f = s.file("/etc/passwd");
    println!("{:o}", f.mode());
    ෱ԬRubyձٞ02 34

    View Slide

  35. SpecinfraΦϒδΣΫτͷఆٛ(Rust)
    pub struct Specinfra;
    impl Specinfra {
    pub fn new() -> Specinfra {
    Specinfra
    }
    pub fn file(self, name: &str) -> File {
    File { name: name }
    }
    }
    ෱ԬRubyձٞ02 35

    View Slide

  36. FileΦϒδΣΫτͷఆٛ(Rust)
    pub struct File<'a> {
    name: &'a str,
    }
    impl<'a> File<'a> {
    pub fn mode(self) -> i32 {
    // ύʔϛογϣϯΛऔಘͯ͠ฦ͢ॲཧ
    }
    }
    ෱ԬRubyձٞ02 36

    View Slide

  37. SpecinfraΦϒδΣΫτͷ֎෦༻ఆٛ(Rust)
    pub extern "C" fn specinfra_new() -> *const Specinfra {
    let s = Specinfra::new();
    Box::into_raw(Box::new(s))
    }
    pub extern "C" fn specinfra_file<'a>(ptr: *const Specinfra,
    name: *const c_char)
    -> *const File<'a> {
    let s = unsafe { &*ptr };
    let name = unsafe { CStr::from_ptr(name) };
    Box::into_raw(Box::new(s.file(name.to_str().unwrap())))
    }
    ෱ԬRubyձٞ02 37

    View Slide

  38. FileΦϒδΣΫτͷ֎෦༻ఆٛ(Rust)
    pub extern "C" fn file_mode(ptr: *const File)
    -> int32_t {
    let f = unsafe {
    assert!(!ptr.is_null());
    &*ptr
    };
    f.mode()
    }
    ෱ԬRubyձٞ02 38

    View Slide

  39. ΦϒδΣΫτ։์༻ͷؔ਺(Rust)
    pub extern "C" fn specinfra_free(ptr: *mut Specinfra) {
    unsafe { Box::from_raw(ptr); }
    }
    pub extern "C" fn file_free(ptr: *mut File) {
    unsafe { Box::from_raw(ptr); }
    }
    ෱ԬRubyձٞ02 39

    View Slide

  40. ΦϒδΣΫτΛѻ͏ίʔυ(Ruby)
    ͜Μͳײ͡ͰϑΝΠϧͷύʔϛογϣϯऔಘ͍ͨ͠
    s = Specinfra::Binding.new
    f = s.file("/etc/passwd")
    printf("%#o\n", f.mode)
    ෱ԬRubyձٞ02 40

    View Slide

  41. SpecinfraΦϒδΣΫτ(Ruby)
    class Specinfra < FFI::AutoPointer
    def self.release(ptr)
    Binding.free(ptr)
    end
    def file(name)
    Binding.file(self, name)
    end
    module Binding
    attach_function :new, :specinfra_new, [], Specinfra
    attach_function :free, :specinfra_free, [Specinfra], :void
    attach_function :file, :specinfra_file, [Specinfra, :string], File
    end
    end
    ෱ԬRubyձٞ02 41

    View Slide

  42. FileΦϒδΣΫτ(Ruby)
    class File < FFI::AutoPointer
    def self.release(ptr)
    file_free(ptr)
    end
    def mode()
    file_mode(self)
    end
    attach_function :file_free, [File], :void
    attach_function :file_mode, [File], :int
    end
    ෱ԬRubyձٞ02 42

    View Slide

  43. ΦϒδΣΫτΛѻ͏ίʔυ(mruby)
    ͜Μͳײ͡ͰϑΝΠϧͷύʔϛογϣϯऔಘ͍ͨ͠
    s = Specinfra.new
    f = s.file("/etc/passwd")
    printf("%#o\n", f.mode)
    ෱ԬRubyձٞ02 43

    View Slide

  44. FileΦϒδΣΫτؔ࿈ఆٛ(mrbgem)
    typedef int file;
    extern int file_mode(file *);
    extern void file_free(file *);
    struct mrb_data_type mrb_file_type
    = { "File", mrb_file_free };
    ෱ԬRubyձٞ02 44

    View Slide

  45. SpecinfraΦϒδΣΫτؔ࿈ఆٛ(mrbgem)
    typedef int specinfra;
    extern specinfra *specinfra_new(void);
    extern file *specinfra_file(specinfra *, char *);
    extern void specinfra_free(specinfra *);
    struct mrb_data_type mrb_specinfra_type
    = { "Specinfra", mrb_specinfra_free };
    ෱ԬRubyձٞ02 45

    View Slide

  46. Specinfra.new(mrbgem)
    mrb_value specinfra_new_(mrb_state *mrb, mrb_value self)
    {
    specinfra *s = specinfra_new();
    DATA_TYPE(self) = &mrb_specinfra_type;
    DATA_PTR(self) = s;
    return self;
    }
    ෱ԬRubyձٞ02 46

    View Slide

  47. Specinfra#file(mrbgem)
    mrb_value specinfra_file_(mrb_state *mrb, mrb_value self)
    {
    mrb_value v;
    mrb_get_args(mrb, "S", &v);
    char *name = mrb_str_to_cstr(mrb, v);
    file *f = specinfra_file(DATA_PTR(self), name);
    struct RClass file_class = mrb_class_get(mrb, "File");
    mrb_value file_object = mrb_obj_new(mrb, file_class, 0, NULL);
    DATA_TYPE(file_object) = &mrb_file_type;
    DATA_PTR(file_object) = f;
    return file_object;
    }
    ෱ԬRubyձٞ02 47

    View Slide

  48. SpecinfraΦϒδΣΫτ։์༻ؔ਺(mrbgem)
    void mrb_specinfra_free(mrb_state *mrb, void *ptr)
    {
    specinfra_free(ptr);
    }
    ෱ԬRubyձٞ02 48

    View Slide

  49. File#mode(mrbgem)
    mrb_value file_mode_(mrb_state *mrb, mrb_value self)
    {
    file *f;
    int m;
    f = DATA_PTR(self);
    m = file_mode(f);
    return mrb_fixnum_value(m);
    }
    ෱ԬRubyձٞ02 49

    View Slide

  50. FileΦϒδΣΫτ։์༻ؔ਺(mrbgem)
    void mrb_file_free(mrb_state *mrb, void *ptr)
    {
    file_free(ptr);
    }
    ෱ԬRubyձٞ02 50

    View Slide

  51. ॳظԽ(mrbgem)
    void mrb_mruby_object_gem_init(mrb_state *mrb)
    {
    struct RClass *s
    = mrb_define_class(mrb, "Specinfra", mrb->object_class);
    mrb_define_method(mrb, s, "initialize", specinfra_new_, MRB_ARGS_NONE());
    mrb_define_method(mrb, s, "file", specinfra_file_, MRB_ARGS_REQ(1));
    struct RClass *f
    = mrb_define_class(mrb, "File", mrb->object_class);
    mrb_define_method(mrb, f, "mode", file_mode_, MRB_ARGS_NONE());
    }
    ෱ԬRubyձٞ02 51

    View Slide

  52. τϨΠτ
    ෱ԬRubyձٞ02 52

    View Slide

  53. τϨΠτΛѻ͏ίʔυ(Rust)
    ͜Μͳײ͡ͰBackendτϨΠτΛ࣮૷ͨ͠DirectΦϒδΣΫτΛ
    ౉͍ͨ͠
    let b = Direct::new();
    let s = Specinfra::new(b);
    ෱ԬRubyձٞ02 53

    View Slide

  54. SpecinfraΦϒδΣΫτͷमਖ਼(Rust)
    pub struct Specinfra<'a> {
    backend: &'a Backend,
    }
    impl<'a> Specinfra<'a> {
    pub fn new(b: &Backend) -> Specinfra {
    b.detect_platform();
    Specinfra { backend: b }
    }
    ...
    ෱ԬRubyձٞ02 54

    View Slide

  55. BackendτϨΠτͷఆٛͱ࣮૷(Rust)
    pub trait Backend {
    fn detect_platform(&self) -> &str;
    }
    pub struct Direct;
    impl Backend for Direct {
    fn detect_platform(&self) -> &str {
    // ϓϥοτϑΥʔϜ൑ผॲཧ
    }
    }
    ෱ԬRubyձٞ02 55

    View Slide

  56. SpecinfraΦϒδΣΫτͷ֎෦༻ఆٛ(Rust)
    Ҿ਺ͰτϨΠτΛड͚औΔΑ͏ʹ͍ͯ͠Δͱ…
    pub extern "C" fn specinfra_new<'a>(ptr: *const Backend)
    -> *const Specinfra<'a> {
    let b = unsafe { &*ptr };
    let s = Specinfra::new(b); // ͜ͷॲཧதͷ…
    Box::into_raw(Box::new(s))
    }
    ෱ԬRubyձٞ02 56

    View Slide

  57. ηάϑΥ…(Rust)
    impl<'a> Specinfra<'a> {
    pub fn new(b: &Backend) -> Specinfra {
    b.detect_platform(); // ͜͜ͰηάϑΥ͢Δ
    Specinfra { backend: b }
    }
    ෱ԬRubyձٞ02 57

    View Slide

  58. BackendWrapper structͷಋೖ(Rust)
    τϨΠτ͸௚઀Ҿ਺Ͱ౉ͣ͞BackendWrapperͰ͘ΔΉ
    pub struct BackendWrapper(pub Box);
    pub extern "C" fn specinfra_new<'a>(ptr: *const BackendWrapper)
    -> *const Specinfra<'a> {
    let b = unsafe { &*ptr };
    let s = Specinfra::new(&*b.0);
    Box::into_raw(Box::new(s))
    }
    ෱ԬRubyձٞ02 58

    View Slide

  59. DirectΦϒδΣΫτͷ֎෦༻ఆٛ(Rust)
    pub extern "C" fn direct_new() -> *const Direct {
    let d = Direct::new();
    Box::into_raw(Box::new(d))
    }
    ΛҎԼͷΑ͏ʹ͢Δ
    pub extern "C" fn direct_new() -> *const BackendWrapper {
    let d = Direct::new();
    let b = BackendWrapper(Box::new(d));
    Box::into_raw(Box::new(b))
    }
    ෱ԬRubyձٞ02 59

    View Slide

  60. τϨΠτΛѻ͏ίʔυ(Ruby)
    ͜͏ॻ͖͍ͨ
    b = Direct::Binding.new
    s = Specinfra::Binding.new(b)
    f = s.file("/etc/passwd")
    printf("%#o\n", f.mode)
    ෱ԬRubyձٞ02 60

    View Slide

  61. DirectΦϒδΣΫτͷఆٛ(Ruby)
    class Direct < FFI::AutoPointer
    def self.release(ptr)
    Binding.free(ptr)
    end
    module Binding
    attach_function :free, :direct_free, [Direct], :void
    attach_function :new, :direct_new, [], Direct
    end
    end
    ෱ԬRubyձٞ02 61

    View Slide

  62. SpecinfraΦϒδΣΫτͷमਖ਼(Ruby)
    class Specinfra < FFI::AutoPointer
    ...
    module Binding
    ...
    attach_function :new, :specinfra_new, [:pointer], Specinfra
    ...
    end
    end
    ෱ԬRubyձٞ02 62

    View Slide

  63. τϨΠτΛѻ͏ίʔυ(mruby)
    ͜͏ॻ͖͍ͨ
    b = Direct.new
    s = Specinfra.new(b)
    f = s.file("/etc/passwd")
    printf("%#o\n", f.mode)
    ෱ԬRubyձٞ02 63

    View Slide

  64. τϨΠτؔ࿈ఆٛ(mrbgem)
    typedef int backend;
    extern specinfra *specinfra_new(backend *);
    extern backend *direct_new(void);
    struct mrb_data_type mrb_direct_type = { "Direct", mrb_free };
    ෱ԬRubyձٞ02 64

    View Slide

  65. Direct.new(mrbgem)
    mrb_value direct_new_(mrb_state *mrb, mrb_value self)
    {
    backend *b;
    b = direct_new();
    DATA_TYPE(self) = &mrb_direct_type;
    DATA_PTR(self) = b;
    return self;
    }
    ෱ԬRubyձٞ02 65

    View Slide

  66. Specinfra.newͷमਖ਼(mrbgem)
    mrb_value specinfra_new_(mrb_state *mrb, mrb_value self)
    {
    mrb_value b;
    mrb_get_args(mrb, "o", &b);
    specinfra *s = specinfra_new(DATA_PTR(b));
    DATA_TYPE(self) = &mrb_specinfra_type;
    DATA_PTR(self) = s;
    return self;
    }
    ෱ԬRubyձٞ02 66

    View Slide

  67. ॳظԽ(mrbgem)
    void mrb_mruby_trait_gem_init(mrb_state *mrb)
    {
    ...
    s = mrb_define_class(mrb, "Specinfra", mrb->object_class);
    mrb_define_method(mrb, s, "initialize", new, MRB_ARGS_REQ(1));
    ...
    struct RClass *d
    = mrb_define_class(mrb, "Direct", mrb->object_class);
    mrb_define_method(mrb, d, "initialize", direct_new_, MRB_ARGS_NONE());
    }
    ෱ԬRubyձٞ02 67

    View Slide

  68. Τϥʔ
    ෱ԬRubyձٞ02 68

    View Slide

  69. Τϥʔॲཧ
    • RustଆͰൃੜͨ͠ΤϥʔΛ֎෦ݴޠʹͲ͏఻͑Δͷ͔ɺΛࣗ
    ෼ͳΓʹߟ͑ͯΈͨ
    • ΋ͬͱ͍͍ํ๏͋Ε͹ڭ͍͑ͯͩ͘͞
    ෱ԬRubyձٞ02 69

    View Slide

  70. ΤϥʔΛൃੜͤ͞Δίʔυ(Rust)
    ύʔϛογϣϯऔಘ࣌ʹΤϥʔ͕ൃੜ͢Δ͜ͱΛ૝ఆ
    pub struct File<'a> {
    name: &'a str,
    error: &'a str,
    }
    impl<'a> File<'a> {
    pub fn mode(self) -> Result {
    // ύʔϛογϣϯΛऔಘͯ͠ฦ͢ॲཧΛೖΕΔ
    }
    }
    ෱ԬRubyձٞ02 70

    View Slide

  71. ύʔϛογϣϯऔಘؔ਺ͷ֎෦ఆٛΛमਖ਼(Rust)
    pub extern "C" fn file_mode(ptr: *mut File) -> int32_t {
    let f = unsafe { &mut *ptr };
    match f.mode() {
    Ok(mode) => mode,
    Err(e) => {
    f.error = e;
    -1
    }
    }
    }
    ෱ԬRubyձٞ02 71

    View Slide

  72. ΤϥʔϝοηʔδऔಘͷͨΊͷ֎෦༻ؔ਺ఆٛ(Rust)
    pub extern "C" fn file_error(ptr: *const File)
    -> *const c_char {
    let f = unsafe { &*ptr };
    CString::new(f.error).unwrap().into_raw()
    }
    ෱ԬRubyձٞ02 72

    View Slide

  73. Τϥʔॲཧ(Ruby)
    ͜͏ॲཧ͍ͨ͠
    b = Direct::Binding.new
    s = Specinfra::Binding.new(b)
    f = s.file("/etc/passwd")
    begin
    printf("%#o\n", f.mode)
    rescue => e
    puts e.message
    end
    ෱ԬRubyձٞ02 73

    View Slide

  74. File#modeΛमਖ਼(Ruby)
    class File < FFI::AutoPointer
    ...
    def mode()
    mode = file_mode(self)
    if mode == -1
    raise file_error(self)
    end
    mode
    end
    ...
    attach_function :file_error, [File], :string
    end
    ෱ԬRubyձٞ02 74

    View Slide

  75. Τϥʔॲཧ(mruby)
    ͜͏ॲཧ͍ͨ͠
    b = Direct.new
    s = Specinfra.new(b)
    f = s.file("/etc/passwd")
    begin
    printf("%#o\n", f.mode)
    rescue => e
    puts e.message
    end
    ෱ԬRubyձٞ02 75

    View Slide

  76. File#modeͷमਖ਼(mrbgem)
    mrb_value mode(mrb_state *mrb, mrb_value self)
    {
    file *f = DATA_PTR(self);
    int m = file_mode(f);
    if (m < 0) {
    mrb_raise(mrb, E_RUNTIME_ERROR, file_error(f));
    } else {
    return mrb_fixnum_value(m);
    }
    }
    ෱ԬRubyձٞ02 76

    View Slide

  77. ࣮ફRust + Ruby/mruby·ͱΊ
    • ΦϒδΣΫτɺτϨΠτɺΤϥʔΛѻ͏ํ๏ʹ͍ͭͯղઆ͠
    ͨ
    • ͜ͷลΓ͋·Γ৘ใ͕ͳ͘ɺࢼߦࡨޡͯ͠ḷΓண͍ͨ΍Γํ
    ͳͷͰɺؒҧ͍͕͋ͬͨΓɺ΋ͬͱ͍͍΍Γํ͕͋Δ͔΋͠
    Ε·ͤΜ
    ෱ԬRubyձٞ02 77

    View Slide

  78. libspcinfraͱ͸
    ෱ԬRubyձٞ02 78

    View Slide

  79. libspecinfraͱ͸
    • SpecinfraͷRustʹΑΔ࠶࣮૷ϓϩδΣΫτ
    ෱ԬRubyձٞ02 79

    View Slide

  80. Specinfraͱ͸
    • Serverspec͔Β೿ੜͨ͠ϥΠϒϥϦ
    • OS/σΟετϦϏϡʔγϣϯຖͷίϚϯυͷҧ͍ͷந৅Խ
    • ௚઀ɺSSHܦ༝ɺDocker APIܦ༝ͳͲ࣮ߦܗࣜͷந৅Խ
    • ͜ΕΒͷந৅ԽʹΑͬͯγεςϜ؅ཧܥπʔϧͷ։ൃΛࢧԉ
    ෱ԬRubyձٞ02 80

    View Slide

  81. SpecinfraΛ༻͍ͨϓϩμΫτͷίʔυྫ
    ServerspecʹΑΔςετίʔυ
    set :backend, :exec
    describe package('nginx') do
    it { should be_installed }
    end
    describe service('nginx') do
    it { should be_enabled }
    it { should be_running }
    end
    ෱ԬRubyձٞ02 81

    View Slide

  82. Specinfra͔Βlibspecinfra΁
    • Specinfra͸rubygemͳͷͰଞͷݴޠ͔Β͸࢖͑ͳ͍
    • libpseicnra͸ҎԼͷܗͰଟݴޠରԠΛ໨ࢦ͢
    • ڞ༗ϥΠϒϥϦΛఏڙ
    • ֤छݴޠόΠϯσΟϯά΋ఏڙ
    ෱ԬRubyձٞ02 82

    View Slide

  83. libspecinfraࢀߟࢿྉ
    • libspecinfra ϓϩδΣΫτͷ֓ཁͱࠓޙʹ͍ͭͯ | Advanced
    Technology Lab
    • http://atl.recruit-tech.co.jp/blog/4339/
    • libspecinfra ։ൃऀ޲͚νϡʔτϦΞϧ | Advanced Technology Lab
    • http://atl.recruit-tech.co.jp/blog/4349/
    • libspecinfraͷ֓ཁͱݱঢ়ͱࠓޙ
    • https://speakerdeck.com/mizzy/overview-of-libspecinfra-project
    ෱ԬRubyձٞ02 83

    View Slide

  84. ͳͥRust?
    • ڞ༗ϥΠϒϥϦΛఏڙͱ͍͏໨తͳΒC΍C++͕͋Δ
    • Ͱ΋৽نͰϓϩδΣΫτ͸͡ΊΔͳΒRust͔ͳɺͱ
    • Cݴޠͱͷ਌࿨ੑʢ㲈ଞݴޠͱͷ਌࿨ੑʣ
    • mruby΍libffi౳ͱܨ͗΍͍͢
    • RustΛ֮͑ͯΈ͔ͨͬͨ
    ෱ԬRubyձٞ02 84

    View Slide

  85. ଞݴޠ࿈ܞΛߟྀͨ͠Rust੡ڞ༗ϥΠϒϥϦͷ։ൃํ਑
    1. ॳظஈ֊Ͱ͸ଞݴޠ࿈ܞ͸Ұ੾ߟྀͤͣɺRust୯ମͰ࢖͏ϥΠϒϥϦͱͯ͠࢖͍
    ΍͍͢ίʔυʹ͢Δ
    2. 1ͷϑΣʔζͰॻ͍ͨίʔυΛ֎෦͔Βݺͼग़ͨ͢Ίͷϥούʔؔ਺Λॻ͘
    • ͜ͷ࣌ɺ1ͷϑΣʔζͰॻ͍ͨίʔυ͸جຊతʹ৮Βͳ͍
    • ϥούʔؔ਺Ͱ͸ɺϓϦϛςΟϒͳ஋ͱϙΠϯλ͚ͩΛѻ͏
    3. ݴޠόΠϯσΟϯάΛॻ͘
    • RustͰexportͯ͠Δؔ਺ͦͷ··ͩͱ֤ݴޠͷ׳शʹ߹Θͳ͍ͷͰɺ׳शͱ
    ͷࠩҧΛόΠϯσΟϯάͰٵऩ͠࢖͍΍͘͢͢Δ
    ෱ԬRubyձٞ02 85

    View Slide

  86. ࢀߟࢿྉ
    • The Rust FFI Omnibus
    • http://jakegoulding.com/rust-ffi-omnibus/
    ෱ԬRubyձٞ02 86

    View Slide

  87. ͓ΘΓʹ
    • ۦ͚଍Ͱઆ໌ͨ͠ͷͰΘ͔Γʹ͍͘ͱ͜Ζ͕ଟʑ͋ͬͨͱࢥ͍·͢
    • ڵຯΛ࣋ͬͨํ͸αϯϓϧίʔυΛಈ͔͠ͳ͕Βࢼͯ͠Έͯͩ͘͞
    ͍
    • αϯϓϧίʔυ͸ͪ͜Β https://github.com/mizzy/
    fukuokark02_code_examples
    • ಈ͔ͳ͍ɺΘ͔Γʹ͍͘ͳͲԿ͔͋Γ·ͨ͠ΒɺGitHub Issues΍
    gosukenator@twitter·Ͱ͓஌Β͍ͤͩ͘͞
    ෱ԬRubyձٞ02 87

    View Slide