Refactor export tables for roblox builtin library

This commit is contained in:
Filip Tibell 2023-08-23 14:53:52 -05:00
parent 57e2072bc0
commit de0f017540
No known key found for this signature in database
27 changed files with 999 additions and 837 deletions

View file

@ -16,6 +16,8 @@ pub struct LuneError {
disable_colors: bool, disable_colors: bool,
} }
// TODO: Rename this struct to "RuntimeError" instead for
// the next breaking release, it's a more fitting name
impl LuneError { impl LuneError {
/** /**
Enables colorization of the error message when formatted using the [`Display`] trait. Enables colorization of the error message when formatted using the [`Display`] trait.

View file

@ -6,12 +6,16 @@ mod builtins;
mod error; mod error;
mod globals; mod globals;
mod scheduler; mod scheduler;
mod util;
pub(crate) mod util;
use self::scheduler::{LuaSchedulerExt, Scheduler}; use self::scheduler::{LuaSchedulerExt, Scheduler};
pub use error::LuneError; pub use error::LuneError;
// TODO: Rename this struct to "Runtime" instead for the
// next breaking release, it's a more fitting name and
// will probably be more obvious when browsing files
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Lune { pub struct Lune {
lua: &'static Lua, lua: &'static Lua,

View file

@ -3,6 +3,8 @@ use core::fmt;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Axes as DomAxes; use rbx_dom_weak::types::Axes as DomAxes;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, EnumItem}; use super::{super::*, EnumItem};
/** /**
@ -17,53 +19,58 @@ pub struct Axes {
pub(crate) z: bool, pub(crate) z: bool,
} }
impl Axes { impl LuaExportsTable<'_> for Axes {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Axes";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, args: LuaMultiValue| { let axes_new = |_, args: LuaMultiValue| {
let mut x = false; let mut x = false;
let mut y = false; let mut y = false;
let mut z = false; let mut z = false;
let mut check = |e: &EnumItem| {
if e.parent.desc.name == "Axis" { let mut check = |e: &EnumItem| {
match &e.name { if e.parent.desc.name == "Axis" {
name if name == "X" => x = true, match &e.name {
name if name == "Y" => y = true, name if name == "X" => x = true,
name if name == "Z" => z = true, name if name == "Y" => y = true,
_ => {} name if name == "Z" => z = true,
} _ => {}
} else if e.parent.desc.name == "NormalId" {
match &e.name {
name if name == "Left" || name == "Right" => x = true,
name if name == "Top" || name == "Bottom" => y = true,
name if name == "Front" || name == "Back" => z = true,
_ => {}
}
} }
}; } else if e.parent.desc.name == "NormalId" {
for (index, arg) in args.into_iter().enumerate() { match &e.name {
if let LuaValue::UserData(u) = arg { name if name == "Left" || name == "Right" => x = true,
if let Ok(e) = u.borrow::<EnumItem>() { name if name == "Top" || name == "Bottom" => y = true,
check(&e); name if name == "Front" || name == "Back" => z = true,
} else { _ => {}
return Err(LuaError::RuntimeError(format!(
"Expected argument #{} to be an EnumItem, got userdata",
index
)));
}
} else {
return Err(LuaError::RuntimeError(format!(
"Expected argument #{} to be an EnumItem, got {}",
index,
arg.type_name()
)));
} }
} }
Ok(Axes { x, y, z }) };
})?,
)?; for (index, arg) in args.into_iter().enumerate() {
Ok(()) if let LuaValue::UserData(u) = arg {
if let Ok(e) = u.borrow::<EnumItem>() {
check(&e);
} else {
return Err(LuaError::RuntimeError(format!(
"Expected argument #{} to be an EnumItem, got userdata",
index
)));
}
} else {
return Err(LuaError::RuntimeError(format!(
"Expected argument #{} to be an EnumItem, got {}",
index,
arg.type_name()
)));
}
}
Ok(Axes { x, y, z })
};
TableBuilder::new(lua)?
.with_function("new", axes_new)?
.build_readonly()
} }
} }

View file

@ -4,6 +4,8 @@ use mlua::prelude::*;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rbx_dom_weak::types::BrickColor as DomBrickColor; use rbx_dom_weak::types::BrickColor as DomBrickColor;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, Color3}; use super::{super::*, Color3};
/** /**
@ -20,57 +22,58 @@ pub struct BrickColor {
pub(crate) rgb: (u8, u8, u8), pub(crate) rgb: (u8, u8, u8),
} }
impl BrickColor { impl LuaExportsTable<'_> for BrickColor {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "BrickColor";
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
type ArgsNumber = u16; type ArgsNumber = u16;
type ArgsName = String; type ArgsName = String;
type ArgsRgb = (u8, u8, u8); type ArgsRgb = (u8, u8, u8);
type ArgsColor3<'lua> = LuaUserDataRef<'lua, Color3>; type ArgsColor3<'lua> = LuaUserDataRef<'lua, Color3>;
datatype_table.set(
"new", let brick_color_new = |lua, args: LuaMultiValue| {
lua.create_function(|lua, args: LuaMultiValue| { if let Ok(number) = ArgsNumber::from_lua_multi(args.clone(), lua) {
if let Ok(number) = ArgsNumber::from_lua_multi(args.clone(), lua) { Ok(color_from_number(number))
Ok(color_from_number(number)) } else if let Ok(name) = ArgsName::from_lua_multi(args.clone(), lua) {
} else if let Ok(name) = ArgsName::from_lua_multi(args.clone(), lua) { Ok(color_from_name(name))
Ok(color_from_name(name)) } else if let Ok((r, g, b)) = ArgsRgb::from_lua_multi(args.clone(), lua) {
} else if let Ok((r, g, b)) = ArgsRgb::from_lua_multi(args.clone(), lua) { Ok(color_from_rgb(r, g, b))
Ok(color_from_rgb(r, g, b)) } else if let Ok(color) = ArgsColor3::from_lua_multi(args.clone(), lua) {
} else if let Ok(color) = ArgsColor3::from_lua_multi(args.clone(), lua) { Ok(Self::from(*color))
Ok(Self::from(*color)) } else {
} else { // FUTURE: Better error message here using given arg types
// FUTURE: Better error message here using given arg types Err(LuaError::RuntimeError(
Err(LuaError::RuntimeError( "Invalid arguments to constructor".to_string(),
"Invalid arguments to constructor".to_string(), ))
)) }
} };
})?,
)?; let brick_color_palette = |_, index: u16| {
datatype_table.set( if index == 0 {
"palette", Err(LuaError::RuntimeError("Invalid index".to_string()))
lua.create_function(|_, index: u16| { } else if let Some(number) = BRICK_COLOR_PALETTE.get((index - 1) as usize) {
if index == 0 { Ok(color_from_number(*number))
Err(LuaError::RuntimeError("Invalid index".to_string())) } else {
} else if let Some(number) = BRICK_COLOR_PALETTE.get((index - 1) as usize) { Err(LuaError::RuntimeError("Invalid index".to_string()))
Ok(color_from_number(*number)) }
} else { };
Err(LuaError::RuntimeError("Invalid index".to_string()))
} let brick_color_random = |_, ()| {
})?, let number = BRICK_COLOR_PALETTE.choose(&mut rand::thread_rng());
)?; Ok(color_from_number(*number.unwrap()))
datatype_table.set( };
"random",
lua.create_function(|_, ()| { let mut builder = TableBuilder::new(lua)?
let number = BRICK_COLOR_PALETTE.choose(&mut rand::thread_rng()); .with_function("new", brick_color_new)?
Ok(color_from_number(*number.unwrap())) .with_function("palette", brick_color_palette)?
})?, .with_function("random", brick_color_random)?;
)?;
for (name, number) in BRICK_COLOR_CONSTRUCTORS { for (name, number) in BRICK_COLOR_CONSTRUCTORS {
datatype_table.set( let f = |_, ()| Ok(color_from_number(*number));
*name, builder = builder.with_function(*name, f)?;
lua.create_function(|_, ()| Ok(color_from_number(*number)))?,
)?;
} }
Ok(())
builder.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use glam::{EulerRot, Mat4, Quat, Vec3};
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::{CFrame as DomCFrame, Matrix3 as DomMatrix3, Vector3 as DomVector3}; use rbx_dom_weak::types::{CFrame as DomCFrame, Matrix3 as DomMatrix3, Vector3 as DomVector3};
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, Vector3}; use super::{super::*, Vector3};
/** /**
@ -35,79 +37,61 @@ impl CFrame {
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
Self(self.0.inverse()) Self(self.0.inverse())
} }
}
impl LuaExportsTable<'_> for CFrame {
const EXPORT_NAME: &'static str = "CFrame";
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
let cframe_angles = |_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
};
let cframe_from_axis_angle =
|_, (v, r): (LuaUserDataRef<Vector3>, f32)| Ok(CFrame(Mat4::from_axis_angle(v.0, r)));
let cframe_from_euler_angles_xyz = |_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
};
let cframe_from_euler_angles_yxz = |_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
};
let cframe_from_matrix = |_,
(pos, rx, ry, rz): (
LuaUserDataRef<Vector3>,
LuaUserDataRef<Vector3>,
LuaUserDataRef<Vector3>,
Option<LuaUserDataRef<Vector3>>,
)| {
Ok(CFrame(Mat4::from_cols(
rx.0.extend(0.0),
ry.0.extend(0.0),
rz.map(|r| r.0)
.unwrap_or_else(|| rx.0.cross(ry.0).normalize())
.extend(0.0),
pos.0.extend(1.0),
)))
};
let cframe_from_orientation = |_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
};
let cframe_look_at = |_,
(from, to, up): (
LuaUserDataRef<Vector3>,
LuaUserDataRef<Vector3>,
Option<LuaUserDataRef<Vector3>>,
)| {
Ok(CFrame(look_at(
from.0,
to.0,
up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0,
)))
};
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
// Constants
datatype_table.set("identity", CFrame(Mat4::IDENTITY))?;
// Strict args constructors
datatype_table.set(
"lookAt",
lua.create_function(
|_,
(from, to, up): (
LuaUserDataRef<Vector3>,
LuaUserDataRef<Vector3>,
Option<LuaUserDataRef<Vector3>>,
)| {
Ok(CFrame(look_at(
from.0,
to.0,
up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0,
)))
},
)?,
)?;
datatype_table.set(
"fromEulerAnglesXYZ",
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
})?,
)?;
datatype_table.set(
"fromEulerAnglesYXZ",
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
})?,
)?;
datatype_table.set(
"Angles",
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
})?,
)?;
datatype_table.set(
"fromOrientation",
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
})?,
)?;
datatype_table.set(
"fromAxisAngle",
lua.create_function(|_, (v, r): (LuaUserDataRef<Vector3>, f32)| {
Ok(CFrame(Mat4::from_axis_angle(v.0, r)))
})?,
)?;
datatype_table.set(
"fromMatrix",
lua.create_function(
|_,
(pos, rx, ry, rz): (
LuaUserDataRef<Vector3>,
LuaUserDataRef<Vector3>,
LuaUserDataRef<Vector3>,
Option<LuaUserDataRef<Vector3>>,
)| {
Ok(CFrame(Mat4::from_cols(
rx.0.extend(0.0),
ry.0.extend(0.0),
rz.map(|r| r.0)
.unwrap_or_else(|| rx.0.cross(ry.0).normalize())
.extend(0.0),
pos.0.extend(1.0),
)))
},
)?,
)?;
// Dynamic args constructor // Dynamic args constructor
type ArgsPos<'lua> = LuaUserDataRef<'lua, Vector3>; type ArgsPos<'lua> = LuaUserDataRef<'lua, Vector3>;
type ArgsLook<'lua> = ( type ArgsLook<'lua> = (
@ -115,48 +99,59 @@ impl CFrame {
LuaUserDataRef<'lua, Vector3>, LuaUserDataRef<'lua, Vector3>,
Option<LuaUserDataRef<'lua, Vector3>>, Option<LuaUserDataRef<'lua, Vector3>>,
); );
type ArgsPosXYZ = (f32, f32, f32); type ArgsPosXYZ = (f32, f32, f32);
type ArgsPosXYZQuat = (f32, f32, f32, f32, f32, f32, f32); type ArgsPosXYZQuat = (f32, f32, f32, f32, f32, f32, f32);
type ArgsMatrix = (f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32); type ArgsMatrix = (f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32);
datatype_table.set(
"new", let cframe_new = |lua, args: LuaMultiValue| {
lua.create_function(|lua, args: LuaMultiValue| { if args.clone().into_vec().is_empty() {
if args.clone().into_vec().is_empty() { Ok(CFrame(Mat4::IDENTITY))
Ok(CFrame(Mat4::IDENTITY)) } else if let Ok(pos) = ArgsPos::from_lua_multi(args.clone(), lua) {
} else if let Ok(pos) = ArgsPos::from_lua_multi(args.clone(), lua) { Ok(CFrame(Mat4::from_translation(pos.0)))
Ok(CFrame(Mat4::from_translation(pos.0))) } else if let Ok((from, to, up)) = ArgsLook::from_lua_multi(args.clone(), lua) {
} else if let Ok((from, to, up)) = ArgsLook::from_lua_multi(args.clone(), lua) { Ok(CFrame(look_at(
Ok(CFrame(look_at( from.0,
from.0, to.0,
to.0, up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0,
up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0, )))
))) } else if let Ok((x, y, z)) = ArgsPosXYZ::from_lua_multi(args.clone(), lua) {
} else if let Ok((x, y, z)) = ArgsPosXYZ::from_lua_multi(args.clone(), lua) { Ok(CFrame(Mat4::from_translation(Vec3::new(x, y, z))))
Ok(CFrame(Mat4::from_translation(Vec3::new(x, y, z)))) } else if let Ok((x, y, z, qx, qy, qz, qw)) =
} else if let Ok((x, y, z, qx, qy, qz, qw)) = ArgsPosXYZQuat::from_lua_multi(args.clone(), lua)
ArgsPosXYZQuat::from_lua_multi(args.clone(), lua) {
{ Ok(CFrame(Mat4::from_rotation_translation(
Ok(CFrame(Mat4::from_rotation_translation( Quat::from_array([qx, qy, qz, qw]),
Quat::from_array([qx, qy, qz, qw]), Vec3::new(x, y, z),
Vec3::new(x, y, z), )))
))) } else if let Ok((x, y, z, r00, r01, r02, r10, r11, r12, r20, r21, r22)) =
} else if let Ok((x, y, z, r00, r01, r02, r10, r11, r12, r20, r21, r22)) = ArgsMatrix::from_lua_multi(args, lua)
ArgsMatrix::from_lua_multi(args, lua) {
{ Ok(CFrame(Mat4::from_cols_array_2d(&[
Ok(CFrame(Mat4::from_cols_array_2d(&[ [r00, r01, r02, 0.0],
[r00, r01, r02, 0.0], [r10, r11, r12, 0.0],
[r10, r11, r12, 0.0], [r20, r21, r22, 0.0],
[r20, r21, r22, 0.0], [x, y, z, 1.0],
[x, y, z, 1.0], ])))
]))) } else {
} else { // FUTURE: Better error message here using given arg types
// FUTURE: Better error message here using given arg types Err(LuaError::RuntimeError(
Err(LuaError::RuntimeError( "Invalid arguments to constructor".to_string(),
"Invalid arguments to constructor".to_string(), ))
)) }
} };
})?,
) TableBuilder::new(lua)?
.with_function("Angles", cframe_angles)?
.with_value("identity", CFrame(Mat4::IDENTITY))?
.with_function("fromAxisAngle", cframe_from_axis_angle)?
.with_function("fromEulerAnglesXYZ", cframe_from_euler_angles_xyz)?
.with_function("fromEulerAnglesYXZ", cframe_from_euler_angles_yxz)?
.with_function("fromMatrix", cframe_from_matrix)?
.with_function("fromOrientation", cframe_from_orientation)?
.with_function("lookAt", cframe_look_at)?
.with_function("new", cframe_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use glam::Vec3;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::{Color3 as DomColor3, Color3uint8 as DomColor3uint8}; use rbx_dom_weak::types::{Color3 as DomColor3, Color3uint8 as DomColor3uint8};
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::super::*; use super::super::*;
/** /**
@ -22,88 +24,87 @@ pub struct Color3 {
pub(crate) b: f32, pub(crate) b: f32,
} }
impl Color3 { impl LuaExportsTable<'_> for Color3 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Color3";
datatype_table.set(
"new",
lua.create_function(|_, (r, g, b): (Option<f32>, Option<f32>, Option<f32>)| {
Ok(Color3 {
r: r.unwrap_or_default(),
g: g.unwrap_or_default(),
b: b.unwrap_or_default(),
})
})?,
)?;
datatype_table.set(
"fromRGB",
lua.create_function(|_, (r, g, b): (Option<u8>, Option<u8>, Option<u8>)| {
Ok(Color3 {
r: (r.unwrap_or_default() as f32) / 255f32,
g: (g.unwrap_or_default() as f32) / 255f32,
b: (b.unwrap_or_default() as f32) / 255f32,
})
})?,
)?;
datatype_table.set(
"fromHSV",
lua.create_function(|_, (h, s, v): (f32, f32, f32)| {
// https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
let i = (h * 6.0).floor();
let f = h * 6.0 - i;
let p = v * (1.0 - s);
let q = v * (1.0 - f * s);
let t = v * (1.0 - (1.0 - f) * s);
let (r, g, b) = match (i % 6.0) as u8 { fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
0 => (v, t, p), let color3_from_rgb = |_, (r, g, b): (Option<u8>, Option<u8>, Option<u8>)| {
1 => (q, v, p), Ok(Color3 {
2 => (p, v, t), r: (r.unwrap_or_default() as f32) / 255f32,
3 => (p, q, v), g: (g.unwrap_or_default() as f32) / 255f32,
4 => (t, p, v), b: (b.unwrap_or_default() as f32) / 255f32,
5 => (v, p, q), })
_ => unreachable!(), };
};
Ok(Color3 { r, g, b }) let color3_from_hsv = |_, (h, s, v): (f32, f32, f32)| {
})?, // https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
)?; let i = (h * 6.0).floor();
datatype_table.set( let f = h * 6.0 - i;
"fromHex", let p = v * (1.0 - s);
lua.create_function(|_, hex: String| { let q = v * (1.0 - f * s);
let trimmed = hex.trim_start_matches('#').to_ascii_uppercase(); let t = v * (1.0 - (1.0 - f) * s);
let chars = if trimmed.len() == 3 {
( let (r, g, b) = match (i % 6.0) as u8 {
u8::from_str_radix(&trimmed[..1].repeat(2), 16), 0 => (v, t, p),
u8::from_str_radix(&trimmed[1..2].repeat(2), 16), 1 => (q, v, p),
u8::from_str_radix(&trimmed[2..3].repeat(2), 16), 2 => (p, v, t),
) 3 => (p, q, v),
} else if trimmed.len() == 6 { 4 => (t, p, v),
( 5 => (v, p, q),
u8::from_str_radix(&trimmed[..2], 16), _ => unreachable!(),
u8::from_str_radix(&trimmed[2..4], 16), };
u8::from_str_radix(&trimmed[4..6], 16),
) Ok(Color3 { r, g, b })
} else { };
return Err(LuaError::RuntimeError(format!(
"Hex color string must be 3 or 6 characters long, got {} character{}", let color3_from_hex = |_, hex: String| {
trimmed.len(), let trimmed = hex.trim_start_matches('#').to_ascii_uppercase();
if trimmed.len() == 1 { "" } else { "s" } let chars = if trimmed.len() == 3 {
))); (
}; u8::from_str_radix(&trimmed[..1].repeat(2), 16),
match chars { u8::from_str_radix(&trimmed[1..2].repeat(2), 16),
(Ok(r), Ok(g), Ok(b)) => Ok(Color3 { u8::from_str_radix(&trimmed[2..3].repeat(2), 16),
r: (r as f32) / 255f32, )
g: (g as f32) / 255f32, } else if trimmed.len() == 6 {
b: (b as f32) / 255f32, (
}), u8::from_str_radix(&trimmed[..2], 16),
_ => Err(LuaError::RuntimeError(format!( u8::from_str_radix(&trimmed[2..4], 16),
"Hex color string '{}' contains invalid character", u8::from_str_radix(&trimmed[4..6], 16),
trimmed )
))), } else {
} return Err(LuaError::RuntimeError(format!(
})?, "Hex color string must be 3 or 6 characters long, got {} character{}",
)?; trimmed.len(),
Ok(()) if trimmed.len() == 1 { "" } else { "s" }
)));
};
match chars {
(Ok(r), Ok(g), Ok(b)) => Ok(Color3 {
r: (r as f32) / 255f32,
g: (g as f32) / 255f32,
b: (b as f32) / 255f32,
}),
_ => Err(LuaError::RuntimeError(format!(
"Hex color string '{}' contains invalid character",
trimmed
))),
}
};
let color3_new = |_, (r, g, b): (Option<f32>, Option<f32>, Option<f32>)| {
Ok(Color3 {
r: r.unwrap_or_default(),
g: g.unwrap_or_default(),
b: b.unwrap_or_default(),
})
};
TableBuilder::new(lua)?
.with_function("fromRGB", color3_from_rgb)?
.with_function("fromHSV", color3_from_hsv)?
.with_function("fromHex", color3_from_hex)?
.with_function("new", color3_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use rbx_dom_weak::types::{
ColorSequence as DomColorSequence, ColorSequenceKeypoint as DomColorSequenceKeypoint, ColorSequence as DomColorSequence, ColorSequenceKeypoint as DomColorSequenceKeypoint,
}; };
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, Color3, ColorSequenceKeypoint}; use super::{super::*, Color3, ColorSequenceKeypoint};
/** /**
@ -17,52 +19,56 @@ pub struct ColorSequence {
pub(crate) keypoints: Vec<ColorSequenceKeypoint>, pub(crate) keypoints: Vec<ColorSequenceKeypoint>,
} }
impl ColorSequence { impl LuaExportsTable<'_> for ColorSequence {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "ColorSequence";
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
type ArgsColor<'lua> = LuaUserDataRef<'lua, Color3>; type ArgsColor<'lua> = LuaUserDataRef<'lua, Color3>;
type ArgsColors<'lua> = (LuaUserDataRef<'lua, Color3>, LuaUserDataRef<'lua, Color3>); type ArgsColors<'lua> = (LuaUserDataRef<'lua, Color3>, LuaUserDataRef<'lua, Color3>);
type ArgsKeypoints<'lua> = Vec<LuaUserDataRef<'lua, ColorSequenceKeypoint>>; type ArgsKeypoints<'lua> = Vec<LuaUserDataRef<'lua, ColorSequenceKeypoint>>;
datatype_table.set(
"new", let color_sequence_new = |lua, args: LuaMultiValue| {
lua.create_function(|lua, args: LuaMultiValue| { if let Ok(color) = ArgsColor::from_lua_multi(args.clone(), lua) {
if let Ok(color) = ArgsColor::from_lua_multi(args.clone(), lua) { Ok(ColorSequence {
Ok(ColorSequence { keypoints: vec![
keypoints: vec![ ColorSequenceKeypoint {
ColorSequenceKeypoint { time: 0.0,
time: 0.0, color: *color,
color: *color, },
}, ColorSequenceKeypoint {
ColorSequenceKeypoint { time: 1.0,
time: 1.0, color: *color,
color: *color, },
}, ],
], })
}) } else if let Ok((c0, c1)) = ArgsColors::from_lua_multi(args.clone(), lua) {
} else if let Ok((c0, c1)) = ArgsColors::from_lua_multi(args.clone(), lua) { Ok(ColorSequence {
Ok(ColorSequence { keypoints: vec![
keypoints: vec![ ColorSequenceKeypoint {
ColorSequenceKeypoint { time: 0.0,
time: 0.0, color: *c0,
color: *c0, },
}, ColorSequenceKeypoint {
ColorSequenceKeypoint { time: 1.0,
time: 1.0, color: *c1,
color: *c1, },
}, ],
], })
}) } else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) {
} else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) { Ok(ColorSequence {
Ok(ColorSequence { keypoints: keypoints.iter().map(|k| **k).collect(),
keypoints: keypoints.iter().map(|k| **k).collect(), })
}) } else {
} else { // FUTURE: Better error message here using given arg types
// FUTURE: Better error message here using given arg types Err(LuaError::RuntimeError(
Err(LuaError::RuntimeError( "Invalid arguments to constructor".to_string(),
"Invalid arguments to constructor".to_string(), ))
)) }
} };
})?,
) TableBuilder::new(lua)?
.with_function("new", color_sequence_new)?
.build_readonly()
} }
} }

View file

@ -3,6 +3,8 @@ use core::fmt;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::ColorSequenceKeypoint as DomColorSequenceKeypoint; use rbx_dom_weak::types::ColorSequenceKeypoint as DomColorSequenceKeypoint;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, Color3}; use super::{super::*, Color3};
/** /**
@ -16,18 +18,20 @@ pub struct ColorSequenceKeypoint {
pub(crate) color: Color3, pub(crate) color: Color3,
} }
impl ColorSequenceKeypoint { impl LuaExportsTable<'_> for ColorSequenceKeypoint {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "ColorSequenceKeypoint";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, (time, color): (f32, LuaUserDataRef<Color3>)| { let color_sequence_keypoint_new = |_, (time, color): (f32, LuaUserDataRef<Color3>)| {
Ok(ColorSequenceKeypoint { Ok(ColorSequenceKeypoint {
time, time,
color: *color, color: *color,
}) })
})?, };
)?;
Ok(()) TableBuilder::new(lua)?
.with_function("new", color_sequence_keypoint_new)?
.build_readonly()
} }
} }

View file

@ -3,6 +3,8 @@ use core::fmt;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Faces as DomFaces; use rbx_dom_weak::types::Faces as DomFaces;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, EnumItem}; use super::{super::*, EnumItem};
/** /**
@ -20,59 +22,64 @@ pub struct Faces {
pub(crate) front: bool, pub(crate) front: bool,
} }
impl Faces { impl LuaExportsTable<'_> for Faces {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Faces";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, args: LuaMultiValue| { let faces_new = |_, args: LuaMultiValue| {
let mut right = false; let mut right = false;
let mut top = false; let mut top = false;
let mut back = false; let mut back = false;
let mut left = false; let mut left = false;
let mut bottom = false; let mut bottom = false;
let mut front = false; let mut front = false;
let mut check = |e: &EnumItem| {
if e.parent.desc.name == "NormalId" { let mut check = |e: &EnumItem| {
match &e.name { if e.parent.desc.name == "NormalId" {
name if name == "Right" => right = true, match &e.name {
name if name == "Top" => top = true, name if name == "Right" => right = true,
name if name == "Back" => back = true, name if name == "Top" => top = true,
name if name == "Left" => left = true, name if name == "Back" => back = true,
name if name == "Bottom" => bottom = true, name if name == "Left" => left = true,
name if name == "Front" => front = true, name if name == "Bottom" => bottom = true,
_ => {} name if name == "Front" => front = true,
} _ => {}
}
};
for (index, arg) in args.into_iter().enumerate() {
if let LuaValue::UserData(u) = arg {
if let Ok(e) = u.borrow::<EnumItem>() {
check(&e);
} else {
return Err(LuaError::RuntimeError(format!(
"Expected argument #{} to be an EnumItem, got userdata",
index
)));
}
} else {
return Err(LuaError::RuntimeError(format!(
"Expected argument #{} to be an EnumItem, got {}",
index,
arg.type_name()
)));
} }
} }
Ok(Faces { };
right,
top, for (index, arg) in args.into_iter().enumerate() {
back, if let LuaValue::UserData(u) = arg {
left, if let Ok(e) = u.borrow::<EnumItem>() {
bottom, check(&e);
front, } else {
}) return Err(LuaError::RuntimeError(format!(
})?, "Expected argument #{} to be an EnumItem, got userdata",
)?; index
Ok(()) )));
}
} else {
return Err(LuaError::RuntimeError(format!(
"Expected argument #{} to be an EnumItem, got {}",
index,
arg.type_name()
)));
}
}
Ok(Faces {
right,
top,
back,
left,
bottom,
front,
})
};
TableBuilder::new(lua)?
.with_function("new", faces_new)?
.build_readonly()
} }
} }

View file

@ -6,6 +6,8 @@ use rbx_dom_weak::types::{
Font as DomFont, FontStyle as DomFontStyle, FontWeight as DomFontWeight, Font as DomFont, FontStyle as DomFontStyle, FontWeight as DomFontWeight,
}; };
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, EnumItem}; use super::{super::*, EnumItem};
/** /**
@ -34,66 +36,65 @@ impl Font {
cached_id: None, cached_id: None,
}) })
} }
}
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { impl LuaExportsTable<'_> for Font {
datatype_table.set( const EXPORT_NAME: &'static str = "Font";
"new",
lua.create_function( fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|_, (family, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| { let font_from_enum = |_, value: LuaUserDataRef<EnumItem>| {
Ok(Font { if value.parent.desc.name == "Font" {
family, match Font::from_enum_item(&value) {
weight: weight.unwrap_or_default(), Some(props) => Ok(props),
style: style.unwrap_or_default(), None => Err(LuaError::RuntimeError(format!(
cached_id: None, "Found unknown Font '{}'",
}) value.name
}, ))),
)?,
)?;
datatype_table.set(
"fromEnum",
lua.create_function(|_, value: LuaUserDataRef<EnumItem>| {
if value.parent.desc.name == "Font" {
match Font::from_enum_item(&value) {
Some(props) => Ok(props),
None => Err(LuaError::RuntimeError(format!(
"Found unknown Font '{}'",
value.name
))),
}
} else {
Err(LuaError::RuntimeError(format!(
"Expected argument #1 to be a Font, got {}",
value.parent.desc.name
)))
} }
})?, } else {
)?; Err(LuaError::RuntimeError(format!(
datatype_table.set( "Expected argument #1 to be a Font, got {}",
"fromName", value.parent.desc.name
lua.create_function( )))
|_, (file, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| { }
Ok(Font { };
family: format!("rbxasset://fonts/families/{}.json", file),
weight: weight.unwrap_or_default(), let font_from_name =
style: style.unwrap_or_default(), |_, (file, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| {
cached_id: None, Ok(Font {
}) family: format!("rbxasset://fonts/families/{}.json", file),
}, weight: weight.unwrap_or_default(),
)?, style: style.unwrap_or_default(),
)?; cached_id: None,
datatype_table.set( })
"fromId", };
lua.create_function(
|_, (id, weight, style): (i32, Option<FontWeight>, Option<FontStyle>)| { let font_from_id =
Ok(Font { |_, (id, weight, style): (i32, Option<FontWeight>, Option<FontStyle>)| {
family: format!("rbxassetid://{}", id), Ok(Font {
weight: weight.unwrap_or_default(), family: format!("rbxassetid://{}", id),
style: style.unwrap_or_default(), weight: weight.unwrap_or_default(),
cached_id: None, style: style.unwrap_or_default(),
}) cached_id: None,
}, })
)?, };
)
let font_new =
|_, (family, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| {
Ok(Font {
family,
weight: weight.unwrap_or_default(),
style: style.unwrap_or_default(),
cached_id: None,
})
};
TableBuilder::new(lua)?
.with_function("fromEnum", font_from_enum)?
.with_function("fromName", font_from_name)?
.with_function("fromId", font_from_id)?
.with_function("new", font_new)?
.build_readonly()
} }
} }

View file

@ -3,6 +3,8 @@ use core::fmt;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::NumberRange as DomNumberRange; use rbx_dom_weak::types::NumberRange as DomNumberRange;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::super::*; use super::super::*;
/** /**
@ -16,20 +18,23 @@ pub struct NumberRange {
pub(crate) max: f32, pub(crate) max: f32,
} }
impl NumberRange { impl LuaExportsTable<'_> for NumberRange {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "NumberRange";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, (min, max): (f32, Option<f32>)| { let number_range_new = |_, (min, max): (f32, Option<f32>)| {
Ok(match max { Ok(match max {
Some(max) => NumberRange { Some(max) => NumberRange {
min: min.min(max), min: min.min(max),
max: min.max(max), max: min.max(max),
}, },
None => NumberRange { min, max: min }, None => NumberRange { min, max: min },
}) })
})?, };
)
TableBuilder::new(lua)?
.with_function("new", number_range_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use rbx_dom_weak::types::{
NumberSequence as DomNumberSequence, NumberSequenceKeypoint as DomNumberSequenceKeypoint, NumberSequence as DomNumberSequence, NumberSequenceKeypoint as DomNumberSequenceKeypoint,
}; };
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, NumberSequenceKeypoint}; use super::{super::*, NumberSequenceKeypoint};
/** /**
@ -17,56 +19,60 @@ pub struct NumberSequence {
pub(crate) keypoints: Vec<NumberSequenceKeypoint>, pub(crate) keypoints: Vec<NumberSequenceKeypoint>,
} }
impl NumberSequence { impl LuaExportsTable<'_> for NumberSequence {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "NumberSequence";
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
type ArgsColor = f32; type ArgsColor = f32;
type ArgsColors = (f32, f32); type ArgsColors = (f32, f32);
type ArgsKeypoints<'lua> = Vec<LuaUserDataRef<'lua, NumberSequenceKeypoint>>; type ArgsKeypoints<'lua> = Vec<LuaUserDataRef<'lua, NumberSequenceKeypoint>>;
datatype_table.set(
"new", let number_sequence_new = |lua, args: LuaMultiValue| {
lua.create_function(|lua, args: LuaMultiValue| { if let Ok(value) = ArgsColor::from_lua_multi(args.clone(), lua) {
if let Ok(value) = ArgsColor::from_lua_multi(args.clone(), lua) { Ok(NumberSequence {
Ok(NumberSequence { keypoints: vec![
keypoints: vec![ NumberSequenceKeypoint {
NumberSequenceKeypoint { time: 0.0,
time: 0.0, value,
value, envelope: 0.0,
envelope: 0.0, },
}, NumberSequenceKeypoint {
NumberSequenceKeypoint { time: 1.0,
time: 1.0, value,
value, envelope: 0.0,
envelope: 0.0, },
}, ],
], })
}) } else if let Ok((v0, v1)) = ArgsColors::from_lua_multi(args.clone(), lua) {
} else if let Ok((v0, v1)) = ArgsColors::from_lua_multi(args.clone(), lua) { Ok(NumberSequence {
Ok(NumberSequence { keypoints: vec![
keypoints: vec![ NumberSequenceKeypoint {
NumberSequenceKeypoint { time: 0.0,
time: 0.0, value: v0,
value: v0, envelope: 0.0,
envelope: 0.0, },
}, NumberSequenceKeypoint {
NumberSequenceKeypoint { time: 1.0,
time: 1.0, value: v1,
value: v1, envelope: 0.0,
envelope: 0.0, },
}, ],
], })
}) } else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) {
} else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) { Ok(NumberSequence {
Ok(NumberSequence { keypoints: keypoints.iter().map(|k| **k).collect(),
keypoints: keypoints.iter().map(|k| **k).collect(), })
}) } else {
} else { // FUTURE: Better error message here using given arg types
// FUTURE: Better error message here using given arg types Err(LuaError::RuntimeError(
Err(LuaError::RuntimeError( "Invalid arguments to constructor".to_string(),
"Invalid arguments to constructor".to_string(), ))
)) }
} };
})?,
) TableBuilder::new(lua)?
.with_function("new", number_sequence_new)?
.build_readonly()
} }
} }

View file

@ -3,6 +3,8 @@ use core::fmt;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::NumberSequenceKeypoint as DomNumberSequenceKeypoint; use rbx_dom_weak::types::NumberSequenceKeypoint as DomNumberSequenceKeypoint;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::super::*; use super::super::*;
/** /**
@ -17,19 +19,21 @@ pub struct NumberSequenceKeypoint {
pub(crate) envelope: f32, pub(crate) envelope: f32,
} }
impl NumberSequenceKeypoint { impl LuaExportsTable<'_> for NumberSequenceKeypoint {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "NumberSequenceKeypoint";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, (time, value, envelope): (f32, f32, Option<f32>)| { let number_sequence_keypoint_new = |_, (time, value, envelope): (f32, f32, Option<f32>)| {
Ok(NumberSequenceKeypoint { Ok(NumberSequenceKeypoint {
time, time,
value, value,
envelope: envelope.unwrap_or_default(), envelope: envelope.unwrap_or_default(),
}) })
})?, };
)?;
Ok(()) TableBuilder::new(lua)?
.with_function("new", number_sequence_keypoint_new)?
.build_readonly()
} }
} }

View file

@ -3,6 +3,8 @@ use core::fmt;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::CustomPhysicalProperties as DomCustomPhysicalProperties; use rbx_dom_weak::types::CustomPhysicalProperties as DomCustomPhysicalProperties;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, EnumItem}; use super::{super::*, EnumItem};
/** /**
@ -32,51 +34,52 @@ impl PhysicalProperties {
elasticity_weight: props.5, elasticity_weight: props.5,
}) })
} }
}
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { impl LuaExportsTable<'_> for PhysicalProperties {
const EXPORT_NAME: &'static str = "PhysicalProperties";
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
type ArgsMaterial<'lua> = LuaUserDataRef<'lua, EnumItem>; type ArgsMaterial<'lua> = LuaUserDataRef<'lua, EnumItem>;
type ArgsNumbers = (f32, f32, f32, Option<f32>, Option<f32>); type ArgsNumbers = (f32, f32, f32, Option<f32>, Option<f32>);
datatype_table.set(
"new", let physical_properties_new = |lua, args: LuaMultiValue| {
lua.create_function(|lua, args: LuaMultiValue| { if let Ok(value) = ArgsMaterial::from_lua_multi(args.clone(), lua) {
if let Ok(value) = ArgsMaterial::from_lua_multi(args.clone(), lua) { if value.parent.desc.name == "Material" {
if value.parent.desc.name == "Material" { match PhysicalProperties::from_material(&value) {
match PhysicalProperties::from_material(&value) { Some(props) => Ok(props),
Some(props) => Ok(props), None => Err(LuaError::RuntimeError(format!(
None => Err(LuaError::RuntimeError(format!( "Found unknown Material '{}'",
"Found unknown Material '{}'", value.name
value.name ))),
))),
}
} else {
Err(LuaError::RuntimeError(format!(
"Expected argument #1 to be a Material, got {}",
value.parent.desc.name
)))
} }
} else if let Ok(( } else {
Err(LuaError::RuntimeError(format!(
"Expected argument #1 to be a Material, got {}",
value.parent.desc.name
)))
}
} else if let Ok((density, friction, elasticity, friction_weight, elasticity_weight)) =
ArgsNumbers::from_lua_multi(args, lua)
{
Ok(PhysicalProperties {
density, density,
friction, friction,
friction_weight: friction_weight.unwrap_or(1.0),
elasticity, elasticity,
friction_weight, elasticity_weight: elasticity_weight.unwrap_or(1.0),
elasticity_weight, })
)) = ArgsNumbers::from_lua_multi(args, lua) } else {
{ // FUTURE: Better error message here using given arg types
Ok(PhysicalProperties { Err(LuaError::RuntimeError(
density, "Invalid arguments to constructor".to_string(),
friction, ))
friction_weight: friction_weight.unwrap_or(1.0), }
elasticity, };
elasticity_weight: elasticity_weight.unwrap_or(1.0),
}) TableBuilder::new(lua)?
} else { .with_function("new", physical_properties_new)?
// FUTURE: Better error message here using given arg types .build_readonly()
Err(LuaError::RuntimeError(
"Invalid arguments to constructor".to_string(),
))
}
})?,
)
} }
} }

View file

@ -4,6 +4,8 @@ use glam::Vec3;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Ray as DomRay; use rbx_dom_weak::types::Ray as DomRay;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, Vector3}; use super::{super::*, Vector3};
/** /**
@ -26,19 +28,23 @@ impl Ray {
let dot_product = lhs.dot(norm).max(0.0); let dot_product = lhs.dot(norm).max(0.0);
self.origin + norm * dot_product self.origin + norm * dot_product
} }
}
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { impl LuaExportsTable<'_> for Ray {
datatype_table.set( const EXPORT_NAME: &'static str = "Ray";
"new",
lua.create_function( fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|_, (origin, direction): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| { let ray_new =
Ok(Ray { |_, (origin, direction): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| {
origin: origin.0, Ok(Ray {
direction: direction.0, origin: origin.0,
}) direction: direction.0,
}, })
)?, };
)
TableBuilder::new(lua)?
.with_function("new", ray_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use glam::Vec2;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Rect as DomRect; use rbx_dom_weak::types::Rect as DomRect;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, Vector2}; use super::{super::*, Vector2};
/** /**
@ -28,33 +30,37 @@ impl Rect {
} }
} }
impl Rect { impl LuaExportsTable<'_> for Rect {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Rect";
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
type ArgsVector2s<'lua> = ( type ArgsVector2s<'lua> = (
Option<LuaUserDataRef<'lua, Vector2>>, Option<LuaUserDataRef<'lua, Vector2>>,
Option<LuaUserDataRef<'lua, Vector2>>, Option<LuaUserDataRef<'lua, Vector2>>,
); );
type ArgsNums = (Option<f32>, Option<f32>, Option<f32>, Option<f32>); type ArgsNums = (Option<f32>, Option<f32>, Option<f32>, Option<f32>);
datatype_table.set(
"new", let rect_new = |lua, args: LuaMultiValue| {
lua.create_function(|lua, args: LuaMultiValue| { if let Ok((min, max)) = ArgsVector2s::from_lua_multi(args.clone(), lua) {
if let Ok((min, max)) = ArgsVector2s::from_lua_multi(args.clone(), lua) { Ok(Rect::new(
Ok(Rect::new( min.map(|m| *m).unwrap_or_default().0,
min.map(|m| *m).unwrap_or_default().0, max.map(|m| *m).unwrap_or_default().0,
max.map(|m| *m).unwrap_or_default().0, ))
)) } else if let Ok((x0, y0, x1, y1)) = ArgsNums::from_lua_multi(args, lua) {
} else if let Ok((x0, y0, x1, y1)) = ArgsNums::from_lua_multi(args, lua) { let min = Vec2::new(x0.unwrap_or_default(), y0.unwrap_or_default());
let min = Vec2::new(x0.unwrap_or_default(), y0.unwrap_or_default()); let max = Vec2::new(x1.unwrap_or_default(), y1.unwrap_or_default());
let max = Vec2::new(x1.unwrap_or_default(), y1.unwrap_or_default()); Ok(Rect::new(min, max))
Ok(Rect::new(min, max)) } else {
} else { // FUTURE: Better error message here using given arg types
// FUTURE: Better error message here using given arg types Err(LuaError::RuntimeError(
Err(LuaError::RuntimeError( "Invalid arguments to constructor".to_string(),
"Invalid arguments to constructor".to_string(), ))
)) }
} };
})?,
) TableBuilder::new(lua)?
.with_function("new", rect_new)?
.build_readonly()
} }
} }

View file

@ -4,6 +4,8 @@ use glam::{Mat4, Vec3};
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Region3 as DomRegion3; use rbx_dom_weak::types::Region3 as DomRegion3;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, CFrame, Vector3}; use super::{super::*, CFrame, Vector3};
/** /**
@ -18,19 +20,20 @@ pub struct Region3 {
pub(crate) max: Vec3, pub(crate) max: Vec3,
} }
impl Region3 { impl LuaExportsTable<'_> for Region3 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Region3";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function( let region3_new = |_, (min, max): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| {
|_, (min, max): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| { Ok(Region3 {
Ok(Region3 { min: min.0,
min: min.0, max: max.0,
max: max.0, })
}) };
},
)?, TableBuilder::new(lua)?
) .with_function("new", region3_new)?
.build_readonly()
} }
} }

View file

@ -4,6 +4,8 @@ use glam::IVec3;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Region3int16 as DomRegion3int16; use rbx_dom_weak::types::Region3int16 as DomRegion3int16;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, Vector3int16}; use super::{super::*, Vector3int16};
/** /**
@ -18,19 +20,21 @@ pub struct Region3int16 {
pub(crate) max: IVec3, pub(crate) max: IVec3,
} }
impl Region3int16 { impl LuaExportsTable<'_> for Region3int16 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Region3int16";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function( let region3int16_new =
|_, (min, max): (LuaUserDataRef<Vector3int16>, LuaUserDataRef<Vector3int16>)| { |_, (min, max): (LuaUserDataRef<Vector3int16>, LuaUserDataRef<Vector3int16>)| {
Ok(Region3int16 { Ok(Region3int16 {
min: min.0, min: min.0,
max: max.0, max: max.0,
}) })
}, };
)?,
) TableBuilder::new(lua)?
.with_function("new", region3int16_new)?
.build_readonly()
} }
} }

View file

@ -4,6 +4,8 @@ use std::ops;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::UDim as DomUDim; use rbx_dom_weak::types::UDim as DomUDim;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::super::*; use super::super::*;
/** /**
@ -21,17 +23,22 @@ impl UDim {
pub(super) fn new(scale: f32, offset: i32) -> Self { pub(super) fn new(scale: f32, offset: i32) -> Self {
Self { scale, offset } Self { scale, offset }
} }
}
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { impl LuaExportsTable<'_> for UDim {
datatype_table.set( const EXPORT_NAME: &'static str = "UDim";
"new",
lua.create_function(|_, (scale, offset): (Option<f32>, Option<i32>)| { fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
Ok(UDim { let udim_new = |_, (scale, offset): (Option<f32>, Option<i32>)| {
scale: scale.unwrap_or_default(), Ok(UDim {
offset: offset.unwrap_or_default(), scale: scale.unwrap_or_default(),
}) offset: offset.unwrap_or_default(),
})?, })
) };
TableBuilder::new(lua)?
.with_function("new", udim_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use glam::Vec2;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::UDim2 as DomUDim2; use rbx_dom_weak::types::UDim2 as DomUDim2;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, UDim}; use super::{super::*, UDim};
/** /**
@ -18,52 +20,53 @@ pub struct UDim2 {
pub(crate) y: UDim, pub(crate) y: UDim,
} }
impl UDim2 { impl LuaExportsTable<'_> for UDim2 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "UDim2";
datatype_table.set(
"fromScale", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, (x, y): (Option<f32>, Option<f32>)| { let udim2_from_offset = |_, (x, y): (Option<i32>, Option<i32>)| {
Ok(UDim2 { Ok(UDim2 {
x: UDim::new(x.unwrap_or_default(), 0), x: UDim::new(0f32, x.unwrap_or_default()),
y: UDim::new(y.unwrap_or_default(), 0), y: UDim::new(0f32, y.unwrap_or_default()),
}) })
})?, };
)?;
datatype_table.set( let udim2_from_scale = |_, (x, y): (Option<f32>, Option<f32>)| {
"fromOffset", Ok(UDim2 {
lua.create_function(|_, (x, y): (Option<i32>, Option<i32>)| { x: UDim::new(x.unwrap_or_default(), 0),
Ok(UDim2 { y: UDim::new(y.unwrap_or_default(), 0),
x: UDim::new(0f32, x.unwrap_or_default()), })
y: UDim::new(0f32, y.unwrap_or_default()), };
})
})?,
)?;
type ArgsUDims<'lua> = ( type ArgsUDims<'lua> = (
Option<LuaUserDataRef<'lua, UDim>>, Option<LuaUserDataRef<'lua, UDim>>,
Option<LuaUserDataRef<'lua, UDim>>, Option<LuaUserDataRef<'lua, UDim>>,
); );
type ArgsNums = (Option<f32>, Option<i32>, Option<f32>, Option<i32>); type ArgsNums = (Option<f32>, Option<i32>, Option<f32>, Option<i32>);
datatype_table.set( let udim2_new = |lua, args: LuaMultiValue| {
"new", if let Ok((x, y)) = ArgsUDims::from_lua_multi(args.clone(), lua) {
lua.create_function(|lua, args: LuaMultiValue| { Ok(UDim2 {
if let Ok((x, y)) = ArgsUDims::from_lua_multi(args.clone(), lua) { x: x.map(|x| *x).unwrap_or_default(),
Ok(UDim2 { y: y.map(|y| *y).unwrap_or_default(),
x: x.map(|x| *x).unwrap_or_default(), })
y: y.map(|y| *y).unwrap_or_default(), } else if let Ok((sx, ox, sy, oy)) = ArgsNums::from_lua_multi(args, lua) {
}) Ok(UDim2 {
} else if let Ok((sx, ox, sy, oy)) = ArgsNums::from_lua_multi(args, lua) { x: UDim::new(sx.unwrap_or_default(), ox.unwrap_or_default()),
Ok(UDim2 { y: UDim::new(sy.unwrap_or_default(), oy.unwrap_or_default()),
x: UDim::new(sx.unwrap_or_default(), ox.unwrap_or_default()), })
y: UDim::new(sy.unwrap_or_default(), oy.unwrap_or_default()), } else {
}) // FUTURE: Better error message here using given arg types
} else { Err(LuaError::RuntimeError(
// FUTURE: Better error message here using given arg types "Invalid arguments to constructor".to_string(),
Err(LuaError::RuntimeError( ))
"Invalid arguments to constructor".to_string(), }
)) };
}
})?, TableBuilder::new(lua)?
) .with_function("fromOffset", udim2_from_offset)?
.with_function("fromScale", udim2_from_scale)?
.with_function("new", udim2_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use glam::{Vec2, Vec3};
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Vector2 as DomVector2; use rbx_dom_weak::types::Vector2 as DomVector2;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::super::*; use super::super::*;
/** /**
@ -17,23 +19,24 @@ use super::super::*;
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Vector2(pub Vec2); pub struct Vector2(pub Vec2);
impl Vector2 { impl LuaExportsTable<'_> for Vector2 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Vector2";
// Constants
datatype_table.set("xAxis", Vector2(Vec2::X))?; fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
datatype_table.set("yAxis", Vector2(Vec2::Y))?; let vector2_new = |_, (x, y): (Option<f32>, Option<f32>)| {
datatype_table.set("zero", Vector2(Vec2::ZERO))?; Ok(Vector2(Vec2 {
datatype_table.set("one", Vector2(Vec2::ONE))?; x: x.unwrap_or_default(),
// Constructors y: y.unwrap_or_default(),
datatype_table.set( }))
"new", };
lua.create_function(|_, (x, y): (Option<f32>, Option<f32>)| {
Ok(Vector2(Vec2 { TableBuilder::new(lua)?
x: x.unwrap_or_default(), .with_value("xAxis", Vector2(Vec2::X))?
y: y.unwrap_or_default(), .with_value("yAxis", Vector2(Vec2::Y))?
})) .with_value("zero", Vector2(Vec2::ZERO))?
})?, .with_value("one", Vector2(Vec2::ONE))?
) .with_function("new", vector2_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use glam::IVec2;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Vector2int16 as DomVector2int16; use rbx_dom_weak::types::Vector2int16 as DomVector2int16;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::super::*; use super::super::*;
/** /**
@ -17,17 +19,20 @@ use super::super::*;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vector2int16(pub IVec2); pub struct Vector2int16(pub IVec2);
impl Vector2int16 { impl LuaExportsTable<'_> for Vector2int16 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Vector2int16";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, (x, y): (Option<i16>, Option<i16>)| { let vector2int16_new = |_, (x, y): (Option<i16>, Option<i16>)| {
Ok(Vector2int16(IVec2 { Ok(Vector2int16(IVec2 {
x: x.unwrap_or_default() as i32, x: x.unwrap_or_default() as i32,
y: y.unwrap_or_default() as i32, y: y.unwrap_or_default() as i32,
})) }))
})?, };
)
TableBuilder::new(lua)?
.with_function("new", vector2int16_new)?
.build_readonly()
} }
} }

View file

@ -5,6 +5,8 @@ use glam::Vec3;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Vector3 as DomVector3; use rbx_dom_weak::types::Vector3 as DomVector3;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::{super::*, EnumItem}; use super::{super::*, EnumItem};
/** /**
@ -20,74 +22,73 @@ use super::{super::*, EnumItem};
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vector3(pub Vec3); pub struct Vector3(pub Vec3);
impl Vector3 { impl LuaExportsTable<'_> for Vector3 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Vector3";
// Constants
datatype_table.set("xAxis", Vector3(Vec3::X))?; fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
datatype_table.set("yAxis", Vector3(Vec3::Y))?; let vector3_from_axis = |_, normal_id: LuaUserDataRef<EnumItem>| {
datatype_table.set("zAxis", Vector3(Vec3::Z))?; if normal_id.parent.desc.name == "Axis" {
datatype_table.set("zero", Vector3(Vec3::ZERO))?; Ok(match normal_id.name.as_str() {
datatype_table.set("one", Vector3(Vec3::ONE))?; "X" => Vector3(Vec3::X),
// Constructors "Y" => Vector3(Vec3::Y),
datatype_table.set( "Z" => Vector3(Vec3::Z),
"fromAxis", name => {
lua.create_function(|_, normal_id: LuaUserDataRef<EnumItem>| { return Err(LuaError::RuntimeError(format!(
if normal_id.parent.desc.name == "Axis" { "Axis '{}' is not known",
Ok(match normal_id.name.as_str() { name
"X" => Vector3(Vec3::X), )))
"Y" => Vector3(Vec3::Y), }
"Z" => Vector3(Vec3::Z), })
name => { } else {
return Err(LuaError::RuntimeError(format!( Err(LuaError::RuntimeError(format!(
"Axis '{}' is not known", "EnumItem must be a Axis, got {}",
name normal_id.parent.desc.name
))) )))
} }
}) };
} else {
Err(LuaError::RuntimeError(format!( let vector3_from_normal_id = |_, normal_id: LuaUserDataRef<EnumItem>| {
"EnumItem must be a Axis, got {}", if normal_id.parent.desc.name == "NormalId" {
normal_id.parent.desc.name Ok(match normal_id.name.as_str() {
))) "Left" => Vector3(Vec3::X),
} "Top" => Vector3(Vec3::Y),
})?, "Front" => Vector3(-Vec3::Z),
)?; "Right" => Vector3(-Vec3::X),
datatype_table.set( "Bottom" => Vector3(-Vec3::Y),
"fromNormalId", "Back" => Vector3(Vec3::Z),
lua.create_function(|_, normal_id: LuaUserDataRef<EnumItem>| { name => {
if normal_id.parent.desc.name == "NormalId" { return Err(LuaError::RuntimeError(format!(
Ok(match normal_id.name.as_str() { "NormalId '{}' is not known",
"Left" => Vector3(Vec3::X), name
"Top" => Vector3(Vec3::Y), )))
"Front" => Vector3(-Vec3::Z), }
"Right" => Vector3(-Vec3::X), })
"Bottom" => Vector3(-Vec3::Y), } else {
"Back" => Vector3(Vec3::Z), Err(LuaError::RuntimeError(format!(
name => { "EnumItem must be a NormalId, got {}",
return Err(LuaError::RuntimeError(format!( normal_id.parent.desc.name
"NormalId '{}' is not known", )))
name }
))) };
}
}) let vector3_new = |_, (x, y, z): (Option<f32>, Option<f32>, Option<f32>)| {
} else { Ok(Vector3(Vec3 {
Err(LuaError::RuntimeError(format!( x: x.unwrap_or_default(),
"EnumItem must be a NormalId, got {}", y: y.unwrap_or_default(),
normal_id.parent.desc.name z: z.unwrap_or_default(),
))) }))
} };
})?,
)?; TableBuilder::new(lua)?
datatype_table.set( .with_value("xAxis", Vector3(Vec3::X))?
"new", .with_value("yAxis", Vector3(Vec3::Y))?
lua.create_function(|_, (x, y, z): (Option<f32>, Option<f32>, Option<f32>)| { .with_value("zAxis", Vector3(Vec3::Z))?
Ok(Vector3(Vec3 { .with_value("zero", Vector3(Vec3::ZERO))?
x: x.unwrap_or_default(), .with_value("one", Vector3(Vec3::ONE))?
y: y.unwrap_or_default(), .with_function("fromAxis", vector3_from_axis)?
z: z.unwrap_or_default(), .with_function("fromNormalId", vector3_from_normal_id)?
})) .with_function("new", vector3_new)?
})?, .build_readonly()
)
} }
} }

View file

@ -5,6 +5,8 @@ use glam::IVec3;
use mlua::prelude::*; use mlua::prelude::*;
use rbx_dom_weak::types::Vector3int16 as DomVector3int16; use rbx_dom_weak::types::Vector3int16 as DomVector3int16;
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
use super::super::*; use super::super::*;
/** /**
@ -17,18 +19,21 @@ use super::super::*;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vector3int16(pub IVec3); pub struct Vector3int16(pub IVec3);
impl Vector3int16 { impl LuaExportsTable<'_> for Vector3int16 {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Vector3int16";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|_, (x, y, z): (Option<i16>, Option<i16>, Option<i16>)| { let vector3int16_new = |_, (x, y, z): (Option<i16>, Option<i16>, Option<i16>)| {
Ok(Vector3int16(IVec3 { Ok(Vector3int16(IVec3 {
x: x.unwrap_or_default() as i32, x: x.unwrap_or_default() as i32,
y: y.unwrap_or_default() as i32, y: y.unwrap_or_default() as i32,
z: z.unwrap_or_default() as i32, z: z.unwrap_or_default() as i32,
})) }))
})?, };
)
TableBuilder::new(lua)?
.with_function("new", vector3int16_new)?
.build_readonly()
} }
} }

68
src/roblox/exports.rs Normal file
View file

@ -0,0 +1,68 @@
use mlua::prelude::*;
/**
Trait for any item that should be exported as part of the `roblox` built-in library.
This may be an enum or a struct that should export constants and/or constructs.
### Example usage
```rs
use mlua::prelude::*;
struct MyType(usize);
impl MyType {
pub fn new(n: usize) -> Self {
Self(n)
}
}
impl LuaExportsTable<'_> for MyType {
const EXPORT_NAME: &'static str = "MyType";
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
let my_type_new = |lua, n: Option<usize>| {
Self::new(n.unwrap_or_default())
};
TableBuilder::new(lua)?
.with_function("new", my_type_new)?
.build_readonly()
}
}
impl LuaUserData for MyType {
// ...
}
```
*/
pub trait LuaExportsTable<'lua> {
const EXPORT_NAME: &'static str;
fn create_exports_table(lua: &'lua Lua) -> LuaResult<LuaTable<'lua>>;
}
/**
Exports a single item that implements the [`LuaExportsTable`] trait.
Returns the name of the export, as well as the export table.
### Example usage
```rs
let lua: mlua::Lua::new();
let (name1, table1) = export::<Type1>(lua)?;
let (name2, table2) = export::<Type2>(lua)?;
```
*/
pub fn export<'lua, T>(lua: &'lua Lua) -> LuaResult<(&'static str, LuaValue<'lua>)>
where
T: LuaExportsTable<'lua>,
{
Ok((
T::EXPORT_NAME,
<T as LuaExportsTable>::create_exports_table(lua)?.into_lua(lua)?,
))
}

View file

@ -12,7 +12,11 @@ use rbx_dom_weak::{
Instance as DomInstance, InstanceBuilder as DomInstanceBuilder, WeakDom, Instance as DomInstance, InstanceBuilder as DomInstanceBuilder, WeakDom,
}; };
use crate::roblox::shared::instance::{class_exists, class_is_a}; use crate::{
lune::util::TableBuilder,
roblox::exports::LuaExportsTable,
roblox::shared::instance::{class_exists, class_is_a},
};
pub(crate) mod base; pub(crate) mod base;
pub(crate) mod data_model; pub(crate) mod data_model;
@ -686,21 +690,24 @@ impl Instance {
} }
} }
impl Instance { impl LuaExportsTable<'_> for Instance {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { const EXPORT_NAME: &'static str = "Instance";
datatype_table.set(
"new", fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_function(|lua, class_name: String| { let instance_new = |lua, class_name: String| {
if class_exists(&class_name) { if class_exists(&class_name) {
Instance::new_orphaned(class_name).into_lua(lua) Instance::new_orphaned(class_name).into_lua(lua)
} else { } else {
Err(LuaError::RuntimeError(format!( Err(LuaError::RuntimeError(format!(
"Failed to create Instance - '{}' is not a valid class name", "Failed to create Instance - '{}' is not a valid class name",
class_name class_name
))) )))
} }
})?, };
)
TableBuilder::new(lua)?
.with_function("new", instance_new)?
.build_readonly()
} }
} }

View file

@ -1,63 +1,59 @@
use mlua::prelude::*; use mlua::prelude::*;
use crate::roblox::instance::Instance; use crate::lune::util::TableBuilder;
pub mod datatypes; pub mod datatypes;
pub mod document; pub mod document;
pub mod instance; pub mod instance;
pub mod reflection; pub mod reflection;
pub(crate) mod exports;
pub(crate) mod shared; pub(crate) mod shared;
fn make<F>(lua: &Lua, f: F) -> LuaResult<LuaValue> use exports::export;
where
F: Fn(&Lua, &LuaTable) -> LuaResult<()>,
{
let tab = lua.create_table()?;
f(lua, &tab)?;
tab.set_readonly(true);
Ok(LuaValue::Table(tab))
}
#[rustfmt::skip] fn create_all_exports(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
fn make_all_datatypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> { use datatypes::types::*;
use datatypes::types::*; use instance::Instance;
Ok(vec![ Ok(vec![
// Datatypes // Datatypes
("Axes", make(lua, Axes::make_table)?), export::<Axes>(lua)?,
("BrickColor", make(lua, BrickColor::make_table)?), export::<BrickColor>(lua)?,
("CFrame", make(lua, CFrame::make_table)?), export::<CFrame>(lua)?,
("Color3", make(lua, Color3::make_table)?), export::<Color3>(lua)?,
("ColorSequence", make(lua, ColorSequence::make_table)?), export::<ColorSequence>(lua)?,
("ColorSequenceKeypoint", make(lua, ColorSequenceKeypoint::make_table)?), export::<ColorSequenceKeypoint>(lua)?,
("Faces", make(lua, Faces::make_table)?), export::<Faces>(lua)?,
("Font", make(lua, Font::make_table)?), export::<Font>(lua)?,
("NumberRange", make(lua, NumberRange::make_table)?), export::<NumberRange>(lua)?,
("NumberSequence", make(lua, NumberSequence::make_table)?), export::<NumberSequence>(lua)?,
("NumberSequenceKeypoint", make(lua, NumberSequenceKeypoint::make_table)?), export::<NumberSequenceKeypoint>(lua)?,
("PhysicalProperties", make(lua, PhysicalProperties::make_table)?), export::<PhysicalProperties>(lua)?,
("Ray", make(lua, Ray::make_table)?), export::<Ray>(lua)?,
("Rect", make(lua, Rect::make_table)?), export::<Rect>(lua)?,
("UDim", make(lua, UDim::make_table)?), export::<UDim>(lua)?,
("UDim2", make(lua, UDim2::make_table)?), export::<UDim2>(lua)?,
("Region3", make(lua, Region3::make_table)?), export::<Region3>(lua)?,
("Region3int16", make(lua, Region3int16::make_table)?), export::<Region3int16>(lua)?,
("Vector2", make(lua, Vector2::make_table)?), export::<Vector2>(lua)?,
("Vector2int16", make(lua, Vector2int16::make_table)?), export::<Vector2int16>(lua)?,
("Vector3", make(lua, Vector3::make_table)?), export::<Vector3>(lua)?,
("Vector3int16", make(lua, Vector3int16::make_table)?), export::<Vector3int16>(lua)?,
// Classes // Classes
("Instance", make(lua, Instance::make_table)?), export::<Instance>(lua)?,
// Singletons // Singletons
("Enum", Enums.into_lua(lua)?), ("Enum", Enums.into_lua(lua)?),
]) ])
} }
pub fn module(lua: &Lua) -> LuaResult<LuaTable> { pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table()?; // FUTURE: We can probably create these lazily as users
for (name, tab) in make_all_datatypes(lua)? { // index the main exports (this return value) table and
exports.set(name, tab)?; // save some memory and startup time. The full exports
} // table is quite big and probably won't get any smaller
exports.set_readonly(true); // since we impl all roblox constructors for each datatype.
Ok(exports) let exports = create_all_exports(lua)?;
TableBuilder::new(lua)?
.with_values(exports)?
.build_readonly()
} }