fyrox_impl/script/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
21//! A special container that is able to create nodes by their type UUID.
22
23use crate::{
24 core::{
25 parking_lot::{Mutex, MutexGuard},
26 uuid::Uuid,
27 TypeUuidProvider,
28 },
29 script::{Script, ScriptTrait},
30};
31use std::collections::BTreeMap;
32
33/// Script constructor contains all required data and methods to create script instances
34/// by their UUIDs. Its is primarily used for serialization needs.
35pub struct ScriptConstructor {
36 /// A simple type alias for boxed node constructor.
37 pub constructor: Box<dyn FnMut() -> Script + Send>,
38
39 /// Script name.
40 pub name: String,
41
42 /// Script source path.
43 pub source_path: &'static str,
44
45 /// A name of the assembly this script constructor belongs to.
46 pub assembly_name: &'static str,
47}
48
49/// A special container that is able to create nodes by their type UUID.
50#[derive(Default)]
51pub struct ScriptConstructorContainer {
52 // BTreeMap allows to have sorted list of constructors.
53 map: Mutex<BTreeMap<Uuid, ScriptConstructor>>,
54}
55
56impl ScriptConstructorContainer {
57 /// Creates default node constructor container with constructors for built-in engine nodes.
58 pub fn new() -> Self {
59 ScriptConstructorContainer::default()
60 }
61
62 /// Adds new type constructor for a given type.
63 ///
64 /// # Panic
65 ///
66 /// The method will panic if there is already a constructor for given type uuid.
67 pub fn add<T>(&self, name: &str) -> &Self
68 where
69 T: TypeUuidProvider + ScriptTrait + Default,
70 {
71 let old = self.map.lock().insert(
72 T::type_uuid(),
73 ScriptConstructor {
74 constructor: Box::new(|| Script::new(T::default())),
75 name: name.to_owned(),
76 source_path: T::source_path(),
77 assembly_name: T::type_assembly_name(),
78 },
79 );
80
81 assert!(old.is_none());
82
83 self
84 }
85
86 /// Adds custom type constructor.
87 pub fn add_custom(
88 &self,
89 type_uuid: Uuid,
90 constructor: ScriptConstructor,
91 ) -> Result<(), String> {
92 let mut map = self.map.lock();
93 if let Some(old) = map.get(&type_uuid) {
94 return Err(format!(
95 "cannot add {} ({}) because its uuid is already used by {} ({})",
96 constructor.name, constructor.assembly_name, old.name, old.assembly_name
97 ));
98 }
99 map.insert(type_uuid, constructor);
100 Ok(())
101 }
102
103 /// Unregisters type constructor.
104 pub fn remove(&self, type_uuid: Uuid) {
105 self.map.lock().remove(&type_uuid);
106 }
107
108 /// Makes an attempt to create a script using provided type UUID. It may fail if there is no
109 /// script constructor for specified type UUID.
110 pub fn try_create(&self, type_uuid: &Uuid) -> Option<Script> {
111 self.map
112 .lock()
113 .get_mut(type_uuid)
114 .map(|c| (c.constructor)())
115 }
116
117 /// Returns inner map of script constructors.
118 pub fn map(&self) -> MutexGuard<BTreeMap<Uuid, ScriptConstructor>> {
119 self.map.lock()
120 }
121}