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 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}