spo_rhai/ast/
script_fn.rs

1//! Module defining script-defined functions.
2#![cfg(not(feature = "no_function"))]
3
4use super::{FnAccess, StmtBlock};
5use crate::{FnArgsVec, ImmutableString};
6#[cfg(feature = "no_std")]
7use std::prelude::v1::*;
8use std::{fmt, hash::Hash};
9
10/// _(internals)_ A type containing information on a script-defined function.
11/// Exported under the `internals` feature only.
12#[derive(Debug, Clone)]
13pub struct ScriptFuncDef {
14    /// Function body.
15    pub body: StmtBlock,
16    /// Function name.
17    pub name: ImmutableString,
18    /// Function access mode.
19    pub access: FnAccess,
20    #[cfg(not(feature = "no_object"))]
21    /// Type of `this` pointer, if any.
22    /// Not available under `no_object`.
23    pub this_type: Option<ImmutableString>,
24    /// Names of function parameters.
25    pub params: FnArgsVec<ImmutableString>,
26    /// _(metadata)_ Function doc-comments (if any). Exported under the `metadata` feature only.
27    ///
28    /// Doc-comments are comment lines beginning with `///` or comment blocks beginning with `/**`,
29    /// placed immediately before a function definition.
30    ///
31    /// Block doc-comments are kept in a single string with line-breaks within.
32    ///
33    /// Line doc-comments are merged, with line-breaks, into a single string without a termination line-break.
34    ///
35    /// Leading white-spaces are stripped, and each string always starts with the corresponding
36    /// doc-comment leader: `///` or `/**`.
37    ///
38    /// Each line in non-block doc-comments starts with `///`.
39    #[cfg(feature = "metadata")]
40    pub comments: crate::StaticVec<crate::SmartString>,
41}
42
43impl fmt::Display for ScriptFuncDef {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        #[cfg(not(feature = "no_object"))]
46        let this_type = self
47            .this_type
48            .as_ref()
49            .map_or(String::new(), |s| format!("{s:?}."));
50
51        #[cfg(feature = "no_object")]
52        let this_type = "";
53
54        write!(
55            f,
56            "{}{}{}({})",
57            match self.access {
58                FnAccess::Public => "",
59                FnAccess::Private => "private ",
60            },
61            this_type,
62            self.name,
63            self.params
64                .iter()
65                .map(ImmutableString::as_str)
66                .collect::<FnArgsVec<_>>()
67                .join(", ")
68        )
69    }
70}
71
72/// A type containing the metadata of a script-defined function.
73///
74/// Not available under `no_function`.
75///
76/// Created by [`AST::iter_functions`][super::AST::iter_functions].
77#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)]
78#[cfg_attr(
79    feature = "serde",
80    derive(serde::Serialize, serde::Deserialize),
81    serde(rename_all = "camelCase")
82)]
83#[non_exhaustive]
84pub struct ScriptFnMetadata<'a> {
85    /// Function name.
86    pub name: &'a str,
87    /// Function parameters (if any).
88    #[cfg_attr(
89        feature = "serde",
90        serde(default, skip_serializing_if = "Vec::is_empty")
91    )]
92    pub params: Vec<&'a str>,
93    /// Function access mode.
94    pub access: FnAccess,
95    /// Type of `this` pointer, if any.
96    /// Not available under `no_object`.
97    #[cfg(not(feature = "no_object"))]
98    #[cfg_attr(
99        feature = "serde",
100        serde(default, skip_serializing_if = "Option::is_none")
101    )]
102    pub this_type: Option<&'a str>,
103    /// _(metadata)_ Function doc-comments (if any).
104    /// Exported under the `metadata` feature only.
105    ///
106    /// Doc-comments are comment lines beginning with `///` or comment blocks beginning with `/**`,
107    /// placed immediately before a function definition.
108    ///
109    /// Block doc-comments are kept in a single string slice with line-breaks within.
110    ///
111    /// Line doc-comments are merged, with line-breaks, into a single string slice without a termination line-break.
112    ///
113    /// Leading white-spaces are stripped, and each string slice always starts with the
114    /// corresponding doc-comment leader: `///` or `/**`.
115    ///
116    /// Each line in non-block doc-comments starts with `///`.
117    #[cfg(feature = "metadata")]
118    #[serde(default, skip_serializing_if = "Vec::is_empty")]
119    pub comments: Vec<&'a str>,
120}
121
122impl fmt::Display for ScriptFnMetadata<'_> {
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        #[cfg(not(feature = "no_object"))]
125        let this_type = self
126            .this_type
127            .as_ref()
128            .map_or(String::new(), |s| format!("{s:?}."));
129
130        #[cfg(feature = "no_object")]
131        let this_type = "";
132
133        write!(
134            f,
135            "{}{}{}({})",
136            match self.access {
137                FnAccess::Public => "",
138                FnAccess::Private => "private ",
139            },
140            this_type,
141            self.name,
142            self.params
143                .iter()
144                .copied()
145                .collect::<FnArgsVec<_>>()
146                .join(", ")
147        )
148    }
149}
150
151impl<'a> From<&'a ScriptFuncDef> for ScriptFnMetadata<'a> {
152    #[inline]
153    fn from(value: &'a ScriptFuncDef) -> Self {
154        Self {
155            name: &value.name,
156            params: value.params.iter().map(ImmutableString::as_str).collect(),
157            access: value.access,
158            #[cfg(not(feature = "no_object"))]
159            this_type: value.this_type.as_deref(),
160            #[cfg(feature = "metadata")]
161            comments: value.comments.iter().map(<_>::as_ref).collect(),
162        }
163    }
164}