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; #[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; #[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#[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; #[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; #[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 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#[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#[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 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}