Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Rust + Ruby/mruby
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Gosuke Miyashita
November 25, 2017
Technology
1.8k
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
71
36k
Serverspec(をつくった自分)のそれまでとその後
mizzy
9
3.3k
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
310
Past and future of Infrastructure as Code
mizzy
0
370
Configuration Managementツールのポリシー定義用中間言語に関する考察/Considerations about an intermediate language of configuration management tools
mizzy
0
520
Infrastructure as Codeのこれまでとこれから/Infra Study Meetup #1
mizzy
28
13k
エンジニアかつ研究者としての今後のキャリアについて/My Career As An Engineer And A Researcher
mizzy
0
460
Compare OCI Runtimes
mizzy
2
1.7k
Serverspec and OSS at IEICE Society Conference 2018
mizzy
2
370
Other Decks in Technology
See All in Technology
Microsoft Build Keynoteふりかえり
tomokusaba
0
120
How Timee Delivers Day 1 Production Ready LLM Features
tomoyks
0
130
なぜ Platform Engineering の土台に Kubernetes を選ぶのか
r4ynode
2
590
ルールやカスタム機能、どう活かす?ハンズオンで体感するIBM Bobの出力コントロール
muehara
1
130
フロンティアAIのゲート化と地政学リスク
nagatsu
0
120
小さく始める AI 活用推進 ― 日経電子版 Web チームの事例/nikkei-tech-talk47
nikkei_engineer_recruiting
0
220
LLMにもCAP定理があるという話
harukasakihara
0
290
RAG を使わないという選択肢
tatsutaka
1
190
Oracle AI Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
6
1.9k
AIっぽい文章を採点して人間らしく直すアプリを作ってみた
yama3133
2
130
Snowflakeと仲良くなる第一歩
coco_se
4
430
NAB Show 2026 動画技術関連レポート / NAB Show 2026 Report
cyberagentdevelopers
PRO
0
170
Featured
See All Featured
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
140
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
250
Paper Plane
katiecoart
PRO
1
51k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
140
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
390
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
270
30 Presentation Tips
portentint
PRO
1
320
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
190
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Ethics towards AI in product and experience design
skipperchong
2
310
Balancing Empowerment & Direction
lara
6
1.2k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
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