Skip to main content

fyrox_graph/
constructor.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use fxhash::FxHashMap;
22use fyrox_core::pool::Handle;
23use fyrox_core::{
24    parking_lot::{Mutex, MutexGuard},
25    reflect::prelude::*,
26    SafeLock, TypeUuidProvider, Uuid,
27};
28use std::sync::Arc;
29
30pub trait ConstructorProvider<T, Ctx>: TypeUuidProvider + Default + Reflect {
31    fn constructor() -> GraphNodeConstructor<T, Ctx>;
32}
33
34pub enum VariantResult<Node> {
35    Owned(Node),
36    Handle(Handle<Node>),
37}
38
39impl<Node> From<Node> for VariantResult<Node> {
40    fn from(node: Node) -> Self {
41        VariantResult::Owned(node)
42    }
43}
44
45impl<Node> From<Handle<Node>> for VariantResult<Node> {
46    fn from(value: Handle<Node>) -> Self {
47        VariantResult::Handle(value)
48    }
49}
50
51/// Shared closure that creates a node of some type.
52pub type Constructor<Node> = Arc<dyn Fn() -> Node + Send + Sync>;
53
54pub type VariantConstructor<Node, Ctx> = Arc<dyn Fn(&mut Ctx) -> VariantResult<Node> + Send + Sync>;
55
56/// Constructor variant.
57pub struct Variant<Node, Ctx> {
58    /// Name of the variant.
59    pub name: String,
60    /// Boxed type constructor.
61    pub constructor: VariantConstructor<Node, Ctx>,
62}
63
64/// Node constructor creates scene nodes in various states.
65pub struct GraphNodeConstructor<Node, Ctx> {
66    /// A boxed type constructor that returns a node in default state. This constructor is used at
67    /// deserialization stage.
68    pub default: Constructor<Node>,
69
70    /// A set of node constructors that returns specific variants of the same node type. Could be
71    /// used to pre-define specific variations of nodes, for example a `Mesh` node could have
72    /// different surfaces (sphere, cube, cone, etc.). It is used by the editor, this collection must
73    /// have at least one item to be shown in the editor.
74    pub variants: Vec<Variant<Node, Ctx>>,
75
76    /// Name of the group the type belongs to.
77    pub group: &'static str,
78
79    /// A name of the assembly this node constructor is from.
80    pub assembly_name: &'static str,
81}
82
83impl<Node, Ctx> GraphNodeConstructor<Node, Ctx> {
84    /// Creates a new node constructor with default values for the given scene node type. This method
85    /// automatically creates default constructor, but leaves potential variants empty (nothing will
86    /// be shown in the editor, use [`Self::with_variant`] to add potential variant of the constructor).
87    pub fn new<Inner>() -> Self
88    where
89        Node: From<Inner>,
90        Inner: ConstructorProvider<Node, Ctx>,
91    {
92        Self {
93            default: Arc::new(|| Node::from(Inner::default())),
94            variants: vec![],
95            group: "",
96            assembly_name: Inner::type_assembly_name(),
97        }
98    }
99
100    /// Sets a desired group for the constructor.
101    pub fn with_group(mut self, group: &'static str) -> Self {
102        self.group = group;
103        self
104    }
105
106    /// Adds a new constructor variant.
107    pub fn with_variant<F>(mut self, name: impl AsRef<str>, variant: F) -> Self
108    where
109        F: Fn(&mut Ctx) -> VariantResult<Node> + Send + Sync + 'static,
110    {
111        self.variants.push(Variant {
112            name: name.as_ref().to_string(),
113            constructor: Arc::new(variant),
114        });
115        self
116    }
117}
118
119/// A special container that is able to create nodes by their type UUID.
120pub struct GraphNodeConstructorContainer<Node, Ctx> {
121    map: Mutex<FxHashMap<Uuid, GraphNodeConstructor<Node, Ctx>>>,
122}
123
124impl<Node, Ctx> Default for GraphNodeConstructorContainer<Node, Ctx> {
125    fn default() -> Self {
126        Self {
127            map: Default::default(),
128        }
129    }
130}
131
132impl<Node, Ctx> GraphNodeConstructorContainer<Node, Ctx> {
133    /// Adds new type constructor for a given type and return previous constructor for the type
134    /// (if any).
135    pub fn add<Inner>(&self)
136    where
137        Inner: ConstructorProvider<Node, Ctx>,
138    {
139        let previous = self
140            .map
141            .safe_lock()
142            .insert(Inner::type_uuid(), Inner::constructor());
143        assert!(previous.is_none());
144    }
145
146    /// Adds custom type constructor.
147    pub fn add_custom(&self, type_uuid: Uuid, constructor: GraphNodeConstructor<Node, Ctx>) {
148        self.map.safe_lock().insert(type_uuid, constructor);
149    }
150
151    /// Unregisters type constructor.
152    pub fn remove(&self, type_uuid: Uuid) {
153        self.map.safe_lock().remove(&type_uuid);
154    }
155
156    /// Makes an attempt to create a node using provided type UUID. It may fail if there is no
157    /// node constructor for specified type UUID.
158    pub fn try_create(&self, type_uuid: &Uuid) -> Option<Node> {
159        self.map
160            .safe_lock()
161            .get_mut(type_uuid)
162            .map(|c| (c.default)())
163    }
164
165    /// Returns total amount of constructors.
166    pub fn len(&self) -> usize {
167        self.map.safe_lock().len()
168    }
169
170    /// Returns true if the container is empty.
171    pub fn is_empty(&self) -> bool {
172        self.len() == 0
173    }
174
175    /// Returns the inner map of the node constructors.
176    pub fn map(&self) -> MutexGuard<'_, FxHashMap<Uuid, GraphNodeConstructor<Node, Ctx>>> {
177        self.map.safe_lock()
178    }
179}