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}