1use std::mem;
2
3use crate::rubysys::{
4 constant::{
5 FL_USER_1, FL_USER_17, FL_USER_2, FL_USER_3, FL_USER_4, FL_USER_5, FL_USER_6, FL_USER_7,
6 FL_USHIFT,
7 },
8 libc::size_t,
9 types::{c_char, c_long, CallbackPtr, EncodingType, InternalValue, RBasic, Value},
10};
11
12pub const STR_TMPLOCK: isize = FL_USER_7;
13
14extern "C" {
15 pub fn rb_str_new(str: *const c_char, len: c_long) -> Value;
18 pub fn rb_str_new_cstr(str: *const c_char) -> Value;
21 pub fn rb_utf8_str_new(str: *const c_char, len: c_long) -> Value;
24 pub fn rb_utf8_str_new_cstr(str: *const c_char) -> Value;
27 pub fn rb_string_value_cstr(str: *const Value) -> *const c_char;
30 pub fn rb_string_value_ptr(str: *const Value) -> *const c_char;
33 pub fn rb_str_strlen(str: Value) -> c_long;
36 pub fn rb_enc_str_asciionly_p(str: Value) -> bool;
39 pub fn rb_enc_str_new(str: *const c_char, len: c_long, enc: EncodingType) -> Value;
42 pub fn rb_str_export_locale(str: Value) -> Value;
45 pub fn rb_str_valid_encoding_p(str: Value) -> bool;
48 pub fn rb_str_cat(str: Value, ptr: *const c_char, len: c_long) -> Value;
51 pub fn rb_check_string_type(str: Value) -> Value;
54 pub fn rb_str_locktmp(str: Value) -> Value;
69 pub fn rb_str_unlocktmp(str: Value) -> Value;
72 pub fn rb_str_new_frozen(orig: Value) -> Value;
75}
76
77#[derive(Debug, PartialEq)]
79#[repr(C)]
80enum RStringEmbed {
81 NoEmbed = FL_USER_1,
82 LenMask = FL_USER_2 | FL_USER_3 | FL_USER_4 | FL_USER_5 | FL_USER_6,
83 LenShift = FL_USHIFT + 2,
84 LenMax = (mem::size_of::<Value>() as isize * 3) / mem::size_of::<c_char>() as isize - 1,
85 Fstr = FL_USER_17,
86}
87
88#[derive(Copy, Clone)]
89#[repr(C)]
90union RStringAs {
91 heap: RStringHeap,
92 ary: [c_char; RStringEmbed::LenMax as usize + 1],
93}
94
95#[derive(Copy, Clone)]
96#[repr(C)]
97union RStringAux {
98 capa: c_long,
99 value: InternalValue,
100}
101
102#[derive(Copy, Clone)]
103#[repr(C)]
104struct RStringHeap {
105 len: c_long,
106 ptr: *const c_char,
107 aux: RStringAux,
108}
109
110#[repr(C)]
111struct RString {
112 basic: RBasic,
113 as_: RStringAs,
114}
115
116unsafe fn rstring_and_flags(value: Value) -> (*const RString, InternalValue) {
117 let rstring: *const RString = mem::transmute(value.value);
118 let flags = (*rstring).basic.flags;
119
120 (rstring, flags)
121}
122
123unsafe fn embed_check(flags: InternalValue) -> bool {
124 flags & (RStringEmbed::NoEmbed as size_t) == 0
125}
126
127pub unsafe fn rstring_embed_len(value: Value) -> c_long {
128 let (_rstring, flags) = rstring_and_flags(value);
129
130 ((flags as i64 >> RStringEmbed::LenShift as i64)
131 & (RStringEmbed::LenMask as i64 >> RStringEmbed::LenShift as i64)) as c_long
132}
133
134pub unsafe fn rstring_len(value: Value) -> c_long {
135 let (rstring, flags) = rstring_and_flags(value);
136
137 if embed_check(flags) {
138 rstring_embed_len(value)
139 } else {
140 (*rstring).as_.heap.len
141 }
142}
143
144pub unsafe fn rstring_ptr(value: Value) -> *const c_char {
145 let (rstring, flags) = rstring_and_flags(value);
146
147 if embed_check(flags) {
148 (*rstring).as_.ary.as_ptr()
149 } else {
150 (*rstring).as_.heap.ptr
151 }
152}
153
154pub unsafe fn rstring_end(value: Value) -> *const c_char {
155 let (rstring, flags) = rstring_and_flags(value);
156
157 if embed_check(flags) {
158 (*rstring)
159 .as_
160 .ary
161 .as_ptr()
162 .add(rstring_embed_len(value) as usize)
163 } else {
164 (*rstring)
165 .as_
166 .heap
167 .ptr
168 .add((*rstring).as_.heap.len as usize)
169 }
170}
171
172pub unsafe fn is_lockedtmp(value: Value) -> bool {
188 let (_rstring, flags) = rstring_and_flags(value);
189
190 flags & STR_TMPLOCK as size_t != 0
191}