Skip to main content

fre_rs/
function.rs

1use super::*;
2
3
4/// The function is used to initialize the extension.
5///
6/// Returns [`None`] if no Extension Data is set.
7/// 
8pub type Initializer = fn () -> Option<Box<dyn Any>>;
9
10/// The function receives ownership of the Extension Data,
11/// allowing it to be saved or disposed.
12/// 
13/// The runtime does **NOT** guarantee that this function will be called before process termination.
14/// 
15pub type Finalizer = fn (ext_data: Option<Box<dyn Any>>);
16
17/// The function is used to initialize a [`Context`].
18///
19/// The first return value sets the Context Data.
20/// The second return value sets the methods associated with the [`Context`].
21/// 
22pub type ContextInitializer = fn (ctx: &CurrentContext) -> (Option<Box<dyn Any>>, FunctionSet);
23
24/// The function is called before the Context Data is disposed,
25/// allowing final access and saving data to the Extension Data.
26///
27pub type ContextFinalizer = fn (ctx: &CurrentContext);
28
29/// The function can be associated with a [`Context`] and treated as its method.
30///
31/// Although the signature returns [`Object<'a>`], implementations may return
32/// any type implementing [`Into<Object> + 'a`], primarily to support
33/// types like [`Option<AsObject<'a>>`].
34/// 
35pub type Function <'a> = fn (ctx: &CurrentContext<'a>, func_data: Option<&mut dyn Any>, args: &[Object<'a>]) -> Object<'a>;
36
37
38/// **In typical usage of this crate, instances of this type should not be constructed directly.**
39/// 
40/// The [`function!`] macro should be used to construct this type, as it provides a safer abstraction.
41/// 
42#[derive(Debug)]
43pub struct FunctionImplementation {
44    raw_name: UCStr,
45    raw_func: FREFunction,
46}
47impl FunctionImplementation {
48    pub fn raw_name(&self) -> &UCStr {&self.raw_name}
49    pub fn raw_func(&self) -> FREFunction {self.raw_func}
50    pub const fn new (raw_name: UCStr, raw_func: FREFunction) -> Self {
51        Self { raw_name, raw_func }
52    }
53}
54
55
56/// A collection of functions associated with a specific context type.
57///
58/// This type is used to construct a set of functions for a [`Context`].
59/// Once registered, these functions are referred to as *methods* within this crate,
60/// and can be invoked from AS3 via `ExtensionContext.call`.
61/// 
62#[derive(Debug)]
63pub struct FunctionSet {
64    list: Vec<FRENamedFunction>,
65    map: HashMap<UCStr, usize>,
66}
67impl FunctionSet {
68    pub fn new () -> Self {
69        Self {
70            list: Vec::new(),
71            map: HashMap::new(),
72        }
73    }
74    pub fn with_capacity (capacity: usize) -> Self{
75        Self {
76            list: Vec::with_capacity(capacity),
77            map: HashMap::with_capacity(capacity),
78        }
79    }
80
81    /// Adds a function that can be registered as a method.
82    ///
83    /// - `name`: The method name. If [`None`], the raw name of `func_impl` is used.
84    /// - `func_data`: Data associated with this method. It will be dropped after [`ContextFinalizer`] returns.
85    /// - `func_impl`: The method implementation created by the [`crate::function!`] macro.
86    /// 
87    /// # Panics
88    ///
89    /// Panics if a function with the same `name` has already been added.
90    ///
91    /// Callers must ensure that each `name` is unique within this set. 
92    /// 
93    pub fn add (
94        &mut self,
95        name: Option<UCStr>,
96        func_data: Option<Box<dyn Any>>,
97        func_impl: &FunctionImplementation,
98    ) {
99        let name = name.unwrap_or(func_impl.raw_name.clone());
100        let index = self.list.len();
101        self.list.push(FRENamedFunction {
102            name: name.as_ptr(),
103            functionData: if let Some(func_data) = func_data {crate::data::into_raw(func_data).as_ptr()} else {FREData::default()},
104            function: func_impl.raw_func,
105        });
106        let r = self.map.insert(name, index);
107        assert!(r.is_none(), "Method name conflict.");
108    }
109}
110impl Drop for FunctionSet {
111    fn drop(&mut self) {
112        self.list.iter()
113            .map(|i| i.functionData)
114            .for_each(|d| {
115                if let Some(d) = NonNullFREData::new(d) {
116                    unsafe {crate::data::drop_from(d)};
117                }
118            });
119    }
120}
121
122
123#[derive(Debug)]
124pub(super) struct MethodSet {
125    registry: Box<[FRENamedFunction]>,
126    dictionary: HashMap<UCStr, usize>,
127}
128impl MethodSet {
129    /// ## Borrow
130    pub(super) fn get(&self, name: &str) -> Option<(FREFunction, FREData)> {
131        self.dictionary.get(name)
132            .map(|index| {
133                let i = &(self.registry[*index]);
134                (i.function, i.functionData)
135            })
136    }
137}
138impl Drop for MethodSet {
139    fn drop(&mut self) {
140        self.registry.iter()
141            .map(|i| i.functionData)
142            .for_each(|d| {
143                if let Some(d) = NonNullFREData::new(d) {
144                    unsafe {crate::data::drop_from(d)};
145                }
146            });
147    }
148}
149impl From<FunctionSet> for MethodSet {
150    fn from(mut value: FunctionSet) -> Self {
151        let registry = std::mem::take(&mut value.list).into_boxed_slice();
152        let dictionary = std::mem::take(&mut value.map);
153        Self { registry, dictionary }
154    }
155}
156impl AsRef<[FRENamedFunction]> for MethodSet {
157    fn as_ref(&self) -> &[FRENamedFunction] {self.registry.as_ref()}
158}
159
160
161/// Sends a message to the debugger output.
162/// 
163/// Delivery is not guaranteed; the `message` may not be presented.
164/// 
165/// # Panics
166///
167/// Panics if no [`CurrentContext`] exists. The call must occur within an
168/// active native function call from the Flash runtime main thread.
169/// 
170/// # Examples
171/// 
172/// ```
173/// use fre_rs::prelude::*;
174/// fn func <'a> (_: CurrentContext<'a>, args: &[Object<'a>]) {
175///     trace("Hello, Flash runtime!");
176///     trace(args);
177///     trace(args[0]);
178/// }
179/// ```
180/// 
181pub fn trace(message: impl ToUcstrLossy) {crate::context::stack::current_context().trace(message);}
182