Skip to main content

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 ScriptFuncDef {
44    /// Clone this [`ScriptFuncDef`] but with only signature-related info.
45    ///
46    /// The body of the function is removed, as well as comments (if any).
47    #[allow(dead_code)]
48    pub(crate) fn clone_function_signatures(&self) -> Self {
49        Self {
50            name: self.name.clone(),
51            access: self.access,
52            body: StmtBlock::NONE,
53            #[cfg(not(feature = "no_object"))]
54            this_type: self.this_type.clone(),
55            params: self.params.clone(),
56            #[cfg(feature = "metadata")]
57            comments: <_>::default(),
58        }
59    }
60}
61
62impl fmt::Display for ScriptFuncDef {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        #[cfg(not(feature = "no_object"))]
65        let this_type = self
66            .this_type
67            .as_ref()
68            .map_or(String::new(), |s| format!("{s:?}."));
69
70        #[cfg(feature = "no_object")]
71        let this_type = "";
72
73        write!(
74            f,
75            "{}{}{}({})",
76            match self.access {
77                FnAccess::Public => "",
78                FnAccess::Private => "private ",
79            },
80            this_type,
81            self.name,
82            self.params
83                .iter()
84                .map(ImmutableString::as_str)
85                .collect::<FnArgsVec<_>>()
86                .join(", ")
87        )
88    }
89}
90
91/// A type containing the metadata of a script-defined function.
92///
93/// Not available under `no_function`.
94///
95/// Created by [`AST::iter_functions`][super::AST::iter_functions].
96#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)]
97#[cfg_attr(
98    feature = "serde",
99    derive(serde::Serialize, serde::Deserialize),
100    serde(rename_all = "camelCase")
101)]
102#[non_exhaustive]
103pub struct ScriptFnMetadata<'a> {
104    /// Function name.
105    pub name: &'a str,
106    /// Function parameters (if any).
107    #[cfg_attr(
108        feature = "serde",
109        serde(default, skip_serializing_if = "Vec::is_empty")
110    )]
111    pub params: Vec<&'a str>,
112    /// Function access mode.
113    pub access: FnAccess,
114    /// Type of `this` pointer, if any.
115    /// Not available under `no_object`.
116    #[cfg(not(feature = "no_object"))]
117    #[cfg_attr(
118        feature = "serde",
119        serde(default, skip_serializing_if = "Option::is_none")
120    )]
121    pub this_type: Option<&'a str>,
122    /// _(metadata)_ Function doc-comments (if any).
123    /// Exported under the `metadata` feature only.
124    ///
125    /// Doc-comments are comment lines beginning with `///` or comment blocks beginning with `/**`,
126    /// placed immediately before a function definition.
127    ///
128    /// Block doc-comments are kept in a single string slice with line-breaks within.
129    ///
130    /// Line doc-comments are merged, with line-breaks, into a single string slice without a termination line-break.
131    ///
132    /// Leading white-spaces are stripped, and each string slice always starts with the
133    /// corresponding doc-comment leader: `///` or `/**`.
134    ///
135    /// Each line in non-block doc-comments starts with `///`.
136    #[cfg(feature = "metadata")]
137    #[serde(default, skip_serializing_if = "Vec::is_empty")]
138    pub comments: Vec<&'a str>,
139}
140
141impl fmt::Display for ScriptFnMetadata<'_> {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        #[cfg(not(feature = "no_object"))]
144        let this_type = self
145            .this_type
146            .as_ref()
147            .map_or(String::new(), |s| format!("{s:?}."));
148
149        #[cfg(feature = "no_object")]
150        let this_type = "";
151
152        write!(
153            f,
154            "{}{}{}({})",
155            match self.access {
156                FnAccess::Public => "",
157                FnAccess::Private => "private ",
158            },
159            this_type,
160            self.name,
161            self.params
162                .iter()
163                .copied()
164                .collect::<FnArgsVec<_>>()
165                .join(", ")
166        )
167    }
168}
169
170impl<'a> From<&'a ScriptFuncDef> for ScriptFnMetadata<'a> {
171    #[inline]
172    fn from(value: &'a ScriptFuncDef) -> Self {
173        Self {
174            name: &value.name,
175            params: value.params.iter().map(ImmutableString::as_str).collect(),
176            access: value.access,
177            #[cfg(not(feature = "no_object"))]
178            this_type: value.this_type.as_deref(),
179            #[cfg(feature = "metadata")]
180            comments: value.comments.iter().map(<_>::as_ref).collect(),
181        }
182    }
183}