playdate_lua/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3// #[macro_use]
4extern crate sys;
5extern crate alloc;
6
7use core::ffi::c_char;
8use alloc::borrow::ToOwned;
9
10use sys::ffi::CStr;
11use sys::ffi::CString;
12use sys::ffi::lua_CFunction;
13
14
15pub mod error;
16
17use error::*;
18
19#[derive(Debug, Clone, Copy)]
20pub struct Lua<Api = api::Default>(Api);
21
22impl Lua<api::Default> {
23	/// Creates default [`Lua`] without type parameter requirement.
24	///
25	/// Uses ZST [`api::Default`].
26	#[allow(non_snake_case)]
27	pub fn Default() -> Self { Self(Default::default()) }
28}
29
30impl Lua<api::Cache> {
31	/// Creates [`Lua`] without type parameter requirement.
32	///
33	/// Uses [`api::Cache`].
34	#[allow(non_snake_case)]
35	pub fn Cached() -> Self { Self(Default::default()) }
36}
37
38impl<Api: Default + api::Api> Default for Lua<Api> {
39	fn default() -> Self { Self(Default::default()) }
40}
41
42impl<Api: Default + api::Api> Lua<Api> {
43	pub fn new() -> Self { Self(Default::default()) }
44}
45
46impl<Api: api::Api> Lua<Api> {
47	pub fn new_with(api: Api) -> Self { Self(api) }
48}
49
50
51impl Lua<api::Default> {}
52
53
54impl<Api: api::Api> Lua<Api> {
55	/// Adds the Lua function *f* to the Lua runtime, with name *name*. (*name*
56	/// can be a table path using dots, e.g. if name = “mycode.myDrawingFunction”
57	/// adds the function “myDrawingFunction” to the global table “myCode”.)
58	///
59	/// Equivalent to [`sys::ffi::playdate_lua::addFunction`]
60	#[doc(alias = "sys::ffi::playdate_lua::addFunction")]
61	pub fn add_function<S: AsRef<str>>(&self, f: lua_CFunction, name: S) -> Result<(), ApiError> {
62		let name = CString::new(name.as_ref())?;
63		let mut out_err: *const c_char = core::ptr::null_mut();
64
65		let func = self.0.add_function();
66
67		// Returns 1 on success or 0 with an error message in *outErr*.
68		let result = unsafe { func(f, name.as_ptr(), &mut out_err) };
69
70		if result == 0 {
71			let err_msg = unsafe { CStr::from_ptr(out_err) };
72			Err(Error::AddFunction(err_msg.to_owned()).into())
73		} else {
74			Ok(())
75		}
76	}
77
78	/// Returns the argument at position *pos* as a string.
79	///
80	/// Equivalent to [`sys::ffi::playdate_lua::getArgString`]
81	#[doc(alias = "sys::ffi::playdate_lua::getArgString")]
82	pub fn get_arg_string(&self, pos: i32) -> Option<CString> {
83		let f = self.0.get_arg_string();
84		unsafe {
85			let ptr = f(pos);
86			if ptr.is_null() {
87				None
88			} else {
89				Some(CStr::from_ptr(ptr).to_owned())
90			}
91		}
92	}
93}
94
95pub mod api {
96	use core::ffi::c_char;
97	use core::ffi::c_int;
98	use core::ptr::NonNull;
99	use sys::ffi::lua_CFunction;
100	use sys::ffi::playdate_lua;
101
102
103	/// Default lua api end-point, ZST.
104	///
105	/// All calls approximately costs ~3 derefs.
106	#[derive(Debug, Clone, Copy, core::default::Default)]
107	pub struct Default;
108	impl Api for Default {}
109
110
111	/// Cached lua api end-point.
112	///
113	/// Stores one reference, so size on stack is eq `usize`.
114	///
115	/// All calls approximately costs ~1 deref.
116	#[derive(Clone, Copy)]
117	#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
118	pub struct Cache(&'static playdate_lua);
119
120	impl core::default::Default for Cache {
121		fn default() -> Self { Self(sys::api!(lua)) }
122	}
123
124	impl From<*const playdate_lua> for Cache {
125		#[inline(always)]
126		fn from(ptr: *const playdate_lua) -> Self { Self(unsafe { ptr.as_ref() }.expect("lua")) }
127	}
128
129	impl From<&'static playdate_lua> for Cache {
130		#[inline(always)]
131		fn from(r: &'static playdate_lua) -> Self { Self(r) }
132	}
133
134	impl From<NonNull<playdate_lua>> for Cache {
135		#[inline(always)]
136		fn from(ptr: NonNull<playdate_lua>) -> Self { Self(unsafe { ptr.as_ref() }) }
137	}
138
139	impl From<&'_ NonNull<playdate_lua>> for Cache {
140		#[inline(always)]
141		fn from(ptr: &NonNull<playdate_lua>) -> Self { Self(unsafe { ptr.as_ref() }) }
142	}
143
144
145	impl Api for Cache {
146		#[inline(always)]
147		fn add_function(
148			&self)
149			-> unsafe extern "C" fn(f: lua_CFunction, name: *const c_char, outErr: *mut *const c_char) -> c_int {
150			self.0.addFunction.expect("addFunction")
151		}
152
153		#[inline(always)]
154		fn get_arg_string(&self) -> unsafe extern "C" fn(pos: c_int) -> *const c_char {
155			self.0.getArgString.expect("getArgString")
156		}
157	}
158
159
160	pub trait Api {
161		/// Returns [`sys::ffi::playdate_lua::addFunction`]
162		#[doc(alias = "sys::ffi::playdate_lua::addFunction")]
163		fn add_function(
164			&self)
165			-> unsafe extern "C" fn(f: lua_CFunction, name: *const c_char, outErr: *mut *const c_char) -> c_int {
166			*sys::api!(lua.addFunction)
167		}
168		/// Returns [`sys::ffi::playdate_lua::getArgString`]
169		#[doc(alias = "sys::ffi::playdate_lua::getArgString")]
170		fn get_arg_string(&self) -> unsafe extern "C" fn(pos: c_int) -> *const c_char {
171			*sys::api!(lua.getArgString)
172		}
173	}
174}