tlua/
values.rs

1use std::borrow::Cow;
2use std::convert::TryFrom;
3use std::ffi::{CStr, CString, OsStr, OsString};
4use std::mem::MaybeUninit;
5use std::num::NonZeroI32;
6use std::ops::Deref;
7use std::os::raw::{c_int, c_void};
8use std::os::unix::ffi::{OsStrExt, OsStringExt};
9use std::path::{Path, PathBuf};
10use std::ptr::null_mut;
11use std::slice;
12use std::str;
13
14use crate::{
15    ffi, AnyLuaString, AsLua, LuaRead, Push, PushGuard, PushInto, PushOne, PushOneInto, ReadResult,
16    Void, WrongType,
17};
18
19macro_rules! numeric_impl {
20    ($t:ident, $push:path, $read:path $(, coerce: $coerce:expr)?) => {
21        impl<L> Push<L> for $t
22        where
23            L: AsLua,
24        {
25            type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
26
27            #[inline(always)]
28            fn push_to_lua(&self, lua: L) -> Result<PushGuard<L>, (Void, L)> {
29                Self::push_into_lua(*self, lua)
30            }
31        }
32
33        impl<L> PushOne<L> for $t
34        where
35            L: AsLua,
36        {
37        }
38
39        impl<L> PushInto<L> for $t
40        where
41            L: AsLua,
42        {
43            type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
44
45            #[inline(always)]
46            fn push_into_lua(self, lua: L) -> Result<PushGuard<L>, (Void, L)> {
47                unsafe {
48                    $push(lua.as_lua(), self as _);
49                    Ok(PushGuard::new(lua, 1))
50                }
51            }
52        }
53
54        impl<L> PushOneInto<L> for $t
55        where
56            L: AsLua,
57        {
58        }
59
60        impl<L> LuaRead<L> for $t
61        where
62            L: AsLua,
63        {
64            #[inline(always)]
65            fn lua_read_at_position(lua: L, index: NonZeroI32) -> ReadResult<$t, L> {
66                return if let Some(v) = unsafe { read_numeric(lua.as_lua(), index.into()) } {
67                    Ok(v as _)
68                } else {
69                    let e = WrongType::default()
70                        .expected_type::<Self>()
71                        .actual_single_lua(&lua, index);
72                    Err((lua, e))
73                };
74
75                #[inline(always)]
76                pub unsafe fn read_numeric(l: *mut ffi::lua_State, idx: c_int) -> Option<$t> {
77                    match ffi::lua_type(l, idx) {
78                        ffi::LUA_TNUMBER => {
79                            let number = $read(l, idx);
80                            $(
81                                let number = $coerce(number);
82                            )?
83                            Some(number as _)
84                        }
85                        ffi::LUA_TCDATA => {
86                            let mut ctypeid = std::mem::MaybeUninit::uninit();
87                            let cdata = ffi::luaL_checkcdata(l, idx, ctypeid.as_mut_ptr());
88                            match ctypeid.assume_init() {
89                                ffi::CTID_CCHAR => Some(*cdata.cast::<std::os::raw::c_char>() as _),
90                                ffi::CTID_INT8 => Some(*cdata.cast::<i8>() as _),
91                                ffi::CTID_INT16 => Some(*cdata.cast::<i16>() as _),
92                                ffi::CTID_INT32 => Some(*cdata.cast::<i32>() as _),
93                                ffi::CTID_INT64 => Some(*cdata.cast::<i64>() as _),
94                                ffi::CTID_UINT8 => Some(*cdata.cast::<u8>() as _),
95                                ffi::CTID_UINT16 => Some(*cdata.cast::<u16>() as _),
96                                ffi::CTID_UINT32 => Some(*cdata.cast::<u32>() as _),
97                                ffi::CTID_UINT64 => Some(*cdata.cast::<u64>() as _),
98                                ffi::CTID_FLOAT => Some(*cdata.cast::<f32>() as _),
99                                ffi::CTID_DOUBLE => Some(*cdata.cast::<f64>() as _),
100                                _ => None,
101                            }
102                        }
103                        _ => None,
104                    }
105                }
106            }
107        }
108    }
109}
110
111numeric_impl! {isize, ffi::luaL_pushint64, ffi::lua_tonumber}
112numeric_impl! {i64, ffi::luaL_pushint64, ffi::lua_tonumber}
113numeric_impl! {i32, ffi::lua_pushinteger, ffi::lua_tointeger}
114numeric_impl! {i16, ffi::lua_pushinteger, ffi::lua_tointeger}
115numeric_impl! {i8, ffi::lua_pushinteger, ffi::lua_tointeger}
116
117numeric_impl! {usize, ffi::luaL_pushuint64, ffi::lua_tonumber,
118    coerce: |n| {
119        if n >= 0. {
120            n as usize
121        } else {
122            n as isize as usize
123        }
124    }
125}
126numeric_impl! {u64, ffi::luaL_pushuint64, ffi::lua_tonumber,
127    coerce: |n| {
128        if n >= 0. {
129            n as u64
130        } else {
131            n as i64 as u64
132        }
133    }
134}
135numeric_impl! {u32, ffi::lua_pushinteger, ffi::lua_tointeger}
136numeric_impl! {u16, ffi::lua_pushinteger, ffi::lua_tointeger}
137numeric_impl! {u8, ffi::lua_pushinteger, ffi::lua_tointeger}
138
139numeric_impl! {f64, ffi::lua_pushnumber, ffi::lua_tonumber}
140numeric_impl! {f32, ffi::lua_pushnumber, ffi::lua_tonumber}
141
142macro_rules! strict_numeric_impl {
143    (@is_valid int $num:tt $t:ty) => {
144        $num.is_finite() && $num.fract() == 0.0 &&
145        $num >= <$t>::MIN as _ && $num <= <$t>::MAX as _
146    };
147    (@is_valid float $num:tt $t:ty) => {
148        !$num.is_finite() || $num >= <$t>::MIN as _ && $num <= <$t>::MAX as _
149    };
150    ($k:tt $t:ty) => {
151        impl<L> LuaRead<L> for Strict<$t>
152        where
153            L: AsLua,
154        {
155            #[inline(always)]
156            fn lua_read_at_position(lua: L, index: NonZeroI32) -> ReadResult<Self, L> {
157                let l = lua.as_lua();
158                let idx = index.into();
159                let res = unsafe {
160                    match ffi::lua_type(l, idx) {
161                        ffi::LUA_TNUMBER => {
162                            let num = ffi::lua_tonumber(l, idx);
163                            let is_valid = strict_numeric_impl!(@is_valid $k num $t);
164                            if is_valid {
165                                Some(num as $t)
166                            } else {
167                                None
168                            }
169                        }
170                        _ => None,
171                    }
172                };
173                res.map(Strict).ok_or_else(|| {
174                    let e = WrongType::default()
175                        .expected_type::<Self>()
176                        .actual_single_lua(&lua, index);
177                    (lua, e)
178                })
179            }
180        }
181    };
182}
183
184/// A wrapper type for reading lua numbers of concrete precisions without
185/// implicit coercions.
186///
187/// By default when reading a numeric type (int or float) from a lua number
188/// (i.e. calling [`LuaRead::lua_read_at_position`]) the resulting number will
189/// be implicitly coerced into the target type. For example if the lua number
190/// has a non zero fractional part it will be discarded when reading the number
191/// as integer.
192/// ```no_run
193/// use tlua::Lua;
194/// let lua = tlua::Lua::new();
195/// let i: Option<i32> = lua.eval("return 3.14").ok();
196/// assert_eq!(i, Some(3));
197/// ```
198///
199/// If you don't want the implicit coercision, you can use the `Strict` wrapper:
200/// ```no_run
201/// # use tlua::Lua;
202/// use tlua::Strict;
203/// # let lua = Lua::new();
204/// let i: Option<Strict<i32>> = lua.eval("return 3.14").ok();
205/// assert_eq!(i, None); // would result in loss of data
206///
207/// let f: Option<Strict<f64>> = lua.eval("return 3.14").ok();
208/// assert_eq!(f, Some(Strict(3.14))); // ok
209/// ```
210///
211/// This *strictness* also applies in terms of number sizes:
212/// ```no_run
213/// # use tlua::{Lua, Strict};
214/// # let lua = Lua::new();
215/// let i: Option<u8> = lua.eval("return 256").ok();
216/// assert_eq!(i, Some(0)); // non-strict => data loss
217///
218/// let i: Option<Strict<u8>> = lua.eval("return 256").ok();
219/// assert_eq!(i, None); // strict => must not lose data
220///
221/// let i: Option<Strict<u16>> = lua.eval("return 256").ok();
222/// assert_eq!(i, Some(Strict(256))); // strict => no data loss
223/// ```
224///
225/// # Reading cdata
226///
227/// This type only supports regular lua numbers. If you want to read a luajit
228/// cdata type, use the [`CData`](crate::CData) wrapper instead.
229#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
230pub struct Strict<T>(pub T);
231
232strict_numeric_impl! {int i8}
233strict_numeric_impl! {int i16}
234strict_numeric_impl! {int i32}
235strict_numeric_impl! {int i64}
236strict_numeric_impl! {int isize}
237strict_numeric_impl! {int u8}
238strict_numeric_impl! {int u16}
239strict_numeric_impl! {int u32}
240strict_numeric_impl! {int u64}
241strict_numeric_impl! {int usize}
242strict_numeric_impl! {float f32}
243strict_numeric_impl! {float f64}
244
245impl<T> From<T> for Strict<T> {
246    fn from(v: T) -> Self {
247        Self(v)
248    }
249}
250
251macro_rules! impl_push_read {
252    (
253        $t:ty,
254        $(push_to_lua(&$self1:ident, $lua1:ident) { $($push:tt)* })?
255        $(push_into_lua($self2:ident, $lua2:ident) { $($push_into:tt)* })?
256        $(
257            read_at_position($lua3:ident, $index1:ident) { $($read:tt)* }
258            $(read_at_maybe_zero_position($lua4:ident, $index2:ident) { $($read_mz:tt)* })?
259        )?
260    ) => {
261        $(
262            impl<L> Push<L> for $t
263            where
264                L: AsLua,
265            {
266                type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
267
268                #[inline(always)]
269                fn push_to_lua(&$self1, $lua1: L) -> Result<PushGuard<L>, (Void, L)> {
270                    $($push)*
271                }
272            }
273
274            impl<L> PushOne<L> for $t
275            where
276                L: AsLua,
277            {
278            }
279        )?
280
281        $(
282            impl<L> PushInto<L> for $t
283            where
284                L: AsLua,
285            {
286                type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
287
288                #[inline(always)]
289                fn push_into_lua($self2, $lua2: L) -> Result<PushGuard<L>, (Void, L)> {
290                    $($push_into)?
291                }
292            }
293
294            impl<L> PushOneInto<L> for $t
295            where
296                L: AsLua,
297            {
298            }
299        )?
300
301        $(
302            impl<L> LuaRead<L> for $t
303            where
304                L: AsLua,
305            {
306                #[inline(always)]
307                fn lua_read_at_position($lua3: L, $index1: NonZeroI32) -> $crate::ReadResult<Self, L> {
308                    $($read)*
309                }
310
311                $(
312                    #[inline(always)]
313                    fn lua_read_at_maybe_zero_position($lua4: L, $index2: i32) -> $crate::ReadResult<Self, L> {
314                        $($read_mz)*
315                    }
316                )?
317            }
318        )?
319    }
320}
321
322macro_rules! push_string_impl {
323    ($self:ident, $lua:ident) => {
324        unsafe {
325            ffi::lua_pushlstring(
326                $lua.as_lua(),
327                $self.as_bytes().as_ptr() as _,
328                $self.as_bytes().len() as _,
329            );
330            Ok(PushGuard::new($lua, 1))
331        }
332    };
333}
334
335macro_rules! lua_read_string_impl {
336    ($lua:ident, $index:ident, $from_slice:expr) => {
337        (|| unsafe {
338            let mut size = MaybeUninit::uninit();
339            let type_code = ffi::lua_type($lua.as_lua(), $index.into());
340            // Because this function may be called while iterating over
341            // a table we must make sure not to change the value on the
342            // stack. So no number to string conversions are supported
343            // anymore
344            if type_code != ffi::LUA_TSTRING {
345                return Err($lua);
346            }
347            let c_ptr = ffi::lua_tolstring($lua.as_lua(), $index.into(), size.as_mut_ptr());
348            if c_ptr.is_null() {
349                return Err($lua);
350            }
351            let slice = slice::from_raw_parts(c_ptr as _, size.assume_init());
352            $from_slice(slice, $lua)
353        })()
354        .map_err(|lua| {
355            let e = $crate::WrongType::default()
356                .expected_type::<Self>()
357                .actual_single_lua(&lua, $index);
358            (lua, e)
359        })
360    };
361}
362
363impl_push_read! { String,
364    push_to_lua(&self, lua) {
365        push_string_impl!(self, lua)
366    }
367    push_into_lua(self, lua) {
368        push_string_impl!(self, lua)
369    }
370    read_at_position(lua, index) {
371        lua_read_string_impl!(lua, index,
372            |slice: &[u8], lua| String::from_utf8(slice.to_vec()).map_err(|_| lua)
373        )
374    }
375}
376
377impl_push_read! { CString,
378    push_to_lua(&self, lua) {
379        push_string_impl!(self, lua)
380    }
381    push_into_lua(self, lua) {
382        push_string_impl!(self, lua)
383    }
384    read_at_position(lua, index) {
385        lua_read_string_impl!(lua, index,
386            |slice: &[u8], lua| CString::new(slice).map_err(|_| lua)
387        )
388    }
389}
390
391impl_push_read! { AnyLuaString,
392    push_to_lua(&self, lua) {
393        push_string_impl!(self, lua)
394    }
395    push_into_lua(self, lua) {
396        push_string_impl!(self, lua)
397    }
398    read_at_position(lua, index) {
399        lua_read_string_impl!(lua, index,
400            |slice: &[u8], _| Ok(AnyLuaString(slice.to_vec()))
401        )
402    }
403}
404
405impl_push_read! { str,
406    push_to_lua(&self, lua) {
407        push_string_impl!(self, lua)
408    }
409}
410
411impl_push_read! { CStr,
412    push_to_lua(&self, lua) {
413        unsafe {
414            ffi::lua_pushlstring(
415                lua.as_lua(),
416                self.as_ptr() as _,
417                self.to_bytes().len() as _,
418            );
419            Ok(PushGuard::new(lua, 1))
420        }
421    }
422}
423
424impl_push_read! { OsString,
425    push_to_lua(&self, lua) {
426        push_string_impl!(self, lua)
427    }
428    push_into_lua(self, lua) {
429        push_string_impl!(self, lua)
430    }
431    read_at_position(lua, index) {
432        lua_read_string_impl!(lua, index,
433            |slice: &[u8], _| Ok(OsString::from_vec(slice.to_vec()))
434        )
435    }
436}
437
438impl_push_read! { OsStr,
439    push_to_lua(&self, lua) {
440        push_string_impl!(self, lua)
441    }
442}
443
444impl_push_read! { PathBuf,
445    push_to_lua(&self, lua) {
446        self.as_path().push_to_lua(lua)
447    }
448    push_into_lua(self, lua) {
449        let s = self.into_os_string();
450        push_string_impl!(s, lua)
451    }
452    read_at_position(lua, index) {
453        OsString::lua_read_at_position(lua, index).map(Into::into)
454    }
455}
456
457impl_push_read! { Path,
458    push_to_lua(&self, lua) {
459        let s = self.as_os_str();
460        push_string_impl!(s, lua)
461    }
462}
463
464/// String on the Lua stack.
465///
466/// It is faster -but less convenient- to read a `StringInLua` rather than a `String` because you
467/// avoid any allocation.
468///
469/// The `StringInLua` derefs to `str`.
470///
471/// # Example
472///
473/// ```no_run
474/// let mut lua = tlua::Lua::new();
475/// lua.set("a", "hello");
476///
477/// let s: tlua::StringInLua<_> = lua.get("a").unwrap();
478/// println!("{}", &*s);    // Prints "hello".
479/// ```
480#[derive(Debug, Eq, Ord, Hash)]
481pub struct StringInLua<'a, L: 'a> {
482    lua: L,
483    str_ref: &'a str,
484}
485
486impl<L> StringInLua<'_, L> {
487    pub fn into_inner(self) -> L {
488        self.lua
489    }
490}
491
492impl<L> std::cmp::PartialEq for StringInLua<'_, L> {
493    fn eq(&self, other: &Self) -> bool {
494        self.str_ref.eq(other.str_ref)
495    }
496}
497
498impl<L> std::cmp::PartialOrd for StringInLua<'_, L> {
499    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
500        self.str_ref.partial_cmp(other.str_ref)
501    }
502}
503
504impl<L> std::cmp::PartialEq<&'_ str> for StringInLua<'_, L> {
505    fn eq(&self, other: &&str) -> bool {
506        self.str_ref.eq(*other)
507    }
508}
509
510impl<'a, L> LuaRead<L> for StringInLua<'a, L>
511where
512    L: 'a + AsLua,
513{
514    fn lua_read_at_position(lua: L, index: NonZeroI32) -> ReadResult<Self, L> {
515        lua_read_string_impl!(
516            lua,
517            index,
518            |slice: &'a [u8], lua| match str::from_utf8(slice) {
519                Ok(str_ref) => Ok(StringInLua { lua, str_ref }),
520                Err(_) => Err(lua),
521            }
522        )
523    }
524}
525
526impl<L> Deref for StringInLua<'_, L> {
527    type Target = str;
528
529    #[inline]
530    fn deref(&self) -> &str {
531        self.str_ref
532    }
533}
534
535impl_push_read! { bool,
536    push_to_lua(&self, lua) {
537        Self::push_into_lua(*self, lua)
538    }
539    push_into_lua(self, lua) {
540        unsafe {
541            ffi::lua_pushboolean(lua.as_lua(), self as _);
542            Ok(PushGuard::new(lua, 1))
543        }
544    }
545    read_at_position(lua, index) {
546        if !unsafe { ffi::lua_isboolean(lua.as_lua(), index.into()) } {
547            let e = WrongType::default()
548                .expected_type::<Self>()
549                .actual_single_lua(&lua, index);
550            return Err((lua, e));
551        }
552
553        Ok(unsafe { ffi::lua_toboolean(lua.as_lua(), index.into()) != 0 })
554    }
555}
556
557impl_push_read! { (),
558    push_to_lua(&self, lua) {
559        ().push_into_lua(lua)
560    }
561    push_into_lua(self, lua) {
562        unsafe { Ok(PushGuard::new(lua, 0)) }
563    }
564    read_at_position(_lua, _index) {
565        Ok(())
566    }
567    read_at_maybe_zero_position(_lua, _index) {
568        Ok(())
569    }
570}
571
572impl<L, T> Push<L> for Option<T>
573where
574    T: Push<L>,
575    L: AsLua,
576{
577    type Err = T::Err;
578
579    #[inline]
580    fn push_to_lua(&self, lua: L) -> Result<PushGuard<L>, (Self::Err, L)> {
581        match self {
582            Some(val) => val.push_to_lua(lua),
583            None => Ok(Nil.push_into_no_err(lua)),
584        }
585    }
586}
587
588impl<L, T> PushOne<L> for Option<T>
589where
590    T: PushOne<L>,
591    L: AsLua,
592{
593}
594
595impl<L, T> PushInto<L> for Option<T>
596where
597    T: PushInto<L>,
598    L: AsLua,
599{
600    type Err = T::Err;
601
602    #[inline]
603    fn push_into_lua(self, lua: L) -> Result<PushGuard<L>, (Self::Err, L)> {
604        match self {
605            Some(val) => val.push_into_lua(lua),
606            None => Ok(Nil.push_into_no_err(lua)),
607        }
608    }
609}
610
611impl<L, T> PushOneInto<L> for Option<T>
612where
613    T: PushOneInto<L>,
614    L: AsLua,
615{
616}
617
618impl<L, T> LuaRead<L> for Option<T>
619where
620    L: AsLua,
621    T: LuaRead<L>,
622{
623    fn lua_read_at_maybe_zero_position(lua: L, index: i32) -> ReadResult<Option<T>, L> {
624        if let Some(index) = NonZeroI32::new(index) {
625            Self::lua_read_at_position(lua, index)
626        } else {
627            Ok(None)
628        }
629    }
630
631    fn lua_read_at_position(lua: L, index: NonZeroI32) -> ReadResult<Option<T>, L> {
632        if unsafe { is_null_or_nil(lua.as_lua(), index.get()) } {
633            return Ok(None);
634        }
635        T::lua_read_at_position(lua, index).map(Some)
636    }
637}
638
639impl<L, A, B> LuaRead<L> for Result<A, B>
640where
641    L: AsLua,
642    A: for<'a> LuaRead<&'a L>,
643    B: for<'b> LuaRead<&'b L>,
644{
645    fn lua_read_at_position(lua: L, index: NonZeroI32) -> ReadResult<Result<A, B>, L> {
646        if let Ok(a) = A::lua_read_at_position(&lua, index) {
647            return Ok(Ok(a));
648        }
649        if let Ok(b) = B::lua_read_at_position(&lua, index) {
650            return Ok(Err(b));
651        }
652        let e = WrongType::default()
653            .expected_type::<Self>()
654            .actual_multiple_lua_at(&lua, index, Self::n_values_expected() as _);
655        Err((lua, e))
656    }
657}
658
659#[derive(
660    Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
661)]
662pub struct Nil;
663
664impl_push_read! {Nil,
665    push_to_lua(&self, lua) {
666        Self::push_into_lua(*self, lua)
667    }
668    push_into_lua(self, lua) {
669        unsafe {
670            ffi::lua_pushnil(lua.as_lua());
671            Ok(PushGuard::new(lua, 1))
672        }
673    }
674    read_at_position(lua, index) {
675        if unsafe { ffi::lua_isnil(lua.as_lua(), index.into()) } {
676            Ok(Nil)
677        } else {
678            let e = WrongType::default()
679                .expected_type::<Self>()
680                .actual_single_lua(&lua, index);
681            Err((lua, e))
682        }
683    }
684    read_at_maybe_zero_position(lua, index) {
685        if let Some(index) = NonZeroI32::new(index) {
686            Self::lua_read_at_position(lua, index)
687        } else {
688            Ok(Nil)
689        }
690    }
691}
692
693#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
694pub struct Null;
695
696impl Null {
697    unsafe fn is_null(lua: crate::LuaState, index: i32) -> bool {
698        if ffi::lua_type(lua, index) == ffi::LUA_TCDATA {
699            let mut ctypeid = MaybeUninit::uninit();
700            let cdata = ffi::luaL_checkcdata(lua, index, ctypeid.as_mut_ptr());
701            if ctypeid.assume_init() == ffi::CTID_P_VOID {
702                return (*cdata.cast::<*const c_void>()).is_null();
703            }
704        }
705        false
706    }
707}
708
709pub unsafe fn is_null_or_nil(lua: crate::LuaState, index: i32) -> bool {
710    ffi::lua_isnil(lua, index) || Null::is_null(lua, index)
711}
712
713impl_push_read! {Null,
714    push_to_lua(&self, lua) {
715        Self::push_into_lua(*self, lua)
716    }
717    push_into_lua(self, lua) {
718        unsafe {
719            let cdata = ffi::luaL_pushcdata(lua.as_lua(), ffi::CTID_P_VOID);
720            *cdata.cast::<*mut c_void>() = null_mut();
721            Ok(PushGuard::new(lua, 1))
722        }
723    }
724    read_at_position(lua, index) {
725        if unsafe { Null::is_null(lua.as_lua(), index.into()) } {
726            Ok(Null)
727        } else {
728            let e = WrongType::default()
729                .expected_type::<Self>()
730                .actual_single_lua(&lua, index);
731            Err((lua, e))
732        }
733    }
734    read_at_maybe_zero_position(lua, index) {
735        if let Some(index) = NonZeroI32::new(index) {
736            Null::lua_read_at_position(lua, index)
737        } else {
738            Ok(Null)
739        }
740    }
741}
742
743#[derive(
744    Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
745)]
746#[serde(try_from = "bool", into = "bool")]
747pub struct True;
748
749impl From<True> for bool {
750    fn from(_: True) -> Self {
751        true
752    }
753}
754
755impl TryFrom<bool> for True {
756    type Error = False;
757    fn try_from(v: bool) -> Result<Self, False> {
758        if v {
759            Ok(True)
760        } else {
761            Err(False)
762        }
763    }
764}
765
766impl_push_read! {True,
767    push_to_lua(&self, lua) {
768        Self::push_into_lua(*self, lua)
769    }
770    push_into_lua(self, lua) {
771        true.push_into_lua(lua)
772    }
773    read_at_position(lua, index) {
774        match bool::lua_read_at_position(&lua, index) {
775            Ok(v) if v => Ok(True),
776            _ => {
777                let e = WrongType::default()
778                    .expected_type::<Self>()
779                    .actual_single_lua(&lua, index);
780                Err((lua, e))
781            }
782        }
783    }
784}
785
786impl std::fmt::Display for True {
787    #[inline(always)]
788    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
789        bool::from(*self).fmt(f)
790    }
791}
792
793#[derive(
794    Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
795)]
796#[serde(try_from = "bool", into = "bool")]
797pub struct False;
798
799impl From<False> for bool {
800    fn from(_: False) -> Self {
801        false
802    }
803}
804
805impl TryFrom<bool> for False {
806    type Error = True;
807    fn try_from(v: bool) -> Result<Self, True> {
808        if !v {
809            Ok(False)
810        } else {
811            Err(True)
812        }
813    }
814}
815
816impl_push_read! {False,
817    push_to_lua(&self, lua) {
818        Self::push_into_lua(*self, lua)
819    }
820    push_into_lua(self, lua) {
821        false.push_into_lua(lua)
822    }
823    read_at_position(lua, index) {
824        match bool::lua_read_at_position(&lua, index) {
825            Ok(v) if !v => Ok(False),
826            _ => {
827                let e = WrongType::default()
828                    .expected_type::<Self>()
829                    .actual_single_lua(&lua, index);
830                Err((lua, e))
831            }
832        }
833    }
834}
835
836impl std::fmt::Display for False {
837    #[inline(always)]
838    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
839        bool::from(*self).fmt(f)
840    }
841}
842
843#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
844pub struct Typename(pub &'static str);
845
846impl Typename {
847    pub fn get(&self) -> &'static str {
848        self.0
849    }
850}
851
852impl_push_read! {Typename,
853    read_at_position(lua, index) {
854        Ok(Self(
855            match crate::typename(lua.as_lua(), index.into()).to_string_lossy() {
856                Cow::Borrowed(s) => s,
857                _ => unreachable!("lua typename is a valid unicode string"),
858            }
859        ))
860    }
861}
862
863/// String wrapper struct that can be used to read a lua value by converting it
864/// to string possibly using `__tostring` metamethod.
865#[derive(Debug, Clone)]
866pub struct ToString(pub String);
867
868impl From<ToString> for String {
869    fn from(other: ToString) -> Self {
870        other.0
871    }
872}
873
874impl From<ToString> for Cow<'_, str> {
875    fn from(other: ToString) -> Self {
876        Cow::Owned(other.0)
877    }
878}
879
880impl std::fmt::Display for ToString {
881    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
882        write!(f, "{}", self.0)
883    }
884}
885
886impl_push_read! {ToString,
887    read_at_position(lua, index) {
888        unsafe {
889            let mut size = MaybeUninit::uninit();
890            let c_ptr = ffi::luaT_tolstring(
891                lua.as_lua(), index.into(), size.as_mut_ptr()
892            );
893            // the newly created string needs to be popped
894            let _new_string = PushGuard::new(lua.as_lua(), 1);
895            if c_ptr.is_null() {
896                let e = WrongType::default()
897                    .expected_type::<Self>()
898                    .actual_single_lua(&lua, index);
899                return Err((lua, e));
900            }
901            let slice = slice::from_raw_parts(c_ptr as _, size.assume_init());
902            Ok(Self(String::from_utf8_lossy(slice).into()))
903        }
904    }
905}