Skip to content

Commit c805a2b

Browse files
committed
add support for list
1 parent 05001fc commit c805a2b

File tree

10 files changed

+296
-158
lines changed

10 files changed

+296
-158
lines changed

assets/scripts/bevy_api.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ function on_event()
1515
print(script)
1616
print(world)
1717

18+
print(world:test_vec({entity, entity})[1])
19+
1820

1921
local my_component_type = world:get_type_by_name("MyComponent")
2022

crates/bevy_mod_scripting_core/src/bindings/allocator.rs

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::any::{Any, TypeId};
55
use std::cell::UnsafeCell;
66
use std::collections::HashMap;
77
use std::fmt::{Display, Formatter};
8+
use std::io::Read;
89
use std::sync::Arc;
910

1011
#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
@@ -18,6 +19,10 @@ impl ReflectAllocationId {
1819
pub(crate) fn new(id: usize) -> Self {
1920
Self(Arc::new(id))
2021
}
22+
23+
pub fn strong_count(&self) -> usize {
24+
Arc::strong_count(&self.0)
25+
}
2126
}
2227

2328
/// Pointer which owns the value it points to, and will deallocate it when dropped
@@ -45,29 +50,28 @@ impl<T: ?Sized> Drop for OwningPtr<T> {
4550
}
4651

4752
// yikes, the indirection. I need this to store boxed values too though
48-
#[derive(Clone, Debug)]
49-
pub enum ReflectAllocation {
50-
Double(Arc<OwningPtr<dyn PartialReflect>>),
51-
Single(Arc<UnsafeCell<dyn PartialReflect>>),
52-
}
53+
#[derive(Debug)]
54+
pub struct ReflectAllocation(Box<UnsafeCell<dyn PartialReflect>>);
5355

54-
unsafe impl Send for ReflectAllocation {}
56+
// unsafe impl Send for ReflectAllocation {}
5557
unsafe impl Sync for ReflectAllocation {}
5658

5759
impl ReflectAllocation {
5860
pub fn get_ptr(&self) -> *mut dyn PartialReflect {
59-
match self {
60-
ReflectAllocation::Double(v) => v.ptr,
61-
ReflectAllocation::Single(v) => v.get(),
62-
}
61+
self.0.as_ref().get()
6362
}
64-
pub fn new(value: Arc<UnsafeCell<dyn PartialReflect>>) -> Self {
65-
Self::Single(value)
63+
64+
pub fn new(value: Box<dyn PartialReflect>) -> Self {
65+
let value: Box<UnsafeCell<dyn PartialReflect>> = unsafe { std::mem::transmute(value) };
66+
Self(value)
6667
}
6768

68-
pub fn new_boxed(value: Box<dyn PartialReflect>) -> Self {
69-
let ptr = Box::leak::<'static>(value);
70-
Self::Double(Arc::new(unsafe { OwningPtr::new(ptr) }))
69+
/// Takes the value out of the allocation.
70+
///
71+
/// # Safety
72+
/// - Must only be done if no other references to this allocation exist at the same time
73+
pub unsafe fn take(self) -> Box<dyn PartialReflect> {
74+
std::mem::transmute(self.0)
7175
}
7276
}
7377

@@ -113,36 +117,21 @@ pub struct ReflectAllocator {
113117
impl ReflectAllocator {
114118
/// Allocates a new [`Reflect`] value and returns an [`AllocationId`] which can be used to access it later.
115119
/// Use [`Self::allocate_boxed`] if you already have an allocated boxed value.
116-
pub fn allocate<T: PartialReflect>(
117-
&mut self,
118-
value: T,
119-
) -> (ReflectAllocationId, ReflectAllocation) {
120-
let type_id = value.get_represented_type_info().map(|i| i.type_id());
121-
122-
let id = ReflectAllocationId::new(self.allocations.len());
123-
let index = id.id();
124-
let value = ReflectAllocation::new(Arc::new(UnsafeCell::new(value)));
125-
self.allocations.insert(id.clone(), value.clone());
126-
if let Some(type_id) = type_id {
127-
self.types.insert(index, type_id);
128-
}
129-
(id, value)
120+
pub fn allocate<T: PartialReflect>(&mut self, value: T) -> ReflectAllocationId {
121+
self.allocate_boxed(Box::new(value))
130122
}
131123

132-
pub fn allocate_boxed(
133-
&mut self,
134-
value: Box<dyn PartialReflect>,
135-
) -> (ReflectAllocationId, ReflectAllocation) {
124+
pub fn allocate_boxed(&mut self, value: Box<dyn PartialReflect>) -> ReflectAllocationId {
136125
let type_id = value.get_represented_type_info().map(|i| i.type_id());
137126

138127
let id = ReflectAllocationId::new(self.allocations.len());
139128
let index = id.id();
140-
let value = ReflectAllocation::new_boxed(value);
141-
self.allocations.insert(id.clone(), value.clone());
129+
let value = ReflectAllocation::new(value);
130+
self.allocations.insert(id.clone(), value);
142131
if let Some(type_id) = type_id {
143132
self.types.insert(index, type_id);
144133
}
145-
(id, value)
134+
id
146135
}
147136

148137
// /// Moves the given boxed [`PartialReflect`] value into the allocator, returning an [`AllocationId`] which can be used to access it later
@@ -168,16 +157,33 @@ impl ReflectAllocator {
168157
// (id, allocation)
169158
// }
170159

171-
pub fn get(&self, id: &ReflectAllocationId) -> Option<ReflectAllocation> {
172-
self.allocations.get(id).cloned()
160+
// pub fn get(&self, id: &ReflectAllocationId) -> Option<ReflectAllocation> {
161+
// self.allocations.get(id).cloned()
162+
// }
163+
164+
pub fn insert(
165+
&mut self,
166+
id: ReflectAllocationId,
167+
value: ReflectAllocation,
168+
) -> Option<ReflectAllocation> {
169+
self.allocations.insert(id, value)
170+
}
171+
172+
pub fn remove(&mut self, id: &ReflectAllocationId) -> Option<ReflectAllocation> {
173+
println!("removing {:?}", id);
174+
self.allocations.remove(id)
173175
}
174176

175177
pub fn get_type_id(&self, id: &ReflectAllocationId) -> Option<TypeId> {
176178
self.types.get(&id.id()).cloned()
177179
}
178180

179-
pub fn get_mut(&self, id: &ReflectAllocationId) -> Option<ReflectAllocation> {
180-
self.allocations.get(id).cloned()
181+
pub fn get_mut(&mut self, id: &ReflectAllocationId) -> Option<&mut ReflectAllocation> {
182+
self.allocations.get_mut(id)
183+
}
184+
185+
pub fn get(&self, id: &ReflectAllocationId) -> Option<&ReflectAllocation> {
186+
self.allocations.get(id)
181187
}
182188

183189
/// Deallocates the [`PartialReflect`] value with the given [`AllocationId`]
@@ -199,7 +205,7 @@ mod test {
199205
#[test]
200206
fn test_reflect_allocator_garbage_clean() {
201207
let mut allocator = ReflectAllocator::default();
202-
let (id, _) = allocator.allocate(0);
208+
let id = allocator.allocate(0);
203209
assert_eq!(allocator.allocations.len(), 1);
204210
drop(id);
205211
allocator.clean_garbage_allocations();
@@ -209,7 +215,7 @@ mod test {
209215
#[test]
210216
fn test_reflect_allocator_garbage_clean_no_garbage() {
211217
let mut allocator = ReflectAllocator::default();
212-
let (_id, _) = allocator.allocate(0);
218+
let _id = allocator.allocate(0);
213219
assert_eq!(allocator.allocations.len(), 1);
214220
allocator.clean_garbage_allocations();
215221
assert_eq!(allocator.allocations.len(), 1);

crates/bevy_mod_scripting_core/src/bindings/function.rs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl CallableWithAccess for DynamicFunction<'_> {
119119
Return::Ref(ref_) => ref_.into_script_value(world),
120120
Return::Mut(mut_ref) => mut_ref.into_script_value(world),
121121
})?
122-
.map_err(|e| InteropError::function_interop_error(self.info(), None, e).into())
122+
.map_err(|e| InteropError::function_interop_error(self.info(), None, e))
123123
}
124124
}
125125

@@ -159,8 +159,12 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
159159
match value {
160160
// TODO: I'd see the logic be a bit cleaner, this if is needed to support 'Raw' ScriptValue arguments
161161
// as we do not want to claim any access since we're not using the value yet
162+
163+
// for owned values the from_script_value impl for ReflectReferences will deal with the case
164+
// here we try to make an actual reference, or otherwise clone the value
162165
ScriptValue::Reference(arg_ref)
163-
if argument_info.type_id() != TypeId::of::<ScriptValue>() =>
166+
if argument_info.type_id() != TypeId::of::<ScriptValue>()
167+
&& matches!(argument_info.ownership(), Ownership::Mut | Ownership::Ref) =>
164168
{
165169
let access_id = ReflectAccessId::for_reference(arg_ref.base.base_id.clone())
166170
.ok_or_else(|| {
@@ -171,30 +175,39 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
171175
)
172176
})?;
173177

174-
let is_write = matches!(argument_info.ownership(), Ownership::Mut);
175-
176-
let success = if is_write {
177-
world.claim_write_access(access_id)
178-
} else {
179-
world.claim_read_access(access_id)
178+
let arg = match argument_info.ownership() {
179+
Ownership::Ref => {
180+
if world.claim_read_access(access_id) {
181+
accesses.push((access_id, Ownership::Ref));
182+
let ref_ = unsafe { arg_ref.reflect_unsafe(world.clone()) };
183+
if let Ok(ref_) = ref_ {
184+
Ok(ArgValue::Ref(ref_))
185+
} else {
186+
Err(ref_.expect_err("invariant"))
187+
}
188+
} else {
189+
Err(InteropError::cannot_claim_access(arg_ref.base.clone()))
190+
}
191+
}
192+
Ownership::Mut => {
193+
if world.claim_write_access(access_id) {
194+
accesses.push((access_id, Ownership::Mut));
195+
let mut_ref = unsafe { arg_ref.reflect_mut_unsafe(world.clone()) };
196+
if let Ok(mut_ref) = mut_ref {
197+
Ok(ArgValue::Mut(mut_ref))
198+
} else {
199+
Err(mut_ref.expect_err("invariant"))
200+
}
201+
} else {
202+
Err(InteropError::cannot_claim_access(arg_ref.base.clone()))
203+
}
204+
}
205+
_ => unreachable!(),
180206
};
181207

182-
if !success {
183-
release_accesses(&mut accesses);
184-
return Err(InteropError::function_interop_error(
185-
function_info,
186-
Some(argument_info),
187-
InteropError::cannot_claim_access(arg_ref.base.clone()),
188-
)
189-
.into());
190-
}
191-
192-
accesses.push((access_id, argument_info.ownership()));
208+
// TODO: check if the value is actually a `dyn Reflect` and not a dynamic
193209

194-
let val =
195-
unsafe { arg_ref.clone().into_arg_value(world.clone(), argument_info) };
196-
let val = match val {
197-
Ok(v) => v,
210+
match arg {
198211
Err(e) => {
199212
release_accesses(&mut accesses);
200213
return Err(InteropError::function_interop_error(
@@ -203,8 +216,8 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
203216
e,
204217
));
205218
}
206-
};
207-
arg_list.push(val);
219+
Ok(arg) => arg_list.push(arg),
220+
}
208221
}
209222
ScriptValue::World => {
210223
arg_list.push(ArgValue::Owned(Box::new(WorldCallbackAccess::from_guard(

crates/bevy_mod_scripting_core/src/bindings/pretty_print.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,10 @@ impl ReflectReferencePrinter {
293293
ReflectRef::Function(f) => {
294294
output.push_str("Function(");
295295
output.push_str(
296-
&f.info()
296+
f.info()
297297
.name()
298298
.unwrap_or(&Cow::Borrowed("<unnamed function>"))
299-
.to_string(),
299+
.as_ref(),
300300
);
301301
output.push(')');
302302
}
@@ -327,7 +327,7 @@ macro_rules! impl_dummy_display (
327327
($t:ty) => {
328328
impl std::fmt::Display for $t {
329329
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330-
write!(f, "Displaying {} without world access: {:#?}", stringify!($t), self);
330+
write!(f, "Displaying {} without world access: {:#?}", stringify!($t), self)?;
331331
Ok(())
332332
}
333333
}
@@ -399,6 +399,16 @@ impl DisplayWithWorld for ScriptValue {
399399
ScriptValue::String(cow) => cow.to_string(),
400400
ScriptValue::World => "World".to_owned(),
401401
ScriptValue::Error(script_error) => script_error.to_string(),
402+
ScriptValue::List(vec) => {
403+
let mut string = String::new();
404+
ReflectReferencePrinter::pretty_print_key_values(
405+
BracketType::Square,
406+
vec.iter()
407+
.map(|v| (None::<String>, v.display_value_with_world(world.clone()))),
408+
&mut string,
409+
);
410+
string
411+
}
402412
}
403413
}
404414
}

0 commit comments

Comments
 (0)