use fxhash::FxHashMap;
use fyrox_core::pool::Handle;
use fyrox_core::{
parking_lot::{Mutex, MutexGuard},
reflect::prelude::*,
SafeLock, TypeUuidProvider, Uuid,
};
use std::sync::Arc;
pub trait ConstructorProvider<T, Ctx>: TypeUuidProvider + Default + Reflect {
fn constructor() -> GraphNodeConstructor<T, Ctx>;
}
pub enum VariantResult<Node> {
Owned(Node),
Handle(Handle<Node>),
}
impl<Node> From<Node> for VariantResult<Node> {
fn from(node: Node) -> Self {
VariantResult::Owned(node)
}
}
impl<Node> From<Handle<Node>> for VariantResult<Node> {
fn from(value: Handle<Node>) -> Self {
VariantResult::Handle(value)
}
}
pub type Constructor<Node> = Arc<dyn Fn() -> Node + Send + Sync>;
pub type VariantConstructor<Node, Ctx> = Arc<dyn Fn(&mut Ctx) -> VariantResult<Node> + Send + Sync>;
pub struct Variant<Node, Ctx> {
pub name: String,
pub constructor: VariantConstructor<Node, Ctx>,
}
pub struct GraphNodeConstructor<Node, Ctx> {
pub default: Constructor<Node>,
pub variants: Vec<Variant<Node, Ctx>>,
pub group: &'static str,
pub assembly_name: &'static str,
}
impl<Node, Ctx> GraphNodeConstructor<Node, Ctx> {
pub fn new<Inner>() -> Self
where
Node: From<Inner>,
Inner: ConstructorProvider<Node, Ctx>,
{
Self {
default: Arc::new(|| Node::from(Inner::default())),
variants: vec![],
group: "",
assembly_name: Inner::type_assembly_name(),
}
}
pub fn with_group(mut self, group: &'static str) -> Self {
self.group = group;
self
}
pub fn with_variant<F>(mut self, name: impl AsRef<str>, variant: F) -> Self
where
F: Fn(&mut Ctx) -> VariantResult<Node> + Send + Sync + 'static,
{
self.variants.push(Variant {
name: name.as_ref().to_string(),
constructor: Arc::new(variant),
});
self
}
}
pub struct GraphNodeConstructorContainer<Node, Ctx> {
map: Mutex<FxHashMap<Uuid, GraphNodeConstructor<Node, Ctx>>>,
}
impl<Node, Ctx> Default for GraphNodeConstructorContainer<Node, Ctx> {
fn default() -> Self {
Self {
map: Default::default(),
}
}
}
impl<Node, Ctx> GraphNodeConstructorContainer<Node, Ctx> {
pub fn add<Inner>(&self)
where
Inner: ConstructorProvider<Node, Ctx>,
{
let previous = self
.map
.safe_lock()
.insert(Inner::type_uuid(), Inner::constructor());
assert!(previous.is_none());
}
pub fn add_custom(&self, type_uuid: Uuid, constructor: GraphNodeConstructor<Node, Ctx>) {
self.map.safe_lock().insert(type_uuid, constructor);
}
pub fn remove(&self, type_uuid: Uuid) {
self.map.safe_lock().remove(&type_uuid);
}
pub fn try_create(&self, type_uuid: &Uuid) -> Option<Node> {
self.map
.safe_lock()
.get_mut(type_uuid)
.map(|c| (c.default)())
}
pub fn len(&self) -> usize {
self.map.safe_lock().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn map(&self) -> MutexGuard<'_, FxHashMap<Uuid, GraphNodeConstructor<Node, Ctx>>> {
self.map.safe_lock()
}
}