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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
72
38k
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
320
Past and future of Infrastructure as Code
mizzy
0
390
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
AgentCore Runtime上にAgentic Coding基盤を構築・展開する際の設計ポイントと限界点 / Design considerations and limitations when building an agentic coding platform on AgentCore Runtime
har1101
2
130
データ_AIの事業の勝敗をわけるもの
nek0128
0
380
絵ではじめるKubernetesセキュリティ
aoi1
3
600
CLIライブラリ開発を支える技術
htnabe
0
120
人間はどの意思決定を手放せるのか
kawasima
14
7k
The Agent Builder Loop from Daily Work to OSS
minorun365
PRO
3
200
Snowflakeのコスト最適化を支えるアーキテクチャ設計
ktatsuya
1
1.6k
Reactの設計論
uhyo
24
13k
OpenTelemetryのメトリクスをCloudWatchに送ってPromQLで見てみた
ota1022
0
150
AIに任せた品質は、誰が見立てるのか - AI時代のテストマネジメント
nakanao
2
1k
LTのテーマ どうきめてる?〜5つの型と私のやり方〜
yama3133
1
110
え、こんなに早く改修できるの?──新人エンジニアとスクラムマスターの2人が語る、AI×アジャイル開発の現場
ysasago
0
130
Featured
See All Featured
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
690
Speed Design
sergeychernyshev
33
2.1k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
330
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Optimizing for Happiness
mojombo
378
71k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
Embracing the Ebb and Flow
colly
88
5.2k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
540
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
300
Practical Orchestrator
shlominoach
192
12k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
280
The agentic SEO stack - context over prompts
schlessera
0
940
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