Skip to content

Commit 8f79d53

Browse files
committed
Fix global retention of AnyBufferAccessInterface
Signed-off-by: Michael X. Grey <[email protected]>
1 parent 70cec2c commit 8f79d53

File tree

2 files changed

+72
-21
lines changed

2 files changed

+72
-21
lines changed

src/buffer/any_buffer.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717

1818
use std::{
1919
any::{Any, TypeId},
20+
collections::HashMap,
2021
ops::RangeBounds,
21-
sync::{Arc, OnceLock},
22+
sync::{Arc, OnceLock, Mutex},
2223
};
2324

2425
use bevy_ecs::{
@@ -40,7 +41,7 @@ use crate::{
4041
pub struct AnyBuffer {
4142
pub(crate) scope: Entity,
4243
pub(crate) source: Entity,
43-
pub(crate) interface: &'static (dyn AnyBufferStorageAccessInterface + Send + Sync)
44+
pub(crate) interface: &'static (dyn AnyBufferAccessInterface + Send + Sync)
4445
}
4546

4647
impl std::fmt::Debug for AnyBuffer {
@@ -70,7 +71,7 @@ impl AnyBuffer {
7071

7172
impl<T: 'static + Send + Sync + Any> From<Buffer<T>> for AnyBuffer {
7273
fn from(value: Buffer<T>) -> Self {
73-
let interface = AnyBufferStorageAccessImpl::<T>::get_interface();
74+
let interface = AnyBufferAccessImpl::<T>::get_interface();
7475
AnyBuffer {
7576
scope: value.scope,
7677
source: value.source,
@@ -90,7 +91,7 @@ pub struct AnyBufferKey {
9091
session: Entity,
9192
accessor: Entity,
9293
lifecycle: Option<Arc<BufferAccessLifecycle>>,
93-
interface: &'static (dyn AnyBufferStorageAccessInterface + Send + Sync),
94+
interface: &'static (dyn AnyBufferAccessInterface + Send + Sync),
9495
}
9596

9697
impl std::fmt::Debug for AnyBufferKey {
@@ -125,7 +126,7 @@ impl AnyBufferKey {
125126

126127
impl<T: 'static + Send + Sync + Any> From<BufferKey<T>> for AnyBufferKey {
127128
fn from(value: BufferKey<T>) -> Self {
128-
let interface = AnyBufferStorageAccessImpl::<T>::get_interface();
129+
let interface = AnyBufferAccessImpl::<T>::get_interface();
129130
AnyBufferKey {
130131
buffer: value.buffer,
131132
session: value.session,
@@ -589,7 +590,7 @@ impl<'w, 's, T: 'static + Send + Sync + Any> AnyBufferAccessMut<'w, 's> for Buff
589590
}
590591
}
591592

592-
pub(crate) trait AnyBufferStorageAccessInterface {
593+
pub(crate) trait AnyBufferAccessInterface {
593594
fn message_type_id(&self) -> TypeId;
594595

595596
fn message_type_name(&self) -> &'static str;
@@ -612,18 +613,26 @@ pub(crate) trait AnyBufferStorageAccessInterface {
612613
) -> Box<dyn AnyBufferAccessMutState>;
613614
}
614615

615-
struct AnyBufferStorageAccessImpl<T>(std::marker::PhantomData<T>);
616+
struct AnyBufferAccessImpl<T>(std::marker::PhantomData<T>);
616617

617-
impl<T: 'static + Send + Sync + Any> AnyBufferStorageAccessImpl<T> {
618-
fn get_interface() -> &'static (dyn AnyBufferStorageAccessInterface + Send + Sync) {
619-
let once: OnceLock<&'static AnyBufferStorageAccessImpl<T>> = OnceLock::new();
620-
*once.get_or_init(|| {
621-
Box::leak(Box::new(AnyBufferStorageAccessImpl(Default::default())))
618+
impl<T: 'static + Send + Sync + Any> AnyBufferAccessImpl<T> {
619+
fn get_interface() -> &'static (dyn AnyBufferAccessInterface + Send + Sync) {
620+
const INTERFACE_MAP: OnceLock<Mutex<HashMap<
621+
TypeId,
622+
&'static (dyn AnyBufferAccessInterface + Send + Sync)
623+
>>> = OnceLock::new();
624+
let binding = INTERFACE_MAP;
625+
626+
let interfaces = binding.get_or_init(|| Mutex::default());
627+
628+
let mut interfaces_mut = interfaces.lock().unwrap();
629+
*interfaces_mut.entry(TypeId::of::<T>()).or_insert_with(|| {
630+
Box::leak(Box::new(AnyBufferAccessImpl::<T>(Default::default())))
622631
})
623632
}
624633
}
625634

626-
impl<T: 'static + Send + Sync + Any> AnyBufferStorageAccessInterface for AnyBufferStorageAccessImpl<T> {
635+
impl<T: 'static + Send + Sync + Any> AnyBufferAccessInterface for AnyBufferAccessImpl<T> {
627636
fn message_type_id(&self) -> TypeId {
628637
TypeId::of::<T>()
629638
}

src/buffer/json_buffer.rs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,70 @@
1515
*
1616
*/
1717

18+
use std::{
19+
any::TypeId,
20+
collections::HashMap,
21+
sync::{Mutex, OnceLock},
22+
};
23+
1824
use bevy_ecs::prelude::Entity;
1925

20-
use schemars::schema::Schema;
26+
use schemars::{
27+
gen::SchemaGenerator,
28+
schema::Schema,
29+
JsonSchema,
30+
};
31+
32+
use serde::{de::DeserializeOwned, Serialize};
2133

2234
#[derive(Clone, Copy, Debug)]
2335
pub struct JsonBuffer {
2436
pub(crate) scope: Entity,
2537
pub(crate) source: Entity,
26-
pub(crate) interface: &'static dyn JsonInterface,
38+
pub(crate) interface: &'static (dyn JsonBufferAccessInterface + Send + Sync),
2739
}
2840

29-
pub(crate) trait JsonInterface {
30-
fn message_type(&self) -> &str;
31-
fn schema(&self) -> &Schema;
41+
pub(crate) trait JsonBufferAccessInterface {
42+
fn message_type_name(&self) -> &str;
43+
fn message_type_id(&self) -> TypeId;
44+
fn schema(&self, generator: &mut SchemaGenerator) -> &'static Schema;
3245
}
3346

34-
impl<'a> std::fmt::Debug for &'a dyn JsonInterface {
47+
impl<'a> std::fmt::Debug for &'a (dyn JsonBufferAccessInterface + Send + Sync) {
3548
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3649
f
3750
.debug_struct("Message Properties")
38-
.field("type", &self.message_type())
39-
.field("schema", self.schema())
51+
.field("type", &self.message_type_name())
4052
.finish()
4153
}
4254
}
55+
56+
struct JsonBufferAccessImpl<T>(std::marker::PhantomData<T>);
57+
58+
impl<T: 'static + Send + Sync + Serialize + DeserializeOwned + JsonSchema> JsonBufferAccessImpl<T> {
59+
60+
}
61+
62+
impl<T: 'static + Send + Sync + Serialize + DeserializeOwned + JsonSchema> JsonBufferAccessInterface for JsonBufferAccessImpl<T> {
63+
fn message_type_name(&self) -> &str {
64+
std::any::type_name::<T>()
65+
}
66+
67+
fn message_type_id(&self) -> TypeId {
68+
TypeId::of::<T>()
69+
}
70+
71+
fn schema(&self, generator: &mut SchemaGenerator) -> &'static Schema {
72+
// We use a const map so that we only need to generate the schema once
73+
// per message type.
74+
const SCHEMA_MAP: OnceLock<Mutex<HashMap<TypeId, &'static Schema>>> = OnceLock::new();
75+
let binding = SCHEMA_MAP;
76+
77+
let schemas = binding.get_or_init(|| Mutex::default());
78+
79+
let mut schemas_mut = schemas.lock().unwrap();
80+
*schemas_mut.entry(TypeId::of::<T>()).or_insert_with(|| {
81+
Box::leak(Box::new(generator.subschema_for::<T>()))
82+
})
83+
}
84+
}

0 commit comments

Comments
 (0)