rhai/packages/
lang_core.rs1use crate::def_package;
2use crate::plugin::*;
3use crate::types::dynamic::Tag;
4use crate::{Dynamic, RhaiResult, RhaiResultOf, ERR, INT};
5use std::convert::TryFrom;
6#[cfg(feature = "no_std")]
7use std::prelude::v1::*;
8
9#[cfg(not(feature = "no_float"))]
10#[cfg(not(feature = "no_std"))]
11use crate::FLOAT;
12
13def_package! {
14 pub LanguageCorePackage(lib) {
16 lib.set_standard_lib(true);
17
18 combine_with_exported_module!(lib, "core", core_functions);
19
20 #[cfg(not(feature = "no_function"))]
21 #[cfg(not(feature = "no_index"))]
22 #[cfg(not(feature = "no_object"))]
23 combine_with_exported_module!(lib, "reflection", reflection_functions);
24 }
25}
26
27#[export_module]
28mod core_functions {
29 #[rhai_fn(name = "exit", volatile, return_raw)]
36 pub fn exit_with_value(value: Dynamic) -> RhaiResult {
37 Err(ERR::Exit(value, Position::NONE).into())
38 }
39 #[rhai_fn(volatile, return_raw)]
46 pub fn exit() -> RhaiResult {
47 Err(ERR::Exit(Dynamic::UNIT, Position::NONE).into())
48 }
49 #[rhai_fn(return_raw)]
64 pub fn take(value: &mut Dynamic) -> RhaiResult {
65 if value.is_read_only() {
66 return Err(
67 ERR::ErrorNonPureMethodCallOnConstant("take".to_string(), Position::NONE).into(),
68 );
69 }
70
71 Ok(std::mem::take(value))
72 }
73 #[rhai_fn(name = "tag", get = "tag", pure)]
85 pub fn get_tag(value: &mut Dynamic) -> INT {
86 value.tag() as INT
87 }
88 #[rhai_fn(name = "set_tag", set = "tag", return_raw)]
100 pub fn set_tag(value: &mut Dynamic, tag: INT) -> RhaiResultOf<()> {
101 const TAG_MIN: Tag = Tag::MIN;
102 const TAG_MAX: Tag = Tag::MAX;
103
104 if tag < TAG_MIN as INT {
105 return Err(ERR::ErrorArithmetic(
106 format!(
107 "{tag} is too small to fit into a tag (must be between {TAG_MIN} and {TAG_MAX})"
108 ),
109 Position::NONE,
110 )
111 .into());
112 }
113 if tag > TAG_MAX as INT {
114 return Err(ERR::ErrorArithmetic(
115 format!(
116 "{tag} is too large to fit into a tag (must be between {TAG_MIN} and {TAG_MAX})"
117 ),
118 Position::NONE,
119 )
120 .into());
121 }
122
123 value.set_tag(tag as Tag);
124 Ok(())
125 }
126
127 #[cfg(not(feature = "no_float"))]
136 #[cfg(not(feature = "no_std"))]
137 #[rhai_fn(name = "sleep", volatile)]
138 pub fn sleep_float(seconds: FLOAT) {
139 if !seconds.is_normal() || seconds.is_sign_negative() {
140 return;
141 }
142
143 #[cfg(not(feature = "f32_float"))]
144 std::thread::sleep(std::time::Duration::from_secs_f64(seconds));
145 #[cfg(feature = "f32_float")]
146 std::thread::sleep(std::time::Duration::from_secs_f32(seconds));
147 }
148 #[cfg(not(feature = "no_std"))]
157 #[rhai_fn(volatile)]
158 pub fn sleep(seconds: INT) {
159 if seconds <= 0 {
160 return;
161 }
162
163 std::thread::sleep(std::time::Duration::from_secs(
164 u64::try_from(seconds).unwrap(),
165 ));
166 }
167
168 #[cfg(not(feature = "no_object"))]
178 #[rhai_fn(return_raw)]
179 pub fn parse_json(_ctx: NativeCallContext, json: &str) -> RhaiResultOf<Dynamic> {
180 #[cfg(feature = "metadata")]
181 let out = serde_json::from_str(json).map_err(|err| err.to_string().into());
182
183 #[cfg(not(feature = "metadata"))]
184 let out = _ctx.engine().parse_json(json, true).map(Dynamic::from);
185
186 out
187 }
188}
189
190#[cfg(not(feature = "no_function"))]
191#[cfg(not(feature = "no_index"))]
192#[cfg(not(feature = "no_object"))]
193#[export_module]
194mod reflection_functions {
195 use crate::module::FuncInfo;
196 use crate::{Array, Map, ScriptFnMetadata};
197
198 #[cfg(not(feature = "no_function"))]
199 #[cfg(not(feature = "no_index"))]
200 #[cfg(not(feature = "no_object"))]
201 fn collect(
202 ctx: NativeCallContext,
203 filter: impl Fn(FnNamespace, FnAccess, &str, usize, &ScriptFnMetadata) -> bool,
204 ) -> Array {
205 let engine = ctx.engine();
206
207 engine.collect_fn_metadata_impl(
208 Some(&ctx),
209 |FuncInfo {
210 metadata,
211 #[cfg(not(feature = "no_module"))]
212 namespace,
213 script,
214 }|
215 -> Option<Dynamic> {
216 let func = script.as_ref()?;
217
218 if !filter(
219 metadata.namespace,
220 func.access,
221 func.name,
222 func.params.len(),
223 func,
224 ) {
225 return None;
226 }
227
228 let mut map = Map::new();
229
230 #[cfg(not(feature = "no_module"))]
231 if !namespace.is_empty() {
232 map.insert(
233 "namespace".into(),
234 engine.get_interned_string(namespace).into(),
235 );
236 }
237 map.insert("name".into(), engine.get_interned_string(func.name).into());
238 map.insert(
239 "access".into(),
240 engine
241 .get_interned_string(match func.access {
242 FnAccess::Public => "public",
243 FnAccess::Private => "private",
244 })
245 .into(),
246 );
247 map.insert(
248 "is_anonymous".into(),
249 func.name.starts_with(crate::engine::FN_ANONYMOUS).into(),
250 );
251 if let Some(this_type) = func.this_type {
252 map.insert("this_type".into(), this_type.into());
253 }
254 map.insert(
255 "params".into(),
256 func.params
257 .iter()
258 .map(|&p| engine.get_interned_string(p).into())
259 .collect::<Array>()
260 .into(),
261 );
262 #[cfg(feature = "metadata")]
263 if !func.comments.is_empty() {
264 map.insert(
265 "comments".into(),
266 func.comments
267 .iter()
268 .map(|&s| engine.get_interned_string(s).into())
269 .collect::<Array>()
270 .into(),
271 );
272 }
273
274 Some(Dynamic::from_map(map))
275 },
276 false,
277 )
278 }
279
280 #[rhai_fn(name = "get_fn_metadata_list", volatile)]
282 pub fn get_fn_metadata_list(ctx: NativeCallContext) -> Array {
283 collect(ctx, |_, _, _, _, _| true)
284 }
285 #[rhai_fn(name = "get_fn_metadata_list", volatile)]
288 pub fn get_fn_metadata(ctx: NativeCallContext, name: &str) -> Array {
289 collect(ctx, |_, _, n, _, _| n == name)
290 }
291 #[rhai_fn(name = "get_fn_metadata_list", volatile)]
294 pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> Array {
295 if params < 0 {
296 return Array::new();
297 }
298 let Ok(params) = usize::try_from(params) else {
299 return Array::new();
300 };
301
302 collect(ctx, |_, _, n, p, _| p == params && n == name)
303 }
304}