Add better userdata api and type coercion, add Vector and Angle types

This commit is contained in:
William Venner 2021-09-20 20:08:01 +01:00
parent 27857866c8
commit b916d3ba19
4 changed files with 117 additions and 8 deletions

View File

@ -16,6 +16,9 @@ pub mod msgc;
/// Advanced dark magic utilities
pub mod hax;
/// Userdata types
pub mod userdata;
/// Returns whether this client is running the x86-64 branch
///
/// Current implementation checks the contents of the bin/ directory, so this is a blocking operation and requires syscalls, use sparingly

View File

@ -2,6 +2,8 @@ use std::{mem::MaybeUninit, borrow::Cow, ffi::c_void};
use crate::lua::*;
use crate::userdata::UserData;
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct LuaState(pub *mut std::ffi::c_void);

View File

@ -6,14 +6,6 @@ pub use import::*;
mod lua_state;
pub use lua_state::LuaState as State;
#[repr(C)]
#[derive(Debug)]
pub struct UserData
{
pub data: *mut core::ffi::c_void,
pub r#type: u8
}
#[derive(Debug, Clone)]
pub enum LuaError {
/// Out of memory

112
gmod/src/userdata.rs Normal file
View File

@ -0,0 +1,112 @@
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum UserData {
None = 255,
Nil = 0,
Bool,
LightUserData,
Number,
String,
Table,
Function,
UserData,
Thread,
// GMod Types
Entity,
Vector,
Angle,
PhysObj,
Save,
Restore,
DamageInfo,
EffectData,
MoveData,
RecipientFilter,
UserCmd,
ScriptedVehicle,
Material,
Panel,
Particle,
ParticleEmitter,
Texture,
UserMsg,
ConVar,
IMesh,
Matrix,
Sound,
PixelVisHandle,
DLight,
Video,
File,
Locomotion,
Path,
NavArea,
SoundHandle,
NavLadder,
ParticleSystem,
ProjectedTexture,
PhysCollide,
SurfaceInfo,
MAX
}
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
#[repr(C)]
pub struct Vector {
x: f32,
y: f32,
z: f32
}
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
#[repr(C)]
pub struct Angle {
p: f32,
y: f32,
r: f32
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct TaggedUserData
{
pub data: *mut core::ffi::c_void,
pub r#type: UserData
}
pub trait CoercibleUserData {}
macro_rules! userdata {
($(UserData::$enum:ident => $struct:ident),+) => {
$(impl CoercibleUserData for $struct {})+
impl TaggedUserData {
/// Coerce this tagged UserData into its corresponding Rust struct, if possible.
///
/// This will perform a type check to ensure that the tagged userdata matches the user data you are coercing to.
pub fn coerce<'a, T: CoercibleUserData>(&self) -> Result<&mut T, UserData> {
match self.r#type {
$(UserData::$enum => Ok(unsafe { &mut *(self.data as *mut T) }),)+
_ => Err(self.r#type)
}
}
/// Coerce this tagged UserData into its corresponding Rust struct, if possible.
///
/// # Safety
/// This will NOT perform a type check to ensure that the tagged userdata matches the user data you are coercing to.
///
/// Coercing to the wrong type is undefined behaviour and is likely to crash your program.
pub unsafe fn coerce_unchecked<T: CoercibleUserData>(&self) -> &mut T {
&mut *(self.data as *mut T)
}
}
};
}
userdata! {
UserData::Vector => Vector,
UserData::Angle => Angle
}