Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Rust + Ruby/mruby
Search
Gosuke Miyashita
November 25, 2017
Technology
1.9k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Rust + Ruby/mruby
Gosuke Miyashita
November 25, 2017
More Decks by Gosuke Miyashita
See All by Gosuke Miyashita
なぜインフラコードのモジュール化は難しいのか - アプリケーションコードとの本質的な違いから考える
mizzy
76
40k
Serverspec(をつくった自分)のそれまでとその後
mizzy
9
3.4k
A method for separating policy definition and behavior control by an intermediate language to achieve optimal server configuration management according to the situation
mizzy
3
330
Past and future of Infrastructure as Code
mizzy
0
400
Configuration Managementツールのポリシー定義用中間言語に関する考察/Considerations about an intermediate language of configuration management tools
mizzy
0
540
Infrastructure as Codeのこれまでとこれから/Infra Study Meetup #1
mizzy
28
13k
エンジニアかつ研究者としての今後のキャリアについて/My Career As An Engineer And A Researcher
mizzy
0
470
Compare OCI Runtimes
mizzy
2
1.7k
Serverspec and OSS at IEICE Society Conference 2018
mizzy
2
400
Other Decks in Technology
See All in Technology
並行性の問題を防げ!実践トランザクション入門
occhi
0
280
[2026 Oracle Technical Deep Dive] オンプレミスDBのCloud移行アプローチ:移行計画に基づくメソッドとツールの選択 (2026年9月17日開催)
oracle4engineer
PRO
0
150
[2026 Oracle Technical Deep Dive] エンタープライズAIエージェントを支えるOCIソリューション。ラインナップと特徴を理解しよう! (2026年9月17日開催)
oracle4engineer
PRO
0
540
Incremental HTTP
kazuho
5
2.1k
雪かき部 #7 もう怖くない!SELECT文!
foursue
0
280
スキルを作る、その前に!複数人で使われるスキルを 作るためのプロセス
junkifurukawa
2
330
「とりあえず動く」の先へ。 AI時代のチーム開発と内部設計/2026-slsdays
slsops
0
150
Kernel testing frameworks
ennael
PRO
0
110
BedrockとLambdaで作る リアルタイム進行型推理ゲーム
kawametho
0
190
メルペイ 会計システム概要と歴史
mewuto
0
160
[AWS 秋のクラウドオペレーション祭り 2026]AWS DevOps Agentで変わるリリースと運用対応 ~リリース管理機能と Directed actions のご紹介~
furuton
3
930
大阪オフィスに Unitree Go2 がやってきたので Physical AI やってみた
dafujii
0
320
Featured
See All Featured
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
66k
Unsuck your backbone
ammeep
672
58k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
Darren the Foodie - Storyboard
khoart
PRO
4
4k
Paper Plane (Part 1)
katiecoart
PRO
2
11k
WCS-LA-2024
lcolladotor
0
840
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
420
Discover your Explorer Soul
emna__ayadi
2
1.3k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
770
Transcript
RustͰॻ͍ͨϥΠϒϥϦ ΛRuby/mruby͔Βݺ ͼग़࣮͢ફతͳํ๏ ԬRubyձٞ02 1
ࣗݾհ • ٶԼ ߶ี • ߹ಉձࣾServerspec Operationsද • ϑϦʔϥϯεͷιϑτΣΞΤϯδχΞ •
http://mizzy.org/ • mizzy@github, gosukenator@twitter ԬRubyձٞ02 2
ஶॻɾ༁ॻ ԬRubyձٞ02 3
ࠓͷൃදʹࢸΔܦҢ • libspecinfraͱ͍͏OSSϓϩδΣΫτΛ͍ͬͯΔ • ͜ͷϓϩδΣΫτҎԼͷߏཁૉΛ࣋ͭ • RustͰ࣮ͨ͠ڞ༗ϥΠϒϥϦ • ڞ༗ϥΠϒϥϦΛར༻͢ΔͨΊͷ֤छݴޠόΠϯσΟϯά ԬRubyձٞ02
4
ࠓͷൃදʹࢸΔܦҢʢ͖ͭͮʣ • Ruby/mrubyόΠϯσΟϯάΛ։ൃ͢ΔͨΊͷํ๏Λௐͨ • ॳาతͳใͨ͘͞Μ͋Δ͕࣮ફతͳใҊ֎গͳ͍ • ৭ʑࢼߦࡨޡͨ͠ͷͰ·ͱΊ͓ͯ͜͏ͱࢥͬͨ • ؒҧ͍ΑΓྑ͍Γํ͕͋Εࣝऀ͕ࢦఠͯ͘͠Εͦ͏ •
ٱʑʹԬʹߦ͘ޱ࣮͕ཉ͔ͬͨ͠ ԬRubyձٞ02 5
ΞδΣϯμ • RustͱFFI • ೖRust + Ruby/mruby • ࣮ફRust +
Ruby/mruby • libspecinfraϓϩδΣΫτͷ֓ཁʢ͕࣌ؒ͋Εʣ • ※Rustͷݴޠ༷తͳ͠·ͤΜ ԬRubyձٞ02 6
RustͱFFI ԬRubyձٞ02 7
FFIͱ • Foreign Function Interface • ͋Δϓϩάϥϛϯάݴޠ͔ΒଞͷϓϩάϥϛϯάݴޠͰఆٛ ͞ΕͨؔͳͲΛར༻͢ΔͨΊͷػߏ • RustɺRubyɺmrubyʹݶΒͳ͍
ԬRubyձٞ02 8
RustͱFFI • RustʹFFI͕Έࠐ·Ε͓ͯΓެࣜυΩϡϝϯτ͋Δ • ओͳػೳେ͖͘2ͭ • ଞݴޠͰॻ͔ΕͨϥΠϒϥϦͷؔΛݺͿػೳ • ଞݴޠʢओʹCʣ͔ΒؔΛݺΔΑ͏ʹ͢Δػೳ ԬRubyձٞ02
9
ଞݴޠͰॻ͔ΕͨϥΠϒϥϦؔΛݺͿ #[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
ଞݴޠ͔ΒؔΛݺΔΑ͏ʹ͢Δ #[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
hello_rust()ΛC͔Βݺͼग़͢ #include <stdio.h> 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
RustͱFFI·ͱΊ • FFI = Foreign Function Interface • ͋Δϓϩάϥϛϯάݴޠ͔ΒଞͷϓϩάϥϛϯάݴޠͰఆٛ ͞ΕͨؔͳͲΛར༻͢ΔͨΊͷػߏ
• RustʹFFI͕Έࠐ·Ε͍ͯͯɺଞͷݴޠͰॻ͔ΕͨϥΠϒ ϥϦͷؔΛݺͼग़ͨ͠Γɺଞͷݴޠ͔ΒRustͰॻ͍ͨϥΠ ϒϥϦͷؔΛݺͼग़ͨ͠ΓͰ͖Δ ԬRubyձٞ02 13
ೖRust + Ruby/mruby ԬRubyձٞ02 14
RustͰॻ͔ΕͨϥΠϒϥϦΛͲ͏ݺͿ͔ • Ruby • native extension • ffi gemΛར༻ͯ͠libffiܦ༝Ͱݺͼग़͢ •
mruby • CͰ֦ு(mrbgem)Λॻ͘ ԬRubyձٞ02 15
ೖRust + Ruby/mruby • RustͱRuby/mrubyΛͲ͏ܨ͙͔۩ମతͳίʔυͰࣔ͠·͢ • ͕ࣗlibspecinfraͷόΠϯσΟϯά։ൃͷͨΊʹֶΜͩͷͱಉ͡εςοϓΛḷ ͬͯΈ·͢ • จࣈΛେ͖ͯ͘͠εϥΠυΛݟ͘͢͢ΔͨΊίʔυΛলུͨ͠Γਪ͞Εͳ
͍ॻ͖ํΛͯ͠Δ෦͋Γ·͢ • શͳίʔυGitHubʹஔ͍ͯ͋Γ·͢ • https://github.com/mizzy/fukuokark02_code_examples • εϥΠυͱඍົʹҧ͏෦͋Γ·͕͢ ԬRubyձٞ02 16
ԬRubyձٞ02 17
ͷ͠ࢉΛߦ͏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
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
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
mrbgemΛར༻ͨ͠mrubyίʔυ puts Integers.addition(1, 2) ԬRubyձٞ02 21
จࣈྻ ԬRubyձٞ02 22
จࣈྻʹ!!!ΛՃ͢Δ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
RustͷؔΛݺͼग़͢Rubyίʔυ module Strings extend FFI::Library ffi_lib 'emphasize' attach_function :emphasize, [:string],
:string end puts Strings.emphasize("Hello") ԬRubyձٞ02 24
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
mrbgemΛར༻ͨ͠mrubyίʔυ puts Strings.emphasize("Hello") ԬRubyձٞ02 26
ߏମ ԬRubyձٞ02 27
ߏମ • ͜Εলུ • ҰԠॻ͖͔͚ͷίʔυαϯϓϧϦϙδτϦʹ͋Γ·͢ • ҎԼͷهࣄ͕ࢀߟʹͳΓ·͢ • 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
ߏମ • ׂͱ໘͍͘͞ • RustଆͱRuby/mrubyͰಉ͡ߏମΛఆٛ͢Δඞཁ͕͋Δ • ߏମͷதRuby/mruby͔ΒݟΕͲ͏Ͱ͍͍ʢ͕ࣗ։ൃ͠ ͯΔlibspecinfraͰʣ • ΦϒδΣΫτͱͯ͠ѻ͍͍ͨ
• RustଆͷstructΛࣔ͢ϙΠϯλͱͦΕΛѻ͏͚ؔͩ͋ΕेͰ ʁ ԬRubyձٞ02 29
ೖRust + Ruby/mruby·ͱΊ • ҾͱฦΓɺจࣈྻҾͱฦΓΛѻ͏ίʔυྫΛࣔͨ͠ • ߏମʹ͍ͭͯɺlibspecinfra։ൃͷͨΊʹௐͯΔ్தͰɺ ͜ΕࣗͷΓ͍ͨ͜ͱͱҧ͏ɺͱࢥͬͨͷͰུ • ߏମ(Rustͷstruct)Λߏମͱͯ͠ѻ͍͍ͨͷͰͳ͘ɺΦϒδ
ΣΫτͱͯ͠ѻ͍͍ͨ • ͦͷΓํ࣍Ͱղઆ͠·͢ ԬRubyձٞ02 30
࣮ફRust + Ruby/mruby ԬRubyձٞ02 31
࣮ફRust + Ruby/mruby • ͔͜͜Β࣮ࡍͷlibspecinfraͷίʔυΛϕʔεͱͨ͠ղઆΛ ͠·͢ • શʹಉ͡ίʔυͰͳ͘؆ུԽͯ͋͠Γ·͢ • ͪ͜ΒͷίʔυGitHubʹ͋Γ·͢
• https://github.com/mizzy/fukuokark02_code_examples ԬRubyձٞ02 32
ΦϒδΣΫτ ԬRubyձٞ02 33
ΦϒδΣΫτΛѻ͏ίʔυ(Rust) ͜Μͳײ͡ͰϑΝΠϧͷύʔϛογϣϯΛऔಘ͍ͨ͠ let s = Specinfra::new(); let f = s.file("/etc/passwd");
println!("{:o}", f.mode()); ԬRubyձٞ02 34
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
FileΦϒδΣΫτͷఆٛ(Rust) pub struct File<'a> { name: &'a str, } impl<'a>
File<'a> { pub fn mode(self) -> i32 { // ύʔϛογϣϯΛऔಘͯ͠ฦ͢ॲཧ } } ԬRubyձٞ02 36
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
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
ΦϒδΣΫτ։์༻ͷؔ(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
ΦϒδΣΫτΛѻ͏ίʔυ(Ruby) ͜Μͳײ͡ͰϑΝΠϧͷύʔϛογϣϯऔಘ͍ͨ͠ s = Specinfra::Binding.new f = s.file("/etc/passwd") printf("%#o\n", f.mode)
ԬRubyձٞ02 40
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
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
ΦϒδΣΫτΛѻ͏ίʔυ(mruby) ͜Μͳײ͡ͰϑΝΠϧͷύʔϛογϣϯऔಘ͍ͨ͠ s = Specinfra.new f = s.file("/etc/passwd") printf("%#o\n", f.mode)
ԬRubyձٞ02 43
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
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
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
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
SpecinfraΦϒδΣΫτ։์༻ؔ(mrbgem) void mrb_specinfra_free(mrb_state *mrb, void *ptr) { specinfra_free(ptr); } ԬRubyձٞ02
48
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
FileΦϒδΣΫτ։์༻ؔ(mrbgem) void mrb_file_free(mrb_state *mrb, void *ptr) { file_free(ptr); } ԬRubyձٞ02
50
ॳظԽ(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
τϨΠτ ԬRubyձٞ02 52
τϨΠτΛѻ͏ίʔυ(Rust) ͜Μͳײ͡ͰBackendτϨΠτΛ࣮ͨ͠DirectΦϒδΣΫτΛ ͍ͨ͠ let b = Direct::new(); let s =
Specinfra::new(b); ԬRubyձٞ02 53
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
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
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
ηάϑΥ…(Rust) impl<'a> Specinfra<'a> { pub fn new(b: &Backend) -> Specinfra
{ b.detect_platform(); // ͜͜ͰηάϑΥ͢Δ Specinfra { backend: b } } ԬRubyձٞ02 57
BackendWrapper structͷಋೖ(Rust) τϨΠτҾͰͣ͞BackendWrapperͰ͘ΔΉ pub struct BackendWrapper(pub Box<Backend>); 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
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
τϨΠτΛѻ͏ίʔυ(Ruby) ͜͏ॻ͖͍ͨ b = Direct::Binding.new s = Specinfra::Binding.new(b) f =
s.file("/etc/passwd") printf("%#o\n", f.mode) ԬRubyձٞ02 60
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
SpecinfraΦϒδΣΫτͷमਖ਼(Ruby) class Specinfra < FFI::AutoPointer ... module Binding ... attach_function
:new, :specinfra_new, [:pointer], Specinfra ... end end ԬRubyձٞ02 62
τϨΠτΛѻ͏ίʔυ(mruby) ͜͏ॻ͖͍ͨ b = Direct.new s = Specinfra.new(b) f =
s.file("/etc/passwd") printf("%#o\n", f.mode) ԬRubyձٞ02 63
τϨΠτؔ࿈ఆٛ(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
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
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
ॳظԽ(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
Τϥʔ ԬRubyձٞ02 68
Τϥʔॲཧ • RustଆͰൃੜͨ͠ΤϥʔΛ֎෦ݴޠʹͲ͏͑Δͷ͔ɺΛࣗ ͳΓʹߟ͑ͯΈͨ • ͬͱ͍͍ํ๏͋Εڭ͍͑ͯͩ͘͞ ԬRubyձٞ02 69
ΤϥʔΛൃੜͤ͞Δίʔυ(Rust) ύʔϛογϣϯऔಘ࣌ʹΤϥʔ͕ൃੜ͢Δ͜ͱΛఆ pub struct File<'a> { name: &'a str, error:
&'a str, } impl<'a> File<'a> { pub fn mode(self) -> Result<i32, &'a str> { // ύʔϛογϣϯΛऔಘͯ͠ฦ͢ॲཧΛೖΕΔ } } ԬRubyձٞ02 70
ύʔϛογϣϯऔಘؔͷ֎෦ఆٛΛमਖ਼(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
ΤϥʔϝοηʔδऔಘͷͨΊͷ֎෦༻ؔఆٛ(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
Τϥʔॲཧ(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
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
Τϥʔॲཧ(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
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
࣮ફRust + Ruby/mruby·ͱΊ • ΦϒδΣΫτɺτϨΠτɺΤϥʔΛѻ͏ํ๏ʹ͍ͭͯղઆ͠ ͨ • ͜ͷลΓ͋·Γใ͕ͳ͘ɺࢼߦࡨޡͯ͠ḷΓண͍ͨΓํ ͳͷͰɺؒҧ͍͕͋ͬͨΓɺͬͱ͍͍Γํ͕͋Δ͔͠ Ε·ͤΜ
ԬRubyձٞ02 77
libspcinfraͱ ԬRubyձٞ02 78
libspecinfraͱ • SpecinfraͷRustʹΑΔ࠶࣮ϓϩδΣΫτ ԬRubyձٞ02 79
Specinfraͱ • Serverspec͔Βੜͨ͠ϥΠϒϥϦ • OS/σΟετϦϏϡʔγϣϯຖͷίϚϯυͷҧ͍ͷநԽ • ɺSSHܦ༝ɺDocker APIܦ༝ͳͲ࣮ߦܗࣜͷநԽ • ͜ΕΒͷநԽʹΑͬͯγεςϜཧܥπʔϧͷ։ൃΛࢧԉ
ԬRubyձٞ02 80
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
Specinfra͔Βlibspecinfra • SpecinfrarubygemͳͷͰଞͷݴޠ͔Β͑ͳ͍ • libpseicnraҎԼͷܗͰଟݴޠରԠΛࢦ͢ • ڞ༗ϥΠϒϥϦΛఏڙ • ֤छݴޠόΠϯσΟϯάఏڙ ԬRubyձٞ02
82
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
ͳͥRust? • ڞ༗ϥΠϒϥϦΛఏڙͱ͍͏తͳΒCC++͕͋Δ • Ͱ৽نͰϓϩδΣΫτ͡ΊΔͳΒRust͔ͳɺͱ • Cݴޠͱͷੑʢ㲈ଞݴޠͱͷੑʣ • mrubylibffiͱܨ͍͗͢ •
RustΛ֮͑ͯΈ͔ͨͬͨ ԬRubyձٞ02 84
ଞݴޠ࿈ܞΛߟྀͨ͠Rustڞ༗ϥΠϒϥϦͷ։ൃํ 1. ॳظஈ֊Ͱଞݴޠ࿈ܞҰߟྀͤͣɺRust୯ମͰ͏ϥΠϒϥϦͱ͍ͯ͠ ͍͢ίʔυʹ͢Δ 2. 1ͷϑΣʔζͰॻ͍ͨίʔυΛ֎෦͔Βݺͼग़ͨ͢ΊͷϥούʔؔΛॻ͘ • ͜ͷ࣌ɺ1ͷϑΣʔζͰॻ͍ͨίʔυجຊతʹ৮Βͳ͍ • ϥούʔؔͰɺϓϦϛςΟϒͳͱϙΠϯλ͚ͩΛѻ͏
3. ݴޠόΠϯσΟϯάΛॻ͘ • RustͰexportͯ͠Δؔͦͷ··ͩͱ֤ݴޠͷ׳शʹ߹Θͳ͍ͷͰɺ׳शͱ ͷࠩҧΛόΠϯσΟϯάͰٵऩ͍͘͢͢͠Δ ԬRubyձٞ02 85
ࢀߟࢿྉ • The Rust FFI Omnibus • http://jakegoulding.com/rust-ffi-omnibus/ ԬRubyձٞ02 86
͓ΘΓʹ • ۦ͚Ͱઆ໌ͨ͠ͷͰΘ͔Γʹ͍͘ͱ͜Ζ͕ଟʑ͋ͬͨͱࢥ͍·͢ • ڵຯΛ࣋ͬͨํαϯϓϧίʔυΛಈ͔͠ͳ͕Βࢼͯ͠Έͯͩ͘͞ ͍ • αϯϓϧίʔυͪ͜Β https://github.com/mizzy/ fukuokark02_code_examples
• ಈ͔ͳ͍ɺΘ͔Γʹ͍͘ͳͲԿ͔͋Γ·ͨ͠ΒɺGitHub Issues gosukenator@twitter·Ͱ͓Β͍ͤͩ͘͞ ԬRubyձٞ02 87