Skip to content

Commit 47bc372

Browse files
authored
impl FromLua/IntoLua for char (#516)
1 parent d376cb9 commit 47bc372

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

Diff for: src/conversion.rs

+65
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,71 @@ impl IntoLua for &Path {
655655
}
656656
}
657657

658+
impl IntoLua for char {
659+
#[inline]
660+
fn into_lua(self, lua: &Lua) -> Result<Value> {
661+
let mut char_bytes = [0; 4];
662+
self.encode_utf8(&mut char_bytes);
663+
Ok(Value::String(lua.create_string(char_bytes)?))
664+
}
665+
}
666+
667+
impl FromLua for char {
668+
#[inline]
669+
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
670+
let ty = value.type_name();
671+
match value {
672+
// When integer: reduce it to u8 and try to convert to char
673+
Value::Integer(i) => {
674+
if i <= u8::MAX.into() && i >= 0 {
675+
Ok(char::from(i as u8))
676+
} else {
677+
Err(Error::FromLuaConversionError {
678+
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+
),
684+
})
685+
}
686+
}
687+
// When String: first char, and only if there is one char
688+
Value::String(s) => {
689+
let str = s.to_str()?;
690+
let mut str_iter = str.chars();
691+
let Some(char) = str_iter.next() else {
692+
return Err(Error::FromLuaConversionError {
693+
from: ty,
694+
to: Self::type_name(),
695+
message: Some(
696+
"string must have one char when converting to char. (empty string)".to_string(),
697+
),
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)
712+
}
713+
}
714+
_ => Err(Error::FromLuaConversionError {
715+
from: ty,
716+
to: Self::type_name(),
717+
message: Some("expected string or integer".to_string()),
718+
}),
719+
}
720+
}
721+
}
722+
658723
#[inline]
659724
unsafe fn push_bytes_into_stack<T>(this: T, lua: &RawLua) -> Result<()>
660725
where

Diff for: tests/conversion.rs

+26
Original file line numberDiff line numberDiff line change
@@ -657,3 +657,29 @@ fn test_either_from_lua() -> Result<()> {
657657

658658
Ok(())
659659
}
660+
661+
#[test]
662+
fn test_char_into_lua() -> Result<()> {
663+
let lua = Lua::new();
664+
665+
let v = '🦀';
666+
let v2 = v.into_lua(&lua)?;
667+
assert_eq!(Some(v.to_string()), v2.as_string_lossy());
668+
669+
Ok(())
670+
}
671+
672+
#[test]
673+
fn test_char_from_lua() -> Result<()> {
674+
let lua = Lua::new();
675+
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');
683+
684+
Ok(())
685+
}

0 commit comments

Comments
 (0)