Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

RustͱFFI ෱ԬRubyձٞ02 7

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

ଞݴޠͰॻ͔ΕͨϥΠϒϥϦؔ਺ΛݺͿ #[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

Slide 11

Slide 11 text

ଞݴޠ͔Βؔ਺Λݺ΂ΔΑ͏ʹ͢Δ #[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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

੔਺ ෱ԬRubyձٞ02 17

Slide 18

Slide 18 text

੔਺ͷ଍͠ࢉΛߦ͏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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

จࣈྻ ෱ԬRubyձٞ02 22

Slide 23

Slide 23 text

จࣈྻʹ!!!Λ෇Ճ͢Δ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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

ߏ଄ମ ෱ԬRubyձٞ02 27

Slide 28

Slide 28 text

ߏ଄ମ • ͜Ε͸লུ • ҰԠॻ͖͔͚ͷίʔυ͸αϯϓϧϦϙδτϦʹ͋Γ·͢ • ҎԼͷهࣄ͕ࢀߟʹͳΓ·͢ • 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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

ΦϒδΣΫτ։์༻ͷؔ਺(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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

ॳظԽ(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

Slide 52

Slide 52 text

τϨΠτ ෱ԬRubyձٞ02 52

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

τϨΠτؔ࿈ఆٛ(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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

ॳظԽ(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

Slide 68

Slide 68 text

Τϥʔ ෱ԬRubyձٞ02 68

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

ύʔϛογϣϯऔಘؔ਺ͷ֎෦ఆٛΛमਖ਼(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

Slide 72

Slide 72 text

ΤϥʔϝοηʔδऔಘͷͨΊͷ֎෦༻ؔ਺ఆٛ(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

Slide 73

Slide 73 text

Τϥʔॲཧ(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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

Τϥʔॲཧ(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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

libspcinfraͱ͸ ෱ԬRubyձٞ02 78

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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