string_enum/
string_enum.rs1use core::ffi::c_int;
4use lunka::prelude::*;
5
6pub unsafe trait LuaEnum<const N: usize> {
7 const OPTIONS: &'static lunka::AuxOptions<'static, N>;
8 unsafe fn from_index_unchecked(index: usize) -> Self;
9}
10
11#[derive(Debug)]
12enum SocketKind {
13 Udp,
14 Tcp,
15 UnixUdp,
16 UnixTcp,
17}
18
19unsafe impl LuaEnum<4> for SocketKind {
20 const OPTIONS: &'static LuaAuxOptions<'static, 4> = &LuaAuxOptions::new([
21 c"udp",
22 c"tcp",
23 c"unix udp",
24 c"unix tcp",
25 ]);
26 unsafe fn from_index_unchecked(index: usize) -> Self {
27 match index {
28 0 => Self::Udp,
29 1 => Self::Tcp,
30 2 => Self::UnixUdp,
31 3 => Self::UnixTcp,
32 _ => ::core::hint::unreachable_unchecked(),
33 }
34 }
35}
36
37trait ThreadExt {
38 fn check_enum<E: LuaEnum<N>, const N: usize>(&self, arg: c_int) -> E;
39}
40
41impl ThreadExt for LuaThread {
42 fn check_enum<E: LuaEnum<N>, const N: usize>(&self, arg: c_int) -> E {
43 let index = self.check_option(arg, None, E::OPTIONS);
44 unsafe { E::from_index_unchecked(index) }
45 }
46}
47
48unsafe extern "C-unwind" fn l_test(l: *mut LuaState) -> c_int {
49 let lua = unsafe { LuaThread::from_ptr(l) };
50 let socket_kind: SocketKind = lua.check_enum(1);
51 println!("socket kind: {socket_kind:?}");
52 0
53}
54
55unsafe extern "C-unwind" fn l_main(l: *mut LuaState) -> c_int {
56 let lua = unsafe { LuaThread::from_ptr_mut(l) };
57 let mut test = move |variant: &[u8]| {
58 lua.run_managed(move |mut mg| {
59 mg.push_c_function(l_test);
60 mg.push_string(variant);
61 unsafe { mg.call(1, 0) }
62 })
63 };
64 test(b"udp");
65 test(b"tcp");
66 test(b"unix udp");
67 test(b"unix tcp");
68 test(b"invalid");
69 0
70}
71
72fn main() {
73 let mut lua = Lua::new();
74 let did_run_ok = lua.run_managed(move |mut mg| {
75 mg.push_c_function(l_main);
76 unsafe { mg.pcall(0, 1, 0).is_ok() }
77 });
78 assert!(!did_run_ok, "test code should fail");
79}