Skip to content

Commit

Permalink
added bevy specific features and add mut_ptr stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
MalekiRe committed Oct 7, 2023
1 parent 9cf1e37 commit 39904bc
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 9 deletions.
1 change: 1 addition & 0 deletions crates/rune/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ similar = { version = "2.2.1", optional = true, features = ["inline", "bytes"] }
sha2 = { version = "0.10.6", optional = true }
base64 = { version = "0.21.0", optional = true }
rand = { version = "0.8.5", optional = true }
bevy = { git = "https://github.com/james-j-obrien/bevy", branch = "dynamic-term-builder", optional = true}

[dev-dependencies]
tokio = { version = "1.28.1", features = ["full"] }
Expand Down
51 changes: 51 additions & 0 deletions crates/rune/src/bevy_related.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use bevy::prelude::Mut;

impl<T: crate::compile::Named> crate::compile::Named for Mut<'_, T> {
const BASE_NAME: rune_core::RawStr = T::BASE_NAME;
}

impl<T: crate::Any> crate::Any for Mut<'static, T> {
fn type_hash() -> rune_core::Hash {
T::type_hash()
}
}

/// This is for internal use, need to create a second trait so that way
/// this trait can be implemented for *all* T, without causing the compiler
/// to cry about other types that implement the other UnsafeToValue
pub trait UnsafeToValue2: Sized {
/// Convert into a value.
///
/// # Safety
///
/// The value returned must not be used after the guard associated with it
/// has been dropped.
unsafe fn unsafe_to_value(
self,
) -> crate::runtime::VmResult<(crate::Value, crate::runtime::SharedPointerGuard)>;
}

impl<T: crate::__private::InstallWith> crate::__private::InstallWith for Mut<'static, T> {
fn install_with(
module: &mut crate::__private::Module,
) -> core::result::Result<(), crate::compile::ContextError> {
T::install_with(module)?;
Ok(())
}
}

impl<T: crate::Any> UnsafeToValue2 for Mut<'_, T> {
unsafe fn unsafe_to_value(
self,
) -> crate::runtime::VmResult<(crate::runtime::Value, crate::runtime::SharedPointerGuard)> {
let this: Mut<T> = unsafe { std::mem::transmute(self) };
let (shared, guard) =
match crate::runtime::try_result(crate::runtime::Shared::from_bevy_mut(this)) {
crate::runtime::VmResult::Ok(value) => value,
crate::runtime::VmResult::Err(err) => {
return crate::runtime::VmResult::Err(crate::runtime::VmError::from(err));
}
};
crate::runtime::VmResult::Ok((crate::runtime::Value::from(shared), guard))
}
}
3 changes: 3 additions & 0 deletions crates/rune/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,5 +618,8 @@ pub mod __private {
pub use rust_alloc::boxed::Box;
}

/// Bevy related specific traits and implementations
#[cfg(feature = "bevy")]
pub mod bevy_related;
#[cfg(test)]
mod tests;
103 changes: 94 additions & 9 deletions crates/rune/src/runtime/any_obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ impl AnyObj {
kind: AnyObjKind::Owned,
drop: drop_impl::<T>,
as_ptr: as_ptr_impl::<T>,
as_ptr_mut: as_ptr_mut_impl::<T>,
debug: debug_impl::<T>,
type_name: type_name_impl::<T>,
type_hash: type_hash_impl::<T>,
Expand Down Expand Up @@ -137,6 +138,7 @@ impl AnyObj {
kind: AnyObjKind::RefPtr,
drop: noop_drop_impl::<T>,
as_ptr: as_ptr_impl::<T>,
as_ptr_mut: as_ptr_mut_impl::<T>,
debug: debug_ref_impl::<T>,
type_name: type_name_impl::<T>,
type_hash: type_hash_impl::<T>,
Expand Down Expand Up @@ -175,6 +177,7 @@ impl AnyObj {
pub unsafe fn from_deref<T>(data: T) -> alloc::Result<Self>
where
T: Deref,
T: DerefMut,
T::Target: Any,
{
let data = {
Expand All @@ -187,6 +190,7 @@ impl AnyObj {
kind: AnyObjKind::RefPtr,
drop: drop_impl::<T>,
as_ptr: as_ptr_deref_impl::<T>,
as_ptr_mut: as_ptr_deref_mut_impl::<T>,
debug: debug_ref_impl::<T::Target>,
type_name: type_name_impl::<T::Target>,
type_hash: type_hash_impl::<T::Target>,
Expand Down Expand Up @@ -251,6 +255,36 @@ impl AnyObj {
kind: AnyObjKind::MutPtr,
drop: noop_drop_impl::<T>,
as_ptr: as_ptr_impl::<T>,
as_ptr_mut: as_ptr_mut_impl::<T>,
debug: debug_mut_impl::<T>,
type_name: type_name_impl::<T>,
type_hash: type_hash_impl::<T>,
},
data,
}
}

/// Construct an Any that wraps a bevy specific mutable pointer that does change detection.
///
/// # Safety
///
/// Caller must ensure that the returned `AnyObj` doesn't outlive the
/// reference it is wrapping.
#[cfg(feature = "bevy")]
pub unsafe fn from_bevy_mut<T>(data: bevy::prelude::Mut<T>) -> Self
where
T: Any,
{
let untyped = bevy::ecs::change_detection::MutUntyped::from(data);
let (ptr, _) = Box::into_raw_with_allocator(Box::try_new(untyped).unwrap());
let data = ptr::NonNull::new_unchecked(ptr as *mut _ as *mut ());

Self {
vtable: &AnyObjVtable {
kind: AnyObjKind::MutPtr,
drop: bevy_mut_drop::<T>,
as_ptr: as_bevy_ptr_impl::<T>,
as_ptr_mut: as_bevy_ptr_mut_impl::<T>,
debug: debug_mut_impl::<T>,
type_name: type_name_impl::<T>,
type_hash: type_hash_impl::<T>,
Expand Down Expand Up @@ -300,7 +334,8 @@ impl AnyObj {
vtable: &AnyObjVtable {
kind: AnyObjKind::MutPtr,
drop: drop_impl::<T>,
as_ptr: as_ptr_deref_mut_impl::<T>,
as_ptr: as_ptr_deref_impl::<T>,
as_ptr_mut: as_ptr_deref_mut_impl::<T>,
debug: debug_mut_impl::<T::Target>,
type_name: type_name_impl::<T::Target>,
type_hash: type_hash_impl::<T::Target>,
Expand Down Expand Up @@ -403,7 +438,8 @@ impl AnyObj {
T: Any,
{
unsafe {
(self.vtable.as_ptr)(self.data.as_ptr(), TypeId::of::<T>()).map(|v| &mut *(v as *mut _))
(self.vtable.as_ptr_mut)(self.data.as_ptr(), TypeId::of::<T>())
.map(|v| &mut *(v as *mut _))
}
}

Expand Down Expand Up @@ -431,8 +467,8 @@ impl AnyObj {
// Safety: invariants are checked at construction time.
// We have mutable access to the inner value because we have mutable
// access to the `Any`.
match unsafe { (self.vtable.as_ptr)(self.data.as_ptr(), expected) } {
Some(ptr) => Ok(ptr as *mut ()),
match unsafe { (self.vtable.as_ptr_mut)(self.data.as_ptr(), expected) } {
Some(ptr) => Ok(ptr),
None => Err(AnyObjError::Cast),
}
}
Expand Down Expand Up @@ -470,8 +506,8 @@ impl AnyObj {
// We have mutable access to the inner value because we have mutable
// access to the `Any`.
unsafe {
match (this.vtable.as_ptr)(this.data.as_ptr(), expected) {
Some(data) => Ok(data as *mut ()),
match (this.vtable.as_ptr_mut)(this.data.as_ptr(), expected) {
Some(data) => Ok(data),
None => {
let this = ManuallyDrop::into_inner(this);
Err((AnyObjError::Cast, this))
Expand Down Expand Up @@ -526,6 +562,9 @@ pub type DropFn = unsafe fn(*mut ());
/// The signature of a pointer coercion function.
pub type AsPtrFn = unsafe fn(this: *const (), expected: TypeId) -> Option<*const ()>;

/// The signature of a pointer coercion function, but mutably.
pub type AsPtrMutFn = unsafe fn(this: *mut (), expected: TypeId) -> Option<*mut ()>;

/// The signature of a descriptive type name function.
pub type DebugFn = fn(&mut fmt::Formatter<'_>) -> fmt::Result;

Expand Down Expand Up @@ -558,6 +597,8 @@ pub struct AnyObjVtable {
drop: DropFn,
/// Punt the inner pointer to the type corresponding to the type hash.
as_ptr: AsPtrFn,
/// Punt the inner pointer to the type corresponding to the type hash, but mutably,
as_ptr_mut: AsPtrMutFn,
/// Type information for diagnostics.
debug: DebugFn,
/// Type name accessor.
Expand All @@ -581,6 +622,41 @@ where
}
}

fn as_ptr_mut_impl<T>(this: *mut (), expected: TypeId) -> Option<*mut ()>
where
T: Any,
{
if expected == TypeId::of::<T>() {
Some(this)
} else {
None
}
}

#[cfg(feature = "bevy")]
fn as_bevy_ptr_impl<T: 'static>(this: *const (), expected: TypeId) -> Option<*const ()> {
if expected == TypeId::of::<T>() {
let this = this as *const () as *const bevy::ecs::change_detection::MutUntyped;
let this = unsafe { &*this }.as_ref();
Some(unsafe { this.as_ptr() } as *const _ as *const ())
} else {
None
}
}

#[cfg(feature = "bevy")]
fn as_bevy_ptr_mut_impl<T: 'static>(this: *mut (), expected: TypeId) -> Option<*mut ()> {
use bevy::prelude::DetectChangesMut;
if expected == TypeId::of::<T>() {
let this = this as *mut () as *mut bevy::ecs::change_detection::MutUntyped;
unsafe { DetectChangesMut::set_changed(&mut *this) }
let this = unsafe { DetectChangesMut::bypass_change_detection(&mut *this) };
Some(this.as_ptr() as *mut _ as *mut ())
} else {
None
}
}

fn as_ptr_deref_impl<T: Deref>(this: *const (), expected: TypeId) -> Option<*const ()>
where
T::Target: Any,
Expand All @@ -593,20 +669,29 @@ where
}
}

fn as_ptr_deref_mut_impl<T: DerefMut>(this: *const (), expected: TypeId) -> Option<*const ()>
fn as_ptr_deref_mut_impl<T: DerefMut>(this: *mut (), expected: TypeId) -> Option<*mut ()>
where
T::Target: Any,
{
if expected == TypeId::of::<T::Target>() {
let guard = this as *mut T;
unsafe { Some((*guard).deref_mut() as *const _ as *const ()) }
unsafe { Some((*guard).deref_mut() as *mut _ as *mut ()) }
} else {
None
}
}

fn noop_drop_impl<T>(_: *mut ()) {}

#[cfg(feature = "bevy")]
fn bevy_mut_drop<T>(this: *mut ()) {
unsafe {
drop(Box::from_raw_in(
this as *mut bevy::ecs::change_detection::MutUntyped,
Global,
));
}
}

fn debug_impl<T>(f: &mut fmt::Formatter<'_>) -> fmt::Result
where
T: Any,
Expand Down
19 changes: 19 additions & 0 deletions crates/rune/src/runtime/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,25 @@ impl Shared<AnyObj> {
Self::unsafe_from_any_pointer(AnyObj::from_mut(data))
}

/// Construct a `Shared<Any>` from a bevy specific mutable pointer that does change detection, this will be "taken"
/// once the returned guard is dropped.
///
/// # Safety
///
/// The reference must be valid for the duration of the guard.
///
/// # Examples
///
#[cfg(feature = "bevy")]
pub unsafe fn from_bevy_mut<T>(
data: bevy::prelude::Mut<T>,
) -> alloc::Result<(Self, SharedPointerGuard)>
where
T: Any,
{
Self::unsafe_from_any_pointer(AnyObj::from_bevy_mut(data))
}

/// Construct a `Shared<Any>` from an Any which is expected to wrap a
/// pointer, that will be "taken" once the returned guard is dropped.
///
Expand Down

0 comments on commit 39904bc

Please sign in to comment.