1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
use libc; use std; use sys; use sys::{VALUE}; use super::{FromRuby, CheckResult, CheckedValue, ToRuby, ToRubyResult}; impl FromRuby for String { type Checked = CheckedValue<String>; fn from_ruby(value: VALUE) -> CheckResult<CheckedValue<String>> { if unsafe { sys::RB_TYPE_P(value, sys::T_STRING) } { if unsafe { sys::rb_enc_get_index(value) == sys::rb_utf8_encindex() } { if unsafe { sys::rb_str_valid_encoding_p(value) } { unsafe { Ok(CheckedValue::new(value)) } } else { type_error!(value, "a valid UTF-8 String") } } else { if unsafe { sys::rb_str_ascii_only_p(value) } { unsafe { Ok(CheckedValue::new(value)) } } else { type_error!(value, "an UTF-8 String") } } } else { type_error!(value, "a String") } } fn from_checked(checked: CheckedValue<String>) -> String { let value = checked.to_value(); let size = unsafe { sys::RSTRING_LEN(value) }; let ptr = unsafe { sys::RSTRING_PTR(value) }; let slice = unsafe { std::slice::from_raw_parts(ptr as *const u8, size as usize) }; unsafe { std::str::from_utf8_unchecked(slice) }.to_string() } } impl ToRuby for String { fn to_ruby(self) -> ToRubyResult { let ptr = self.as_ptr(); let len = self.len(); Ok(unsafe { sys::rb_utf8_str_new(ptr as *const libc::c_char, len as libc::c_long) }) } } impl<'a> ToRuby for &'a str { fn to_ruby(self) -> ToRubyResult { let ptr = self.as_ptr(); let len = self.len(); Ok(unsafe { sys::rb_utf8_str_new(ptr as *const libc::c_char, len as libc::c_long) }) } }