ruby_sys/
string.rs

1use libc::size_t;
2use std::mem;
3
4use constant::{FL_USHIFT, FL_USER_1, FL_USER_2, FL_USER_3, FL_USER_4, FL_USER_5, FL_USER_6};
5use types::{c_char, c_long, InternalValue, RBasic, Value};
6
7extern "C" {
8    pub fn rb_str_new(str: *const c_char, len: c_long) -> Value;
9    pub fn rb_str_new_cstr(str: *const c_char) -> Value;
10    pub fn rb_utf8_str_new(str: *const c_char, len: c_long) -> Value;
11    pub fn rb_string_value_cstr(str: *const Value) -> *const c_char;
12    pub fn rb_string_value_ptr(str: *const Value) -> *const c_char;
13}
14
15#[repr(C)]
16enum RStringEmbed {
17    NoEmbed = FL_USER_1,
18    LenMask = FL_USER_2 | FL_USER_3 | FL_USER_4 | FL_USER_5 | FL_USER_6,
19    LenShift = FL_USHIFT + 2,
20}
21
22#[repr(C)]
23struct RStringAs {
24    heap: RStringHeap,
25}
26
27#[repr(C)]
28struct RStringHeap {
29    len: c_long,
30    // Really, this is a union but value is the largest item.
31    value: InternalValue,
32    ptr: InternalValue,
33}
34
35#[repr(C)]
36struct RString {
37    basic: RBasic,
38    as_: RStringAs,
39}
40
41pub unsafe fn rb_str_len(value: Value) -> c_long {
42    let rstring: *const RString = mem::transmute(value.value);
43    let flags = (*rstring).basic.flags;
44
45    if flags & (RStringEmbed::NoEmbed as size_t) == 0 {
46        ((flags as i64 >> RStringEmbed::LenShift as i64) &
47         (RStringEmbed::LenMask as i64 >> RStringEmbed::LenShift as i64)) as c_long
48    } else {
49        (*rstring).as_.heap.len
50    }
51}