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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
41k
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
340
Past and future of Infrastructure as Code
mizzy
0
410
Configuration Managementツールのポリシー定義用中間言語に関する考察/Considerations about an intermediate language of configuration management tools
mizzy
0
550
Infrastructure as Codeのこれまでとこれから/Infra Study Meetup #1
mizzy
28
13k
エンジニアかつ研究者としての今後のキャリアについて/My Career As An Engineer And A Researcher
mizzy
0
480
Compare OCI Runtimes
mizzy
2
1.8k
Serverspec and OSS at IEICE Society Conference 2018
mizzy
2
420
Other Decks in Technology
See All in Technology
`go get`したらELFが降ってきた件
taiyow
0
190
お客様の「やりたい」の先を見通す合意形成プロセス ~裏にある課題と不安を解きほぐすコツ~
yukakoseki
0
120
Gifu WordPress Meetup #200 に向けて、私たちには何ができるだろうか?/ 2026-11-07 Gifu WordPress Meetup
torounit
0
230
公共分野での生成AI活用
toru_kubota
1
300
Sinatra on PicoRuby ローカルでセルフホスト
bash0c7
0
110
AWS基盤改善を支える 私たちの理念と行動指針
kentosuzuki
0
120
「AIチャットからもできないの?」と言われたら ~業務アプリをMCP対応するときの認証・認可の勘所
oidfj
0
190
レガシーコードに対する loop engineering的なAI開発プロセス導入について
kubell_hr
0
280
AI時代のエンジニアの情報発信〜個人の発信を組織の力に変える〜
ryo_kawamata
1
7.4k
慶應義塾大学 AI実践05 論文執筆の仕組み化
keio_smilab
PRO
7
3.8k
プロダクションコードにおける encoding/json から encoding/json/v2 へのスムーズな移行
sansantech
PRO
1
190
2026 Apache Flink Community Checkpoint
rmetzger
0
200
Featured
See All Featured
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
930
The Cult of Friendly URLs
andyhume
79
7.1k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7.1k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
760
First, design no harm
axbom
PRO
2
1.4k
How Software Deployment tools have changed in the past 20 years
geshan
3
35k
WCS-LA-2024
lcolladotor
0
980
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
600
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
2
510
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
420
Docker and Python
trallard
47
4.3k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3.1k
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