Skip to content

Commit

Permalink
Move as much as possible into bevy_related
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Oct 7, 2023
1 parent 39904bc commit 7e6c0b7
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 132 deletions.
157 changes: 118 additions & 39 deletions crates/rune/src/bevy_related.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,130 @@
use core::any::TypeId;
use core::fmt;

use bevy::ecs::change_detection::MutUntyped;
use bevy::prelude::Mut;

impl<T: crate::compile::Named> crate::compile::Named for Mut<'_, T> {
const BASE_NAME: rune_core::RawStr = T::BASE_NAME;
use crate::alloc::alloc::Global;
use crate::alloc::{self, Box};
use crate::any::Any;
use crate::compile::Named;
use crate::hash::Hash;
use crate::runtime::{
AnyObj, AnyObjKind, AnyObjVtable, RawStr, Shared, SharedPointerGuard, Value, VmResult,
};

/// Unsafely convert a bevy mutable reference into a value and a guard.
///
/// # Safety
///
/// The value returned must not be used after the guard associated with it has
/// been dropped.
pub unsafe fn bevy_mut_to_value<T>(this: Mut<'_, T>) -> VmResult<(Value, SharedPointerGuard)>
where
T: Any,
{
let (shared, guard) = vm_try!(from_bevy_mut(this));
VmResult::Ok((Value::from(shared), guard))
}

/// 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
///
unsafe fn from_bevy_mut<T>(
data: bevy::prelude::Mut<'_, T>,
) -> alloc::Result<(Shared<AnyObj>, SharedPointerGuard)>
where
T: Any,
{
Shared::unsafe_from_any_pointer(anyobj_from_bevy_mut(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.
unsafe fn anyobj_from_bevy_mut<T>(data: Mut<'_, T>) -> AnyObj
where
T: Any,
{
let untyped = MutUntyped::from(data);
let (ptr, _) = Box::into_raw_with_allocator(Box::try_new(untyped).unwrap());
let data = ptr as *const _ as *const ();

let 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>,
};

AnyObj::new_raw(vtable, data)
}

impl<T: crate::Any> crate::Any for Mut<'static, T> {
fn type_hash() -> rune_core::Hash {
T::type_hash()
fn bevy_mut_drop<T>(this: *mut ()) {
unsafe {
drop(Box::from_raw_in(this as *mut MutUntyped<'static>, Global));
}
}

/// 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(())
fn as_bevy_ptr_impl<T>(this: *const (), expected: TypeId) -> Option<*const ()>
where
T: ?Sized + 'static,
{
if expected == TypeId::of::<T>() {
unsafe {
let this = this as *const () as *const MutUntyped<'static>;
Some((*this).as_ref().as_ptr() as *const _ as *const ())
}
} else {
None
}
}

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))
fn as_bevy_ptr_mut_impl<T>(this: *mut (), expected: TypeId) -> Option<*mut ()>
where
T: ?Sized + 'static,
{
if expected == TypeId::of::<T>() {
unsafe {
let this = this as *mut () as *mut MutUntyped<'static>;
// NB: `as_mut` calls `set_changed`.
Some((*this).as_mut().as_ptr() as *mut ())
}
} else {
None
}
}

fn debug_mut_impl<T>(f: &mut fmt::Formatter<'_>) -> fmt::Result
where
T: ?Sized + Named,
{
write!(f, "&mut {}", T::BASE_NAME)
}

fn type_name_impl<T>() -> RawStr
where
T: ?Sized + Named,
{
T::BASE_NAME
}

fn type_hash_impl<T>() -> Hash
where
T: ?Sized + Any,
{
T::type_hash()
}
3 changes: 2 additions & 1 deletion crates/rune/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,8 +618,9 @@ pub mod __private {
pub use rust_alloc::boxed::Box;
}

/// Bevy related specific traits and implementations
/// Bevy support.
#[cfg(feature = "bevy")]
pub mod bevy_related;

#[cfg(test)]
mod tests;
2 changes: 1 addition & 1 deletion crates/rune/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub use self::access::{
};

mod any_obj;
pub use self::any_obj::{AnyObj, AnyObjError, AnyObjVtable};
pub use self::any_obj::{AnyObj, AnyObjError, AnyObjKind, AnyObjVtable};

mod args;
pub use self::args::Args;
Expand Down
79 changes: 8 additions & 71 deletions crates/rune/src/runtime/any_obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,35 +264,6 @@ impl AnyObj {
}
}

/// 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>,
},
data,
}
}

/// Construct an Any that wraps a DerefMut type, behaving as the Target of
/// the DerefMut implementation
///
Expand Down Expand Up @@ -575,7 +546,7 @@ pub type TypeNameFn = fn() -> RawStr;
pub type TypeHashFn = fn() -> Hash;

/// The kind of the stored value in the `AnyObj`.
enum AnyObjKind {
pub enum AnyObjKind {
/// A boxed value that is owned.
Owned,
/// A pointer (`*const T`).
Expand All @@ -592,19 +563,19 @@ enum AnyObjKind {
#[repr(C)]
pub struct AnyObjVtable {
/// The kind of the object being stored. Determines how it can be accessed.
kind: AnyObjKind,
pub kind: AnyObjKind,
/// The underlying drop implementation for the stored type.
drop: DropFn,
pub drop: DropFn,
/// Punt the inner pointer to the type corresponding to the type hash.
as_ptr: AsPtrFn,
pub as_ptr: AsPtrFn,
/// Punt the inner pointer to the type corresponding to the type hash, but mutably,
as_ptr_mut: AsPtrMutFn,
pub as_ptr_mut: AsPtrMutFn,
/// Type information for diagnostics.
debug: DebugFn,
pub debug: DebugFn,
/// Type name accessor.
type_name: TypeNameFn,
pub type_name: TypeNameFn,
/// Get the type hash of the stored type.
type_hash: TypeHashFn,
pub type_hash: TypeHashFn,
}

unsafe fn drop_impl<T>(this: *mut ()) {
Expand Down Expand Up @@ -633,30 +604,6 @@ where
}
}

#[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 @@ -682,16 +629,6 @@ where
}
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
23 changes: 3 additions & 20 deletions crates/rune/src/runtime/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,32 +450,15 @@ 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.
///
/// # Safety
///
/// The reference must be valid for the duration of the guard.
unsafe fn unsafe_from_any_pointer(any: AnyObj) -> alloc::Result<(Self, SharedPointerGuard)> {
pub(crate) unsafe fn unsafe_from_any_pointer(
any: AnyObj,
) -> alloc::Result<(Self, SharedPointerGuard)> {
let shared = SharedBox {
access: Access::new(true),
count: Cell::new(2),
Expand Down

0 comments on commit 7e6c0b7

Please sign in to comment.