From 1f2fc6455fe4c8723b46a0ce4312a7e01b26ee06 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 25 Jul 2017 00:37:37 +0200 Subject: [PATCH] Beef up the String API Adds `as_bytes` to view the string as a `[u8]`. Unlike the conversion to a `&str` slice, this cannot fail. Adds tests for both functions, which made me notice that `to_str` is broken when the string contains null bytes, so I made it use the `as_bytes` method. --- src/lua.rs | 24 ++++++++++++++++-------- src/tests.rs | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/lua.rs b/src/lua.rs index 8fee6b5..faadf36 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1,9 +1,8 @@ -use std::fmt; +use std::{fmt, ptr, slice, str}; use std::ops::{Deref, DerefMut}; use std::iter::FromIterator; use std::cell::{RefCell, Ref, RefMut}; -use std::ptr; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::any::TypeId; use std::marker::PhantomData; use std::collections::{HashMap, VecDeque}; @@ -189,18 +188,27 @@ impl<'lua> String<'lua> { /// # } /// ``` pub fn to_str(&self) -> Result<&str> { + str::from_utf8(self.as_bytes()).map_err(|e| Error::FromLuaConversionError(e.to_string())) + } + + /// Get the bytes that make up this string. + /// + /// The returned slice will not contain the terminating null byte, but will contain any null + /// bytes embedded into the Lua string. + pub fn as_bytes(&self) -> &[u8] { let lua = self.0.lua; unsafe { stack_err_guard(lua.state, 0, || { check_stack(lua.state, 1); lua.push_ref(lua.state, &self.0); assert_eq!(ffi::lua_type(lua.state, -1), ffi::LUA_TSTRING); - let s = CStr::from_ptr(ffi::lua_tostring(lua.state, -1)) - .to_str() - .map_err(|e| Error::FromLuaConversionError(e.to_string()))?; + + let mut size = 0; + let data = ffi::lua_tolstring(lua.state, -1, &mut size); + ffi::lua_pop(lua.state, 1); - Ok(s) - }) + Ok(slice::from_raw_parts(data as *const u8, size)) + }).expect("infallible stack_err_guard failed") // this conversion cannot fail } } } diff --git a/src/tests.rs b/src/tests.rs index d7cbbfb..3a19d05 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -863,3 +863,22 @@ fn detroys_userdata() { drop(lua); // should destroy all objects assert_eq!(DROPPED.load(Ordering::SeqCst), true); } + +#[test] +fn string_views() { + let lua = Lua::new(); + lua.eval::<()>(r#" + ok = "null bytes are valid utf-8, wh\0 knew?" + err = "but \xff isn't :(" + "#, None).unwrap(); + + let globals = lua.globals(); + let ok: LuaString = globals.get("ok").unwrap(); + let err: LuaString = globals.get("err").unwrap(); + + assert_eq!(ok.to_str().unwrap(), "null bytes are valid utf-8, wh\0 knew?"); + assert_eq!(ok.as_bytes(), &b"null bytes are valid utf-8, wh\0 knew?"[..]); + + assert!(err.to_str().is_err()); + assert_eq!(err.as_bytes(), &b"but \xff isn't :("[..]); +}