-
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
symbol::rb_intern!
macro to memoize symbols (#318)
- Loading branch information
Showing
4 changed files
with
80 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,3 +25,6 @@ mod memory_test; | |
|
||
#[cfg(test)] | ||
mod stable_api_test; | ||
|
||
#[cfg(test)] | ||
mod symbol_test; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use std::slice; | ||
|
||
use rb_sys::{ | ||
rb_funcall, rb_id2sym, rb_intern, rb_utf8_str_new, RSTRING_LEN, RSTRING_PTR, STATIC_SYM_P, | ||
}; | ||
use rb_sys_test_helpers::ruby_test; | ||
|
||
#[ruby_test] | ||
fn test_creates_a_usable_id() { | ||
let method_name = unsafe { rb_intern!("reverse") }; | ||
|
||
let mystring = unsafe { rb_utf8_str_new("jerrbear".as_ptr() as *mut _, 8) }; | ||
let ret = unsafe { rb_funcall(mystring, method_name, 0) }; | ||
let ptr = unsafe { RSTRING_PTR(ret) as *const u8 }; | ||
let len = unsafe { RSTRING_LEN(ret) } as _; | ||
let result = unsafe { slice::from_raw_parts(ptr, len) }; | ||
|
||
assert_eq!(result, b"raebrrej"); | ||
} | ||
|
||
#[ruby_test] | ||
fn test_has_repeatable_results() { | ||
let method_name1 = unsafe { rb_intern!("reverse") }; | ||
let method_name2 = unsafe { rb_intern!("reverse") }; | ||
|
||
assert_ne!(method_name1, 0); | ||
assert_ne!(method_name2, 0); | ||
assert_eq!(method_name1, method_name2); | ||
} | ||
|
||
#[ruby_test] | ||
fn test_non_usascii() { | ||
let method_name1 = unsafe { rb_intern!("🙈") }; | ||
let method_name2 = unsafe { rb_intern!("🙈") }; | ||
|
||
assert_ne!(method_name1, 0); | ||
assert_ne!(method_name2, 0); | ||
assert_eq!(method_name1, method_name2); | ||
|
||
let sym1 = unsafe { rb_id2sym(method_name1) }; | ||
let sym2 = unsafe { rb_id2sym(method_name2) }; | ||
|
||
assert!(STATIC_SYM_P(sym1)); | ||
assert!(STATIC_SYM_P(sym2)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/// Finds or creates a symbol for the given static string. This macro will | ||
/// memoize the ID to avoid repeated calls to libruby. You should prefer this | ||
/// macro over [`rb_intern3`] when the string is known at compile time. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This macro is safe under two conditions: | ||
/// - Ruby VM is initialized and that thus safe to call into libruby | ||
/// - The first call to this macro will be done inside of a managed Ruby thread (i.e. not a native thread) | ||
/// | ||
/// # Example | ||
/// | ||
/// ```no_run | ||
/// use rb_sys::{symbol::rb_intern, rb_funcall, rb_utf8_str_new}; | ||
/// | ||
/// unsafe { | ||
/// let reverse_id = rb_intern!("reverse"); | ||
/// let msg = rb_utf8_str_new("nice one".as_ptr() as *mut _, 4); | ||
/// rb_funcall(msg, reverse_id, 0); | ||
/// } | ||
/// ``` | ||
#[macro_export] | ||
macro_rules! rb_intern { | ||
($s:literal) => {{ | ||
static mut ID: $crate::ID = 0; | ||
if ID == 0 { | ||
ID = $crate::rb_intern3($s.as_ptr() as _, $s.len() as _, $crate::rb_utf8_encoding()); | ||
} | ||
ID | ||
}}; | ||
} |