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}