Something went wrong. Try again.
Personal fork of prime agent. Mirror of: https://mnemosyne.sigilzero.dev/sigilzero/prime-agent
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226use std::borrow::Cow;use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};use std::ffi::{CStr, CString, OsStr, OsString};use std::hash::{BuildHasher, Hash};use std::os::raw::c_int;use std::path::{Path, PathBuf};use std::string::String as StdString;use std::{mem, slice, str};
use bstr::{BStr, BString, ByteSlice, ByteVec};use num_traits::cast;
use crate::error::{Error, Result};use crate::function::Function;use crate::state::{Lua, RawLua};use crate::string::{BorrowedBytes, BorrowedStr, String};use crate::table::Table;use crate::thread::Thread;use crate::traits::{FromLua, IntoLua, ShortTypeName as _};use crate::types::{Either, LightUserData, MaybeSend, RegistryKey};use crate::userdata::{AnyUserData, UserData};use crate::value::{Nil, Value};
impl IntoLua for Value { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(self) }}
impl IntoLua for &Value { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(self.clone()) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_value(self) }}
impl FromLua for Value { #[inline] fn from_lua(lua_value: Value, _: &Lua) -> Result<Self> { Ok(lua_value) }}
impl IntoLua for String { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::String(self)) }}
impl IntoLua for &String { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::String(self.clone())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.0); Ok(()) }}
impl FromLua for String { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<String> { let ty = value.type_name(); lua.coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: "string".to_string(), message: Some("expected string or number".to_string()), }) }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { let state = lua.state(); let type_id = ffi::lua_type(state, idx); if type_id == ffi::LUA_TSTRING { ffi::lua_xpush(state, lua.ref_thread(), idx); return Ok(String(lua.pop_ref_thread())); } // Fallback to default Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua()) }}
impl IntoLua for BorrowedStr<'_> { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::String(self.borrow.into_owned())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.borrow.0); Ok(()) }}
impl IntoLua for &BorrowedStr<'_> { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::String(self.borrow.clone().into_owned())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.borrow.0); Ok(()) }}
impl FromLua for BorrowedStr<'_> { fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let s = String::from_lua(value, lua)?; let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?; let buf = unsafe { mem::transmute::<&str, &'static str>(buf) }; let borrow = Cow::Owned(s); Ok(Self { buf, borrow, _lua }) }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { let s = String::from_stack(idx, lua)?; let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?; let buf = unsafe { mem::transmute::<&str, &'static str>(buf) }; let borrow = Cow::Owned(s); Ok(Self { buf, borrow, _lua }) }}
impl IntoLua for BorrowedBytes<'_> { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::String(self.borrow.into_owned())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.borrow.0); Ok(()) }}
impl IntoLua for &BorrowedBytes<'_> { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::String(self.borrow.clone().into_owned())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.borrow.0); Ok(()) }}
impl FromLua for BorrowedBytes<'_> { fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let s = String::from_lua(value, lua)?; let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s); let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) }; let borrow = Cow::Owned(s); Ok(Self { buf, borrow, _lua }) }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { let s = String::from_stack(idx, lua)?; let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s); let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) }; let borrow = Cow::Owned(s); Ok(Self { buf, borrow, _lua }) }}
impl IntoLua for Table { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Table(self)) }}
impl IntoLua for &Table { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Table(self.clone())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.0); Ok(()) }}
impl FromLua for Table { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Table> { match value { Value::Table(table) => Ok(table), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "table".to_string(), message: None, }), } }}
impl IntoLua for Function { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Function(self)) }}
impl IntoLua for &Function { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Function(self.clone())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.0); Ok(()) }}
impl FromLua for Function { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Function> { match value { Value::Function(table) => Ok(table), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "function".to_string(), message: None, }), } }}
impl IntoLua for Thread { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Thread(self)) }}
impl IntoLua for &Thread { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Thread(self.clone())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.0); Ok(()) }}
impl FromLua for Thread { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Thread> { match value { Value::Thread(t) => Ok(t), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "thread".to_string(), message: None, }), } }}
impl IntoLua for AnyUserData { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::UserData(self)) }}
impl IntoLua for &AnyUserData { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::UserData(self.clone())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.0); Ok(()) }}
impl FromLua for AnyUserData { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<AnyUserData> { match value { Value::UserData(ud) => Ok(ud), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "userdata".to_string(), message: None, }), } }}
impl<T: UserData + MaybeSend + 'static> IntoLua for T { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::UserData(lua.create_userdata(self)?)) }}
impl IntoLua for Error { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Error(Box::new(self))) }}
impl FromLua for Error { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Error> { match value { Value::Error(err) => Ok(*err), val => Ok(Error::runtime(val.to_string()?)), } }}
#[cfg(feature = "anyhow")]impl IntoLua for anyhow::Error { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Error(Box::new(Error::from(self)))) }}
impl IntoLua for RegistryKey { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { lua.registry_value(&self) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { <&RegistryKey>::push_into_stack(&self, lua) }}
impl IntoLua for &RegistryKey { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { lua.registry_value(self) }
unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { if !lua.owns_registry_value(self) { return Err(Error::MismatchedRegistryKey); }
match self.id() { ffi::LUA_REFNIL => ffi::lua_pushnil(lua.state()), id => { ffi::lua_rawgeti(lua.state(), ffi::LUA_REGISTRYINDEX, id as _); } } Ok(()) }}
impl FromLua for RegistryKey { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<RegistryKey> { lua.create_registry_value(value) }}
impl IntoLua for bool { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Boolean(self)) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { ffi::lua_pushboolean(lua.state(), self as c_int); Ok(()) }}
impl FromLua for bool { #[inline] fn from_lua(v: Value, _: &Lua) -> Result<Self> { match v { Value::Nil => Ok(false), Value::Boolean(b) => Ok(b), _ => Ok(true), } }
#[inline] unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { Ok(ffi::lua_toboolean(lua.state(), idx) != 0) }}
impl IntoLua for LightUserData { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::LightUserData(self)) }}
impl FromLua for LightUserData { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::LightUserData(ud) => Ok(ud), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "lightuserdata".to_string(), message: None, }), } }}
#[cfg(feature = "luau")]impl IntoLua for crate::Vector { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Vector(self)) }}
#[cfg(feature = "luau")]impl FromLua for crate::Vector { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::Vector(v) => Ok(v), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "vector".to_string(), message: None, }), } }}
#[cfg(feature = "luau")]impl IntoLua for crate::Buffer { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Buffer(self)) }}
#[cfg(feature = "luau")]impl IntoLua for &crate::Buffer { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Buffer(self.clone())) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { lua.push_ref(&self.0); Ok(()) }}
#[cfg(feature = "luau")]impl FromLua for crate::Buffer { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::Buffer(buf) => Ok(buf), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "buffer".to_string(), message: None, }), } }}
impl IntoLua for StdString { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { #[cfg(feature = "lua55")] if true { return Ok(Value::String(lua.create_external_string(self)?)); }
Ok(Value::String(lua.create_string(self)?)) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { #[cfg(feature = "lua55")] if lua.unlikely_memory_error() { return crate::util::push_external_string(lua.state(), self.into(), false); }
push_bytes_into_stack(self, lua) }}
impl FromLua for StdString { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); Ok(lua .coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: Self::type_name(), message: Some("expected string or number".to_string()), })? .to_str()? .to_owned()) }
#[inline] unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { let state = lua.state(); let type_id = ffi::lua_type(state, idx); if type_id == ffi::LUA_TSTRING { let mut size = 0; let data = ffi::lua_tolstring(state, idx, &mut size); let bytes = slice::from_raw_parts(data as *const u8, size); return str::from_utf8(bytes) .map(|s| s.to_owned()) .map_err(|e| Error::FromLuaConversionError { from: "string", to: Self::type_name(), message: Some(e.to_string()), }); } // Fallback to default Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua()) }}
impl IntoLua for &str { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self)?)) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { push_bytes_into_stack(self, lua) }}
impl IntoLua for Cow<'_, str> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self.as_bytes())?)) }}
impl IntoLua for Box<str> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(&*self)?)) }}
impl FromLua for Box<str> { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); Ok(lua .coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: Self::type_name(), message: Some("expected string or number".to_string()), })? .to_str()? .to_owned() .into_boxed_str()) }}
impl IntoLua for CString { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { #[cfg(feature = "lua55")] if true { return Ok(Value::String(lua.create_external_string(self)?)); }
Ok(Value::String(lua.create_string(self.as_bytes())?)) }}
impl FromLua for CString { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); let string = lua .coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: Self::type_name(), message: Some("expected string or number".to_string()), })?;
match CStr::from_bytes_with_nul(&string.as_bytes_with_nul()) { Ok(s) => Ok(s.into()), Err(_) => Err(Error::FromLuaConversionError { from: ty, to: Self::type_name(), message: Some("invalid C-style string".to_string()), }), } }}
impl IntoLua for &CStr { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self.to_bytes())?)) }}
impl IntoLua for Cow<'_, CStr> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self.to_bytes())?)) }}
impl IntoLua for BString { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { #[cfg(feature = "lua55")] if true { return Ok(Value::String(lua.create_external_string(self)?)); }
Ok(Value::String(lua.create_string(self)?)) }}
impl FromLua for BString { fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); match value { Value::String(s) => Ok((*s.as_bytes()).into()), #[cfg(feature = "luau")] Value::Buffer(buf) => Ok(buf.to_vec().into()), _ => Ok((*lua .coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: Self::type_name(), message: Some("expected string or number".to_string()), })? .as_bytes()) .into()), } }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { let state = lua.state(); match ffi::lua_type(state, idx) { ffi::LUA_TSTRING => { let mut size = 0; let data = ffi::lua_tolstring(state, idx, &mut size); Ok(slice::from_raw_parts(data as *const u8, size).into()) } #[cfg(feature = "luau")] ffi::LUA_TBUFFER => { let mut size = 0; let buf = ffi::lua_tobuffer(state, idx, &mut size); mlua_assert!(!buf.is_null(), "invalid Luau buffer"); Ok(slice::from_raw_parts(buf as *const u8, size).into()) } type_id => { // Fallback to default Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua()) } } }}
impl IntoLua for &BStr { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self)?)) }}
impl IntoLua for OsString { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { self.as_os_str().into_lua(lua) }}
impl FromLua for OsString { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); let bs = BString::from_lua(value, lua)?; Vec::from(bs) .into_os_string() .map_err(|err| Error::FromLuaConversionError { from: ty, to: "OsString".into(), message: Some(err.to_string()), }) }}
impl IntoLua for &OsStr { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { let s = <[u8]>::from_os_str(self).ok_or_else(|| Error::ToLuaConversionError { from: "OsStr".into(), to: "string", message: Some("invalid utf-8 encoding".into()), })?; Ok(Value::String(lua.create_string(s)?)) }}
impl IntoLua for PathBuf { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { self.as_os_str().into_lua(lua) }}
impl FromLua for PathBuf { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { OsString::from_lua(value, lua).map(PathBuf::from) }}
impl IntoLua for &Path { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { self.as_os_str().into_lua(lua) }}
impl IntoLua for char { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { let mut char_bytes = [0; 4]; self.encode_utf8(&mut char_bytes); Ok(Value::String(lua.create_string(&char_bytes[..self.len_utf8()])?)) }}
impl FromLua for char { fn from_lua(value: Value, _lua: &Lua) -> Result<Self> { let ty = value.type_name(); match value { Value::Integer(i) => { cast(i) .and_then(char::from_u32) .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: "char".to_string(), message: Some("integer out of range when converting to char".to_string()), }) } Value::String(s) => { let str = s.to_str()?; let mut str_iter = str.chars(); match (str_iter.next(), str_iter.next()) { (Some(char), None) => Ok(char), _ => Err(Error::FromLuaConversionError { from: ty, to: "char".to_string(), message: Some( "expected string to have exactly one char when converting to char".to_string(), ), }), } } _ => Err(Error::FromLuaConversionError { from: ty, to: Self::type_name(), message: Some("expected string or integer".to_string()), }), } }}
#[inline]unsafe fn push_bytes_into_stack<T>(this: T, lua: &RawLua) -> Result<()>where T: IntoLua + AsRef<[u8]>,{ let bytes = this.as_ref(); if lua.unlikely_memory_error() && bytes.len() < (1 << 30) { // Fast path: push directly into the Lua stack. ffi::lua_pushlstring(lua.state(), bytes.as_ptr() as *const _, bytes.len()); return Ok(()); } // Fallback to default lua.push_value(&T::into_lua(this, lua.lua())?)}
macro_rules! lua_convert_int { ($x:ty) => { impl IntoLua for $x { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(cast(self) .map(Value::Integer) .unwrap_or_else(|| Value::Number(self as ffi::lua_Number))) }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { match cast(self) { Some(i) => ffi::lua_pushinteger(lua.state(), i), None => ffi::lua_pushnumber(lua.state(), self as ffi::lua_Number), } Ok(()) } }
impl FromLua for $x { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); (match value { Value::Integer(i) => cast(i), Value::Number(n) => cast(n), _ => { if let Some(i) = lua.coerce_integer(value.clone())? { cast(i) } else { cast( lua.coerce_number(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: stringify!($x).to_string(), message: Some( "expected number or string coercible to number".to_string(), ), })?, ) } } }) .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: stringify!($x).to_string(), message: Some("out of range".to_owned()), }) }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { let state = lua.state(); let type_id = ffi::lua_type(state, idx); if type_id == ffi::LUA_TNUMBER { let mut ok = 0; let i = ffi::lua_tointegerx(state, idx, &mut ok); if ok != 0 { return cast(i).ok_or_else(|| Error::FromLuaConversionError { from: "integer", to: stringify!($x).to_string(), message: Some("out of range".to_owned()), }); } } // Fallback to default Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua()) } } };}
lua_convert_int!(i8);lua_convert_int!(u8);lua_convert_int!(i16);lua_convert_int!(u16);lua_convert_int!(i32);lua_convert_int!(u32);lua_convert_int!(i64);lua_convert_int!(u64);lua_convert_int!(i128);lua_convert_int!(u128);lua_convert_int!(isize);lua_convert_int!(usize);
macro_rules! lua_convert_float { ($x:ty) => { impl IntoLua for $x { #[inline] fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Number(self as _)) } }
impl FromLua for $x { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); lua.coerce_number(value)? .map(|n| n as $x) .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: stringify!($x).to_string(), message: Some("expected number or string coercible to number".to_string()), }) }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { let state = lua.state(); let type_id = ffi::lua_type(state, idx); if type_id == ffi::LUA_TNUMBER { return Ok(ffi::lua_tonumber(state, idx) as _); } // Fallback to default Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua()) } } };}
lua_convert_float!(f32);lua_convert_float!(f64);
impl<T> IntoLua for &[T]where T: IntoLua + Clone,{ #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_sequence_from(self.iter().cloned())?)) }}
impl<T, const N: usize> IntoLua for [T; N]where T: IntoLua,{ #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_sequence_from(self)?)) }}
impl<T, const N: usize> FromLua for [T; N]where T: FromLua,{ #[inline] fn from_lua(value: Value, _lua: &Lua) -> Result<Self> { match value { #[cfg(feature = "luau")] #[rustfmt::skip] Value::Vector(v) if N == crate::Vector::SIZE => unsafe { use std::{mem, ptr}; let mut arr: [mem::MaybeUninit<T>; N] = mem::MaybeUninit::uninit().assume_init(); ptr::write(arr[0].as_mut_ptr() , T::from_lua(Value::Number(v.x() as _), _lua)?); ptr::write(arr[1].as_mut_ptr(), T::from_lua(Value::Number(v.y() as _), _lua)?); ptr::write(arr[2].as_mut_ptr(), T::from_lua(Value::Number(v.z() as _), _lua)?); #[cfg(feature = "luau-vector4")] ptr::write(arr[3].as_mut_ptr(), T::from_lua(Value::Number(v.w() as _), _lua)?); Ok(mem::transmute_copy(&arr)) }, Value::Table(table) => { let vec = table.sequence_values().collect::<Result<Vec<_>>>()?; vec.try_into() .map_err(|vec: Vec<T>| Error::FromLuaConversionError { from: "table", to: Self::type_name(), message: Some(format!("expected table of length {N}, got {}", vec.len())), }) } _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: Self::type_name(), message: Some("expected table".to_string()), }), } }}
impl<T: IntoLua> IntoLua for Box<[T]> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_sequence_from(self.into_vec())?)) }}
impl<T: FromLua> FromLua for Box<[T]> { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { Ok(Vec::<T>::from_lua(value, lua)?.into_boxed_slice()) }}
impl<T: IntoLua> IntoLua for Vec<T> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_sequence_from(self)?)) }}
impl<T: FromLua> FromLua for Vec<T> { #[inline] fn from_lua(value: Value, _lua: &Lua) -> Result<Self> { match value { Value::Table(table) => table.sequence_values().collect(), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: Self::type_name(), message: Some("expected table".to_string()), }), } }}
impl<K: Eq + Hash + IntoLua, V: IntoLua, S: BuildHasher> IntoLua for HashMap<K, V, S> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_table_from(self)?)) }}
impl<K: Eq + Hash + FromLua, V: FromLua, S: BuildHasher + Default> FromLua for HashMap<K, V, S> { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Self> { if let Value::Table(table) = value { table.pairs().collect() } else { Err(Error::FromLuaConversionError { from: value.type_name(), to: Self::type_name(), message: Some("expected table".to_string()), }) } }}
impl<K: Ord + IntoLua, V: IntoLua> IntoLua for BTreeMap<K, V> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_table_from(self)?)) }}
impl<K: Ord + FromLua, V: FromLua> FromLua for BTreeMap<K, V> { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Self> { if let Value::Table(table) = value { table.pairs().collect() } else { Err(Error::FromLuaConversionError { from: value.type_name(), to: Self::type_name(), message: Some("expected table".to_string()), }) } }}
impl<T: Eq + Hash + IntoLua, S: BuildHasher> IntoLua for HashSet<T, S> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table( lua.create_table_from(self.into_iter().map(|val| (val, true)))?, )) }}
impl<T: Eq + Hash + FromLua, S: BuildHasher + Default> FromLua for HashSet<T, S> { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: Self::type_name(), message: Some("expected table".to_string()), }), } }}
impl<T: Ord + IntoLua> IntoLua for BTreeSet<T> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table( lua.create_table_from(self.into_iter().map(|val| (val, true)))?, )) }}
impl<T: Ord + FromLua> FromLua for BTreeSet<T> { #[inline] fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: Self::type_name(), message: Some("expected table".to_string()), }), } }}
impl<T: IntoLua> IntoLua for Option<T> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { match self { Some(val) => val.into_lua(lua), None => Ok(Nil), } }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { match self { Some(val) => val.push_into_stack(lua)?, None => ffi::lua_pushnil(lua.state()), } Ok(()) }}
impl<T: FromLua> FromLua for Option<T> { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { match value { Nil => Ok(None), value => Ok(Some(T::from_lua(value, lua)?)), } }
#[inline] unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { match ffi::lua_type(lua.state(), idx) { ffi::LUA_TNIL => Ok(None), _ => Ok(Some(T::from_stack(idx, lua)?)), } }}
impl<L: IntoLua, R: IntoLua> IntoLua for Either<L, R> { #[inline] fn into_lua(self, lua: &Lua) -> Result<Value> { match self { Either::Left(l) => l.into_lua(lua), Either::Right(r) => r.into_lua(lua), } }
#[inline] unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { match self { Either::Left(l) => l.push_into_stack(lua), Either::Right(r) => r.push_into_stack(lua), } }}
impl<L: FromLua, R: FromLua> FromLua for Either<L, R> { #[inline] fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let value_type_name = value.type_name(); // Try the left type first match L::from_lua(value.clone(), lua) { Ok(l) => Ok(Either::Left(l)), // Try the right type Err(_) => match R::from_lua(value, lua).map(Either::Right) { Ok(r) => Ok(r), Err(_) => Err(Error::FromLuaConversionError { from: value_type_name, to: Self::type_name(), message: None, }), }, } }
#[inline] unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { match L::from_stack(idx, lua) { Ok(l) => Ok(Either::Left(l)), Err(_) => match R::from_stack(idx, lua).map(Either::Right) { Ok(r) => Ok(r), Err(_) => { let value_type_name = CStr::from_ptr(ffi::lua_typename(lua.state(), ffi::lua_type(lua.state(), idx))); Err(Error::FromLuaConversionError { from: value_type_name.to_str().unwrap(), to: Self::type_name(), message: None, }) } }, } }}