mirror of
https://github.com/lune-org/lune.git
synced 2024-12-13 13:30:38 +00:00
Implement translation layer between lua values and rbx_dom_weak variants
This commit is contained in:
parent
a31553e130
commit
078c08eabf
3 changed files with 187 additions and 3 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -861,6 +861,7 @@ dependencies = [
|
|||
name = "lune-roblox"
|
||||
version = "0.5.5"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"glam",
|
||||
"mlua",
|
||||
"rbx_binary",
|
||||
|
|
|
@ -17,6 +17,7 @@ path = "src/lib.rs"
|
|||
[dependencies]
|
||||
mlua.workspace = true
|
||||
|
||||
base64 = "0.21"
|
||||
glam = "0.23"
|
||||
thiserror = "1.0"
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ pub mod types {
|
|||
pub use super::vector3::Vector3;
|
||||
}
|
||||
|
||||
// Trait definitions for conversion between rbx_dom_weak variant <-> datatype
|
||||
// Trait definitions for conversion between rbx_dom_weak variant <-> our custom datatypes
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum RbxConversionError {
|
||||
|
@ -30,6 +30,17 @@ pub(crate) enum RbxConversionError {
|
|||
can_convert_to: Option<&'static str>,
|
||||
detail: Option<String>,
|
||||
},
|
||||
External {
|
||||
message: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl RbxConversionError {
|
||||
pub fn external(e: impl std::error::Error) -> Self {
|
||||
RbxConversionError::External {
|
||||
message: e.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type RbxConversionResult<T> = Result<T, RbxConversionError>;
|
||||
|
@ -49,7 +60,7 @@ pub(crate) trait DatatypeTable {
|
|||
fn make_dt_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()>;
|
||||
}
|
||||
|
||||
// Shared impls for datatype metamethods
|
||||
// Shared impls for datatype metamethods belonging to this module
|
||||
|
||||
fn datatype_impl_to_string<D>(_: &Lua, datatype: &D, _: ()) -> LuaResult<String>
|
||||
where
|
||||
|
@ -128,6 +139,177 @@ impl RbxVariantDisplayName for RbxVariant {
|
|||
}
|
||||
}
|
||||
|
||||
// Generic impls for converting from lua values <-> rbx_dom_weak variants
|
||||
// We use a separate trait here since creating lua stuff needs the lua context
|
||||
|
||||
pub(crate) trait FromRbxVariantLua<'lua>: Sized {
|
||||
fn from_rbx_variant_lua(variant: &RbxVariant, lua: &'lua Lua) -> RbxConversionResult<Self>;
|
||||
}
|
||||
|
||||
impl<'lua> FromRbxVariantLua<'lua> for LuaValue<'lua> {
|
||||
fn from_rbx_variant_lua(variant: &RbxVariant, lua: &'lua Lua) -> RbxConversionResult<Self> {
|
||||
use self::types::*;
|
||||
use base64::engine::general_purpose::STANDARD_NO_PAD;
|
||||
use base64::engine::Engine as _;
|
||||
use RbxVariant as Rbx;
|
||||
|
||||
match variant {
|
||||
// Primitives
|
||||
Rbx::Bool(b) => Ok(LuaValue::Boolean(*b)),
|
||||
Rbx::Int64(i) => Ok(LuaValue::Integer(*i as i32)),
|
||||
Rbx::Int32(i) => Ok(LuaValue::Integer(*i)),
|
||||
Rbx::Float64(n) => Ok(LuaValue::Number(*n)),
|
||||
Rbx::Float32(n) => Ok(LuaValue::Number(*n as f64)),
|
||||
Rbx::String(s) => Ok(LuaValue::String(
|
||||
lua.create_string(s).map_err(RbxConversionError::external)?,
|
||||
)),
|
||||
Rbx::Content(s) => Ok(LuaValue::String(
|
||||
lua.create_string(AsRef::<str>::as_ref(s))
|
||||
.map_err(RbxConversionError::external)?,
|
||||
)),
|
||||
Rbx::BinaryString(s) => {
|
||||
let encoded = STANDARD_NO_PAD.encode(AsRef::<[u8]>::as_ref(s));
|
||||
Ok(LuaValue::String(
|
||||
lua.create_string(&encoded)
|
||||
.map_err(RbxConversionError::external)?,
|
||||
))
|
||||
}
|
||||
// Custom datatypes
|
||||
// NOTE: When adding a new datatype, also add it in the FromRbxVariantLua impl below
|
||||
Rbx::Vector2(_) => Vector2::from_rbx_variant(variant)?
|
||||
.to_lua(lua)
|
||||
.map_err(RbxConversionError::external),
|
||||
Rbx::Vector3(_) => Vector3::from_rbx_variant(variant)?
|
||||
.to_lua(lua)
|
||||
.map_err(RbxConversionError::external),
|
||||
// Not yet implemented datatypes
|
||||
Rbx::Axes(_) => todo!(),
|
||||
Rbx::BrickColor(_) => todo!(),
|
||||
Rbx::CFrame(_) => todo!(),
|
||||
Rbx::Color3(_) => todo!(),
|
||||
Rbx::Color3uint8(_) => todo!(),
|
||||
Rbx::ColorSequence(_) => todo!(),
|
||||
Rbx::Enum(_) => todo!(),
|
||||
Rbx::Faces(_) => todo!(),
|
||||
Rbx::NumberRange(_) => todo!(),
|
||||
Rbx::NumberSequence(_) => todo!(),
|
||||
Rbx::OptionalCFrame(_) => todo!(),
|
||||
Rbx::PhysicalProperties(_) => todo!(),
|
||||
Rbx::Ray(_) => todo!(),
|
||||
Rbx::Rect(_) => todo!(),
|
||||
Rbx::Region3(_) => todo!(),
|
||||
Rbx::Region3int16(_) => todo!(),
|
||||
Rbx::UDim(_) => todo!(),
|
||||
Rbx::UDim2(_) => todo!(),
|
||||
Rbx::Vector2int16(_) => todo!(),
|
||||
Rbx::Vector3int16(_) => todo!(),
|
||||
v => Err(RbxConversionError::FromRbxVariant {
|
||||
from: v.display_name(),
|
||||
to: "LuaValue",
|
||||
detail: Some("Type not supported".to_string()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> ToRbxVariant for LuaValue<'lua> {
|
||||
fn to_rbx_variant(
|
||||
&self,
|
||||
desired_type: Option<RbxVariantType>,
|
||||
) -> RbxConversionResult<RbxVariant> {
|
||||
use self::types::*;
|
||||
use base64::engine::general_purpose::STANDARD_NO_PAD;
|
||||
use base64::engine::Engine as _;
|
||||
use RbxVariantType as Rbx;
|
||||
|
||||
if let Some(desired_type) = desired_type {
|
||||
match (self, desired_type) {
|
||||
// Primitives
|
||||
(LuaValue::Boolean(b), Rbx::Bool) => Ok(RbxVariant::Bool(*b)),
|
||||
(LuaValue::Integer(i), Rbx::Int64) => Ok(RbxVariant::Int64(*i as i64)),
|
||||
(LuaValue::Integer(i), Rbx::Int32) => Ok(RbxVariant::Int32(*i)),
|
||||
(LuaValue::Integer(i), Rbx::Float64) => Ok(RbxVariant::Float64(*i as f64)),
|
||||
(LuaValue::Integer(i), Rbx::Float32) => Ok(RbxVariant::Float32(*i as f32)),
|
||||
(LuaValue::Number(n), Rbx::Int64) => Ok(RbxVariant::Int64(*n as i64)),
|
||||
(LuaValue::Number(n), Rbx::Int32) => Ok(RbxVariant::Int32(*n as i32)),
|
||||
(LuaValue::Number(n), Rbx::Float64) => Ok(RbxVariant::Float64(*n)),
|
||||
(LuaValue::Number(n), Rbx::Float32) => Ok(RbxVariant::Float32(*n as f32)),
|
||||
(LuaValue::String(s), Rbx::String) => Ok(RbxVariant::String(
|
||||
s.to_str()
|
||||
.map_err(RbxConversionError::external)?
|
||||
.to_string(),
|
||||
)),
|
||||
(LuaValue::String(s), Rbx::Content) => Ok(RbxVariant::Content(
|
||||
s.to_str()
|
||||
.map_err(RbxConversionError::external)?
|
||||
.to_string()
|
||||
.into(),
|
||||
)),
|
||||
(LuaValue::String(s), Rbx::BinaryString) => Ok(RbxVariant::BinaryString(
|
||||
STANDARD_NO_PAD
|
||||
.decode(s)
|
||||
.map_err(RbxConversionError::external)?
|
||||
.into(),
|
||||
)),
|
||||
// Custom datatypes
|
||||
// NOTE: When adding a new datatype, also add it below + in the FromRbxVariantLua impl above
|
||||
(LuaValue::UserData(u), d) => {
|
||||
if let Ok(v2) = u.borrow::<Vector2>() {
|
||||
v2.to_rbx_variant(Some(d))
|
||||
} else if let Ok(v3) = u.borrow::<Vector3>() {
|
||||
v3.to_rbx_variant(Some(d))
|
||||
} else {
|
||||
Err(RbxConversionError::ToRbxVariant {
|
||||
to: d.display_name(),
|
||||
from: "userdata",
|
||||
detail: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
// Not yet implemented rbx types
|
||||
(v, d) => Err(RbxConversionError::ToRbxVariant {
|
||||
to: d.display_name(),
|
||||
from: v.type_name(),
|
||||
detail: None,
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
match self {
|
||||
// Primitives
|
||||
LuaValue::Boolean(b) => Ok(RbxVariant::Bool(*b)),
|
||||
LuaValue::Integer(i) => Ok(RbxVariant::Int32(*i)),
|
||||
LuaValue::Number(n) => Ok(RbxVariant::Float64(*n)),
|
||||
LuaValue::String(s) => Ok(RbxVariant::String(
|
||||
s.to_str()
|
||||
.map_err(RbxConversionError::external)?
|
||||
.to_string(),
|
||||
)),
|
||||
// Custom datatypes
|
||||
// NOTE: When adding a new datatype, also add it above
|
||||
LuaValue::UserData(u) => {
|
||||
if let Ok(v2) = u.borrow::<Vector2>() {
|
||||
v2.to_rbx_variant(None)
|
||||
} else if let Ok(v3) = u.borrow::<Vector3>() {
|
||||
v3.to_rbx_variant(None)
|
||||
} else {
|
||||
Err(RbxConversionError::ToRbxVariant {
|
||||
to: "Variant",
|
||||
from: "userdata",
|
||||
detail: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
// Not yet implemented rbx types
|
||||
v => Err(RbxConversionError::ToRbxVariant {
|
||||
to: "Variant",
|
||||
from: v.type_name(),
|
||||
detail: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement tests for all datatypes in lua and run them here
|
||||
// using the same mechanic we have to run tests in the main lib, these
|
||||
// using the same mechanic we use to run tests in the main lib, these
|
||||
// tests should also live next to other folders like fs, net, task, ..
|
||||
|
|
Loading…
Reference in a new issue