diff --git a/src/conversion.rs b/src/conversion.rs index ad0a7003..e24d6c86 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -655,6 +655,71 @@ impl IntoLua for &Path { } } +impl IntoLua for char { + #[inline] + 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)?)) + } +} + +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 { + 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(), + ), + }) + } + } + // 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 { + from: ty, + to: Self::type_name(), + message: Some( + "string must have one char when converting to char. (empty string)".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 { + from: ty, + to: Self::type_name(), + message: Some("expected string or integer".to_string()), + }), + } + } +} + #[inline] unsafe fn push_bytes_into_stack(this: T, lua: &RawLua) -> Result<()> where diff --git a/tests/conversion.rs b/tests/conversion.rs index 2cb9b880..e479c6bd 100644 --- a/tests/conversion.rs +++ b/tests/conversion.rs @@ -657,3 +657,29 @@ fn test_either_from_lua() -> Result<()> { Ok(()) } + +#[test] +fn test_char_into_lua() -> Result<()> { + let lua = Lua::new(); + + let v = '🦀'; + let v2 = v.into_lua(&lua)?; + assert_eq!(Some(v.to_string()), v2.as_string_lossy()); + + Ok(()) +} + +#[test] +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'); + + Ok(()) +}