Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rust with Ruby

Rust with Ruby

Lightening talk about bridging Rust and Ruby with FFI. http://rusttrace.herokuapp.com/report

Zac Stewart

July 09, 2015
Tweet

More Decks by Zac Stewart

Other Decks in Technology

Transcript

  1. fn main() { let mut x = vec!["Hello", "world"]; let

    y = &x[0]; x.push("foo"); } error: cannot borrow `x` as mutable because it is also borrowed as immutable x.push("foo"); ^ note: previous borrow of `x` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `x` until the borrow ends let y = &x[0]; ^ note: previous borrow ends here fn main() { } ^
  2. irb(main):001:0> a = %w( no you're stupid ) # =>

    ["no", "you're", "stupid"] irb(main):002:0> x = a[0] # => "no" irb(main):003:0> x.upcase! # => "NO" irb(main):004:0> a # => ["NO", "you're", "stupid"]
  3. impl Usage { fn new() -> Usage { Usage {

    calls: HashMap::new(), total: 0 } } fn record(&mut self, method_name: String) { *self.calls.entry(method_name).or_insert(0) += 1; self.total += 1; } }
  4. @calls = Hash.new(0) @totals = 0 def record(event, file, line,

    id, classname) if %w( call c-call ).include?(event) @calls["#{classname}##{id}"] += 1 @totals += 1 end end set_trace_func proc { |event, file, line, id, binding, classname| record(event, file, line, id, classname) }
  5. pub struct Usage { calls: HashMap<String, u32>, total: u32 }

    impl Usage { fn new() -> Usage { Usage { calls: HashMap::new(), total: 0 } } fn record(&mut self, method_name: String) { *self.calls.entry(method_name).or_insert(0) += 1; self.total += 1; } }
  6. pub fn record(usage: &mut Usage, event: &str, file: &str, line:

    u32, id: &str, class_name: &str) { if event == "call" || event == "c-call" { usage.record(class_name.to_string() + "#" + method_name) } }
  7. #[no_mangle] pub extern "C" fn record(usage: &mut Usage, event: *const

    c_char, file: *const c_char, line: u32, id: *const c_char, class_name: *const c_char) { let event = unsafe { CStr::from_ptr(event) }; let event = str::from_utf8(event.to_bytes()).unwrap(); if event == "call" || event == "c-call" { let method_name = unsafe { CStr::from_ptr(id) }; let method_name = str::from_utf8(method_name.to_bytes()).unwrap(); let class_name = unsafe { CStr::from_ptr(class_name) }; let class_name = str::from_utf8(class_name.to_bytes()).unwrap(); usage.record(class_name.to_string() + "#" + method_name) } }
  8. module Rust extend FFI::Library ffi_lib 'target/release/librusttrace.dylib' attach_function :new_usage, [], :pointer

    attach_function :record, [:pointer, :string, :string, :int, :string, :string], :void end
  9. @usage = Rust.new_usage set_trace_func proc { |event, file, line, id,

    binding, classname| Rust.record(@usage, event, file, line, id.to_s, classname.to_s) }
  10. pub struct CallCount { count: u32, method_name: String } impl

    CallCount { fn new(method: &str, count: &u32) -> CallCount { CallCount { method_name: method.to_string(), count: *count } } } fn report(usage: &Usage) -> Vec<CallCount> { let mut counts: Vec<CallCount> = usage.calls .iter() .map(|(method, count)| CallCount::new(method, count) ) .collect(); counts.sort_by(|a, b| a.count.cmp(&b.count).reverse()); counts }
  11. #[repr(C)] pub struct CallCount { count: u32, method_name: *const c_char

    } impl CallCount { fn new(method: &str, count: &u32) -> CallCount { let method_name = self.method_name.clone(); let method_name = CString::new(method_name).unwrap(); CallCount { method_name: method.into_ptr(), count: *count } } } fn report(usage: &Usage) -> Vec<CallCount> { let mut counts: Vec<CallCount> = usage.calls .iter() .map(|(method, count)| CallCount::new(method, count) ) .collect(); counts.sort_by(|a, b| a.count.cmp(&b.count).reverse()); counts }
  12. pub struct Report { length: usize, call_counts: *const CallCount }

    fn report(usage: &Usage) -> Report { let mut counts: Vec<CallCount> = usage.calls .iter() .map(|(method, count)| CallCount::new(method, count) ) .collect(); counts.sort_by(|a, b| a.count.cmp(&b.count).reverse()); Report { length: counts.len(), call_counts: counts.as_ptr() } }
  13. class CallCount < FFI::Struct layout :count, :uint, :method_name, :string def

    method_name self[:method_name] end def count self[:count] end end class Report < FFI::Struct include Enumerable layout :length, :uint, :call_counts, :pointer def each self[:length].times do |i| yield CallCount.new(self[:call_counts] + (i * CallCount.size)) end end end
  14. module Rust extend FFI::Library ffi_lib 'target/release/librusttrace.dylib' attach_function :new_usage, [], :pointer

    attach_function :record, [:pointer, :string, :string, :int, :string, :string], :void attach_function :report, [:pointer], Report.by_value end
  15. module Rusttrace class Usage module Rust extend FFI::Library ffi_lib 'target/release/librusttrace.dylib'

    attach_function :new_usage, [], :pointer attach_function :record, [:pointer, :string, :string, :int, :string, :string], :void attach_function :report, [:pointer], Report.by_value end def initialize @usage = Rust.new_usage end def attach set_trace_func proc { |event, file, line, id, binding, classname| Rust.record(@usage, event, file, line, id.to_s, classname.to_s) } end def report Rust.report(@usage) end end end