From 8574682ffc7337cfb8f1e59c877dc197a25e1949 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Tue, 28 Jan 2025 10:41:10 +0000 Subject: [PATCH] Improve From/Into Lua char conversion --- src/conversion.rs | 44 ++++++++++++-------------------------------- tests/conversion.rs | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index e24d6c86..c63fd369 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -660,55 +660,35 @@ impl IntoLua for char { fn into_lua(self, lua: &Lua) -> Result { let mut char_bytes = [0; 4]; self.encode_utf8(&mut char_bytes); - Ok(Value::String(lua.create_string(char_bytes)?)) + Ok(Value::String(lua.create_string(&char_bytes[..self.len_utf8()])?)) } } impl FromLua for char { - #[inline] fn from_lua(value: Value, _lua: &Lua) -> Result { let ty = value.type_name(); match value { - // When integer: reduce it to u8 and try to convert to char Value::Integer(i) => { - if i <= u8::MAX.into() && i >= 0 { - Ok(char::from(i as u8)) - } else { - Err(Error::FromLuaConversionError { + cast(i) + .and_then(char::from_u32) + .ok_or_else(|| Error::FromLuaConversionError { from: ty, - to: Self::type_name(), - message: Some( - "expected int to be a u8 when converting to char. You can also use strings." - .to_string(), - ), + to: "char".to_string(), + message: Some("integer out of range when converting to char".to_string()), }) - } } - // When String: first char, and only if there is one char Value::String(s) => { let str = s.to_str()?; let mut str_iter = str.chars(); - let Some(char) = str_iter.next() else { - return Err(Error::FromLuaConversionError { + match (str_iter.next(), str_iter.next()) { + (Some(char), None) => Ok(char), + _ => Err(Error::FromLuaConversionError { from: ty, - to: Self::type_name(), + to: "char".to_string(), message: Some( - "string must have one char when converting to char. (empty string)".to_string(), + "expected string to have exactly one char when converting to char".to_string(), ), - }); - }; - - if let Some(_extra_char) = str_iter.next() { - Err(Error::FromLuaConversionError { - from: ty, - to: Self::type_name(), - message: Some( - "expected lua string to have exactly one char when converting to char" - .to_string(), - ), - }) - } else { - Ok(char) + }), } } _ => Err(Error::FromLuaConversionError { diff --git a/tests/conversion.rs b/tests/conversion.rs index e479c6bd..3987ba42 100644 --- a/tests/conversion.rs +++ b/tests/conversion.rs @@ -673,13 +673,18 @@ fn test_char_into_lua() -> Result<()> { fn test_char_from_lua() -> Result<()> { let lua = Lua::new(); - let f = lua.create_function(|_, s: mlua::String| Ok(s))?; - let s = f.call::("A")?; - assert_eq!(s, 'A'); - - let f = lua.create_function(|_, s: mlua::Integer| Ok(s))?; - let s = f.call::(65)?; - assert_eq!(s, 'A'); + assert_eq!(lua.convert::("A")?, 'A'); + assert_eq!(lua.convert::(65)?, 'A'); + assert_eq!(lua.convert::(128175)?, '💯'); + assert!(lua + .convert::(5456324) + .is_err_and(|e| e.to_string().contains("integer out of range"))); + assert!(lua + .convert::("hello") + .is_err_and(|e| e.to_string().contains("expected string to have exactly one char"))); + assert!(lua + .convert::(HashMap::::new()) + .is_err_and(|e| e.to_string().contains("expected string or integer"))); Ok(()) }