Skip to content

Commit

Permalink
Improve From/Into Lua char conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
khvzak committed Jan 28, 2025
1 parent 47bc372 commit 8574682
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 39 deletions.
44 changes: 12 additions & 32 deletions src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,55 +660,35 @@ impl IntoLua for char {
fn into_lua(self, lua: &Lua) -> Result<Value> {
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<Self> {
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 {
Expand Down
19 changes: 12 additions & 7 deletions tests/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<char>("A")?;
assert_eq!(s, 'A');

let f = lua.create_function(|_, s: mlua::Integer| Ok(s))?;
let s = f.call::<char>(65)?;
assert_eq!(s, 'A');
assert_eq!(lua.convert::<char>("A")?, 'A');
assert_eq!(lua.convert::<char>(65)?, 'A');
assert_eq!(lua.convert::<char>(128175)?, '💯');
assert!(lua
.convert::<char>(5456324)
.is_err_and(|e| e.to_string().contains("integer out of range")));
assert!(lua
.convert::<char>("hello")
.is_err_and(|e| e.to_string().contains("expected string to have exactly one char")));
assert!(lua
.convert::<char>(HashMap::<String, String>::new())
.is_err_and(|e| e.to_string().contains("expected string or integer")));

Ok(())
}

0 comments on commit 8574682

Please sign in to comment.