Skip to content

Commit 8574682

Browse files
committed
Improve From/Into Lua char conversion
1 parent 47bc372 commit 8574682

File tree

2 files changed

+24
-39
lines changed

2 files changed

+24
-39
lines changed

src/conversion.rs

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -660,55 +660,35 @@ impl IntoLua for char {
660660
fn into_lua(self, lua: &Lua) -> Result<Value> {
661661
let mut char_bytes = [0; 4];
662662
self.encode_utf8(&mut char_bytes);
663-
Ok(Value::String(lua.create_string(char_bytes)?))
663+
Ok(Value::String(lua.create_string(&char_bytes[..self.len_utf8()])?))
664664
}
665665
}
666666

667667
impl FromLua for char {
668-
#[inline]
669668
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
670669
let ty = value.type_name();
671670
match value {
672-
// When integer: reduce it to u8 and try to convert to char
673671
Value::Integer(i) => {
674-
if i <= u8::MAX.into() && i >= 0 {
675-
Ok(char::from(i as u8))
676-
} else {
677-
Err(Error::FromLuaConversionError {
672+
cast(i)
673+
.and_then(char::from_u32)
674+
.ok_or_else(|| Error::FromLuaConversionError {
678675
from: ty,
679-
to: Self::type_name(),
680-
message: Some(
681-
"expected int to be a u8 when converting to char. You can also use strings."
682-
.to_string(),
683-
),
676+
to: "char".to_string(),
677+
message: Some("integer out of range when converting to char".to_string()),
684678
})
685-
}
686679
}
687-
// When String: first char, and only if there is one char
688680
Value::String(s) => {
689681
let str = s.to_str()?;
690682
let mut str_iter = str.chars();
691-
let Some(char) = str_iter.next() else {
692-
return Err(Error::FromLuaConversionError {
683+
match (str_iter.next(), str_iter.next()) {
684+
(Some(char), None) => Ok(char),
685+
_ => Err(Error::FromLuaConversionError {
693686
from: ty,
694-
to: Self::type_name(),
687+
to: "char".to_string(),
695688
message: Some(
696-
"string must have one char when converting to char. (empty string)".to_string(),
689+
"expected string to have exactly one char when converting to char".to_string(),
697690
),
698-
});
699-
};
700-
701-
if let Some(_extra_char) = str_iter.next() {
702-
Err(Error::FromLuaConversionError {
703-
from: ty,
704-
to: Self::type_name(),
705-
message: Some(
706-
"expected lua string to have exactly one char when converting to char"
707-
.to_string(),
708-
),
709-
})
710-
} else {
711-
Ok(char)
691+
}),
712692
}
713693
}
714694
_ => Err(Error::FromLuaConversionError {

tests/conversion.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -673,13 +673,18 @@ fn test_char_into_lua() -> Result<()> {
673673
fn test_char_from_lua() -> Result<()> {
674674
let lua = Lua::new();
675675

676-
let f = lua.create_function(|_, s: mlua::String| Ok(s))?;
677-
let s = f.call::<char>("A")?;
678-
assert_eq!(s, 'A');
679-
680-
let f = lua.create_function(|_, s: mlua::Integer| Ok(s))?;
681-
let s = f.call::<char>(65)?;
682-
assert_eq!(s, 'A');
676+
assert_eq!(lua.convert::<char>("A")?, 'A');
677+
assert_eq!(lua.convert::<char>(65)?, 'A');
678+
assert_eq!(lua.convert::<char>(128175)?, '💯');
679+
assert!(lua
680+
.convert::<char>(5456324)
681+
.is_err_and(|e| e.to_string().contains("integer out of range")));
682+
assert!(lua
683+
.convert::<char>("hello")
684+
.is_err_and(|e| e.to_string().contains("expected string to have exactly one char")));
685+
assert!(lua
686+
.convert::<char>(HashMap::<String, String>::new())
687+
.is_err_and(|e| e.to_string().contains("expected string or integer")));
683688

684689
Ok(())
685690
}

0 commit comments

Comments
 (0)