rhai/types/scope.rs
1//! Module that defines the [`Scope`] type representing a function call-stack scope.
2
3use super::dynamic::{AccessMode, Variant};
4use crate::{Dynamic, Identifier, ImmutableString, StaticVec, ThinVec};
5#[cfg(feature = "no_std")]
6use std::prelude::v1::*;
7use std::{
8 fmt, iter,
9 iter::{Extend, FromIterator},
10 marker::PhantomData,
11};
12
13/// Minimum number of entries in the [`Scope`] to avoid reallocations.
14pub const MIN_SCOPE_ENTRIES: usize = 8;
15
16/// Type containing information about the current scope. Useful for keeping state between
17/// [`Engine`][crate::Engine] evaluation runs.
18///
19/// # Lifetime
20///
21/// Currently the lifetime parameter is not used, but it is not guaranteed to remain unused for
22/// future versions. Until then, `'static` can be used.
23///
24/// # Thread Safety
25///
26/// Currently, [`Scope`] is neither [`Send`] nor [`Sync`]. Turn on the `sync` feature to make it
27/// [`Send`] `+` [`Sync`].
28///
29/// # Example
30///
31/// ```
32/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
33/// use rhai::{Engine, Scope};
34///
35/// let engine = Engine::new();
36/// let mut my_scope = Scope::new();
37///
38/// my_scope.push("z", 40_i64);
39///
40/// engine.run_with_scope(&mut my_scope, "let x = z + 1; z = 0;")?;
41///
42/// let result: i64 = engine.eval_with_scope(&mut my_scope, "x + 1")?;
43///
44/// assert_eq!(result, 42);
45/// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 41);
46/// assert_eq!(my_scope.get_value::<i64>("z").expect("z should exist"), 0);
47/// # Ok(())
48/// # }
49/// ```
50///
51/// When searching for entries, newly-added entries are found before similarly-named but older
52/// entries, allowing for automatic _shadowing_.
53//
54// # Implementation Notes
55//
56// [`Scope`] is implemented as three arrays. Two (`values` and `names`) are of exactly the same
57// length. That's because in the vast majority of cases the name is NOT used to look up a variable.
58// Variable lookup is usually via direct indexing, by-passing the name altogether.
59//
60// [`Dynamic`] is reasonably small so packing it tightly improves cache performance.
61#[derive(Debug, Hash, Default)]
62pub struct Scope<'a> {
63 /// Current value of the entry.
64 values: ThinVec<Dynamic>,
65 /// Name of the entry.
66 names: ThinVec<ImmutableString>,
67 /// Aliases of the entry.
68 ///
69 /// This `Vec` is not filled until needed because aliases are used rarely
70 /// (only for `export` statements).
71 aliases: ThinVec<StaticVec<ImmutableString>>,
72 /// Phantom to keep the lifetime parameter in order not to break existing code.
73 dummy: PhantomData<&'a ()>,
74}
75
76impl fmt::Display for Scope<'_> {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 for (i, (name, constant, value)) in self.iter_inner().enumerate() {
79 writeln!(
80 f,
81 "[{}] {}{} = {:?}",
82 i + 1,
83 if constant { "const " } else { "" },
84 name,
85 value,
86 )?;
87 }
88
89 Ok(())
90 }
91}
92
93impl Clone for Scope<'_> {
94 #[inline]
95 fn clone(&self) -> Self {
96 Self {
97 values: self
98 .values
99 .iter()
100 .map(|v| {
101 // Also copy the value's access mode (otherwise will turn to read-write)
102 let mut v2 = v.clone();
103 v2.set_access_mode(v.access_mode());
104 v2
105 })
106 .collect(),
107 names: self.names.clone(),
108 aliases: self.aliases.clone(),
109 dummy: self.dummy,
110 }
111 }
112}
113
114impl IntoIterator for Scope<'_> {
115 type Item = (String, Dynamic, Vec<ImmutableString>);
116 type IntoIter = Box<dyn Iterator<Item = Self::Item>>;
117
118 fn into_iter(self) -> Self::IntoIter {
119 Box::new(
120 self.values
121 .into_iter()
122 .zip(
123 self.names.into_iter().zip(
124 self.aliases
125 .into_iter()
126 .map(|a| a.to_vec())
127 .chain(iter::repeat(Vec::new())),
128 ),
129 )
130 .map(|(value, (name, alias))| (name.to_string(), value, alias)),
131 )
132 }
133}
134
135impl<'a> IntoIterator for &'a Scope<'_> {
136 type Item = (&'a str, &'a Dynamic, &'a [ImmutableString]);
137 type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
138
139 fn into_iter(self) -> Self::IntoIter {
140 Box::new(
141 self.values
142 .iter()
143 .zip(
144 self.names.iter().zip(
145 self.aliases
146 .iter()
147 .map(<_>::as_ref)
148 .chain(iter::repeat(&[][..])),
149 ),
150 )
151 .map(|(value, (name, alias))| (name.as_str(), value, alias)),
152 )
153 }
154}
155
156impl Scope<'_> {
157 /// Create a new [`Scope`].
158 ///
159 /// # Example
160 ///
161 /// ```
162 /// use rhai::Scope;
163 ///
164 /// let mut my_scope = Scope::new();
165 ///
166 /// my_scope.push("x", 42_i64);
167 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
168 /// ```
169 #[inline(always)]
170 #[must_use]
171 pub fn new() -> Self {
172 Self {
173 values: ThinVec::new(),
174 names: ThinVec::new(),
175 aliases: ThinVec::new(),
176 dummy: PhantomData,
177 }
178 }
179 /// Create a new [`Scope`] with a particular capacity.
180 ///
181 /// # Example
182 ///
183 /// ```
184 /// use rhai::Scope;
185 ///
186 /// let mut my_scope = Scope::with_capacity(10);
187 ///
188 /// my_scope.push("x", 42_i64);
189 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
190 /// ```
191 #[inline(always)]
192 #[must_use]
193 pub fn with_capacity(capacity: usize) -> Self {
194 Self {
195 values: ThinVec::with_capacity(capacity),
196 names: ThinVec::with_capacity(capacity),
197 aliases: ThinVec::new(),
198 dummy: PhantomData,
199 }
200 }
201 /// Empty the [`Scope`].
202 ///
203 /// # Example
204 ///
205 /// ```
206 /// use rhai::Scope;
207 ///
208 /// let mut my_scope = Scope::new();
209 ///
210 /// my_scope.push("x", 42_i64);
211 /// assert!(my_scope.contains("x"));
212 /// assert_eq!(my_scope.len(), 1);
213 /// assert!(!my_scope.is_empty());
214 ///
215 /// my_scope.clear();
216 /// assert!(!my_scope.contains("x"));
217 /// assert_eq!(my_scope.len(), 0);
218 /// assert!(my_scope.is_empty());
219 /// ```
220 #[inline(always)]
221 pub fn clear(&mut self) -> &mut Self {
222 self.names.clear();
223 self.values.clear();
224 self.aliases.clear();
225 self
226 }
227 /// Get the number of entries inside the [`Scope`].
228 ///
229 /// # Example
230 ///
231 /// ```
232 /// use rhai::Scope;
233 ///
234 /// let mut my_scope = Scope::new();
235 /// assert_eq!(my_scope.len(), 0);
236 ///
237 /// my_scope.push("x", 42_i64);
238 /// assert_eq!(my_scope.len(), 1);
239 /// ```
240 #[inline(always)]
241 #[must_use]
242 pub fn len(&self) -> usize {
243 self.values.len()
244 }
245 /// Returns `true` if this [`Scope`] contains no variables.
246 ///
247 /// # Example
248 ///
249 /// ```
250 /// use rhai::Scope;
251 ///
252 /// let mut my_scope = Scope::new();
253 /// assert!(my_scope.is_empty());
254 ///
255 /// my_scope.push("x", 42_i64);
256 /// assert!(!my_scope.is_empty());
257 /// ```
258 #[inline(always)]
259 #[must_use]
260 pub fn is_empty(&self) -> bool {
261 self.values.is_empty()
262 }
263 /// Add (push) a new entry to the [`Scope`].
264 ///
265 /// # Example
266 ///
267 /// ```
268 /// use rhai::Scope;
269 ///
270 /// let mut my_scope = Scope::new();
271 ///
272 /// my_scope.push("x", 42_i64);
273 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
274 /// ```
275 #[inline(always)]
276 pub fn push(&mut self, name: impl Into<Identifier>, value: impl Variant + Clone) -> &mut Self {
277 self.push_entry(
278 name.into().into(),
279 AccessMode::ReadWrite,
280 Dynamic::from(value),
281 )
282 }
283 /// Add (push) a new [`Dynamic`] entry to the [`Scope`].
284 ///
285 /// # Example
286 ///
287 /// ```
288 /// use rhai::{Dynamic, Scope};
289 ///
290 /// let mut my_scope = Scope::new();
291 ///
292 /// my_scope.push_dynamic("x", Dynamic::from(42_i64));
293 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
294 /// ```
295 #[inline(always)]
296 pub fn push_dynamic(&mut self, name: impl Into<Identifier>, value: Dynamic) -> &mut Self {
297 self.push_entry(name.into().into(), value.access_mode(), value)
298 }
299 /// Add (push) a new constant to the [`Scope`].
300 ///
301 /// Constants are immutable and cannot be assigned to. Their values never change.
302 /// Constants propagation is a technique used to optimize an [`AST`][crate::AST].
303 ///
304 /// # Example
305 ///
306 /// ```
307 /// use rhai::Scope;
308 ///
309 /// let mut my_scope = Scope::new();
310 ///
311 /// my_scope.push_constant("x", 42_i64);
312 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
313 /// ```
314 #[inline(always)]
315 pub fn push_constant(
316 &mut self,
317 name: impl Into<Identifier>,
318 value: impl Variant + Clone,
319 ) -> &mut Self {
320 self.push_entry(
321 name.into().into(),
322 AccessMode::ReadOnly,
323 Dynamic::from(value),
324 )
325 }
326 /// Add (push) a new constant with a [`Dynamic`] value to the Scope.
327 ///
328 /// Constants are immutable and cannot be assigned to. Their values never change.
329 /// Constants propagation is a technique used to optimize an [`AST`][crate::AST].
330 ///
331 /// # Example
332 ///
333 /// ```
334 /// use rhai::{Dynamic, Scope};
335 ///
336 /// let mut my_scope = Scope::new();
337 ///
338 /// my_scope.push_constant_dynamic("x", Dynamic::from(42_i64));
339 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
340 /// ```
341 #[inline(always)]
342 pub fn push_constant_dynamic(
343 &mut self,
344 name: impl Into<Identifier>,
345 value: Dynamic,
346 ) -> &mut Self {
347 self.push_entry(name.into().into(), AccessMode::ReadOnly, value)
348 }
349 /// Add (push) a new entry with a [`Dynamic`] value to the [`Scope`].
350 #[inline]
351 pub(crate) fn push_entry(
352 &mut self,
353 name: ImmutableString,
354 access: AccessMode,
355 mut value: Dynamic,
356 ) -> &mut Self {
357 if self.is_empty() {
358 self.names.reserve(MIN_SCOPE_ENTRIES);
359 self.values.reserve(MIN_SCOPE_ENTRIES);
360 }
361 self.names.push(name);
362 value.set_access_mode(access);
363 self.values.push(value);
364 self
365 }
366 /// Remove the last entry from the [`Scope`].
367 ///
368 /// # Panics
369 ///
370 /// Panics is the [`Scope`] is empty.
371 ///
372 /// # Example
373 ///
374 /// ```
375 /// use rhai::Scope;
376 ///
377 /// let mut my_scope = Scope::new();
378 ///
379 /// my_scope.push("x", 42_i64);
380 /// my_scope.push("y", 123_i64);
381 /// assert!(my_scope.contains("x"));
382 /// assert!(my_scope.contains("y"));
383 /// assert_eq!(my_scope.len(), 2);
384 ///
385 /// my_scope.pop();
386 /// assert!(my_scope.contains("x"));
387 /// assert!(!my_scope.contains("y"));
388 /// assert_eq!(my_scope.len(), 1);
389 ///
390 /// my_scope.pop();
391 /// assert!(!my_scope.contains("x"));
392 /// assert!(!my_scope.contains("y"));
393 /// assert_eq!(my_scope.len(), 0);
394 /// assert!(my_scope.is_empty());
395 /// ```
396 #[inline(always)]
397 pub fn pop(&mut self) -> &mut Self {
398 self.names
399 .pop()
400 .unwrap_or_else(|| panic!("`Scope` is empty"));
401 self.values.truncate(self.names.len());
402 self.aliases.truncate(self.names.len());
403 self
404 }
405 /// Remove the last entry from the [`Scope`] and return it.
406 #[inline(always)]
407 #[allow(dead_code)]
408 pub(crate) fn pop_entry(&mut self) -> Option<(ImmutableString, Dynamic, Vec<ImmutableString>)> {
409 self.values.pop().map(|value| {
410 (
411 self.names.pop().unwrap(),
412 value,
413 if self.aliases.len() > self.values.len() {
414 self.aliases.pop().unwrap().to_vec()
415 } else {
416 Vec::new()
417 },
418 )
419 })
420 }
421 /// Truncate (rewind) the [`Scope`] to a previous size.
422 ///
423 /// # Example
424 ///
425 /// ```
426 /// use rhai::Scope;
427 ///
428 /// let mut my_scope = Scope::new();
429 ///
430 /// my_scope.push("x", 42_i64);
431 /// my_scope.push("y", 123_i64);
432 /// assert!(my_scope.contains("x"));
433 /// assert!(my_scope.contains("y"));
434 /// assert_eq!(my_scope.len(), 2);
435 ///
436 /// my_scope.rewind(1);
437 /// assert!(my_scope.contains("x"));
438 /// assert!(!my_scope.contains("y"));
439 /// assert_eq!(my_scope.len(), 1);
440 ///
441 /// my_scope.rewind(0);
442 /// assert!(!my_scope.contains("x"));
443 /// assert!(!my_scope.contains("y"));
444 /// assert_eq!(my_scope.len(), 0);
445 /// assert!(my_scope.is_empty());
446 /// ```
447 #[inline(always)]
448 pub fn rewind(&mut self, size: usize) -> &mut Self {
449 self.names.truncate(size);
450 self.values.truncate(size);
451 self.aliases.truncate(size);
452 self
453 }
454 /// Does the [`Scope`] contain the entry?
455 ///
456 /// # Example
457 ///
458 /// ```
459 /// use rhai::Scope;
460 ///
461 /// let mut my_scope = Scope::new();
462 ///
463 /// my_scope.push("x", 42_i64);
464 /// assert!(my_scope.contains("x"));
465 /// assert!(!my_scope.contains("y"));
466 /// ```
467 #[inline]
468 #[must_use]
469 pub fn contains(&self, name: &str) -> bool {
470 self.names.iter().any(|key| name == key)
471 }
472 /// Find an entry in the [`Scope`], starting from the last.
473 #[inline]
474 #[must_use]
475 pub(crate) fn search(&self, name: &str) -> Option<usize> {
476 self.names
477 .iter()
478 .rev() // Always search a Scope in reverse order
479 .position(|key| name == key)
480 .map(|i| self.len() - 1 - i)
481 }
482 /// Get the value of an entry in the [`Scope`], starting from the last.
483 ///
484 /// # Example
485 ///
486 /// ```
487 /// use rhai::Scope;
488 ///
489 /// let mut my_scope = Scope::new();
490 ///
491 /// my_scope.push("x", 42_i64);
492 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
493 /// ```
494 #[inline]
495 #[must_use]
496 pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
497 self.names
498 .iter()
499 .rev()
500 .position(|key| name == key)
501 .and_then(|i| self.values[self.len() - 1 - i].flatten_clone().try_cast())
502 }
503 /// Get a reference the value of an entry in the [`Scope`], starting from the last.
504 ///
505 /// # Panics
506 ///
507 /// Panics if the value is _shared_.
508 ///
509 /// # Example
510 ///
511 /// ```
512 /// use rhai::Scope;
513 ///
514 /// let mut my_scope = Scope::new();
515 ///
516 /// my_scope.push("x", 42_i64);
517 ///
518 /// let ptr = my_scope.get_value_ref::<i64>("x").expect("x should exist");
519 ///
520 /// assert_eq!(*ptr, 42);
521 /// ```
522 #[inline]
523 #[must_use]
524 pub fn get_value_ref<T: Variant + Clone>(&self, name: &str) -> Option<&T> {
525 self.names
526 .iter()
527 .rev()
528 .position(|key| name == key)
529 .and_then(|i| {
530 let v = &self.values[self.len() - 1 - i];
531 #[cfg(not(feature = "no_closure"))]
532 assert!(!v.is_shared());
533 v.downcast_ref()
534 })
535 }
536 /// Get a mutable reference the value of an entry in the [`Scope`], starting from the last.
537 ///
538 /// # Panics
539 ///
540 /// Panics if the value is _shared_.
541 ///
542 /// # Example
543 ///
544 /// ```
545 /// use rhai::Scope;
546 ///
547 /// let mut my_scope = Scope::new();
548 ///
549 /// my_scope.push("x", 42_i64);
550 ///
551 /// let ptr = my_scope.get_value_mut::<i64>("x").expect("x should exist");
552 ///
553 /// *ptr = 0;
554 ///
555 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 0);
556 /// ```
557 #[inline]
558 #[must_use]
559 pub fn get_value_mut<T: Variant + Clone>(&mut self, name: &str) -> Option<&mut T> {
560 let len = self.len();
561
562 self.names
563 .iter_mut()
564 .rev()
565 .position(|key| name == key)
566 .and_then(move |i| {
567 let v = &mut self.values[len - 1 - i];
568 #[cfg(not(feature = "no_closure"))]
569 assert!(!v.is_shared());
570 v.downcast_mut()
571 })
572 }
573 /// Check if the named entry in the [`Scope`] is constant.
574 ///
575 /// Search starts backwards from the last, stopping at the first entry matching the specified name.
576 ///
577 /// Returns [`None`] if no entry matching the specified name is found.
578 ///
579 /// # Example
580 ///
581 /// ```
582 /// use rhai::Scope;
583 ///
584 /// let mut my_scope = Scope::new();
585 ///
586 /// my_scope.push_constant("x", 42_i64);
587 /// assert_eq!(my_scope.is_constant("x"), Some(true));
588 /// assert_eq!(my_scope.is_constant("y"), None);
589 /// ```
590 #[inline]
591 #[must_use]
592 pub fn is_constant(&self, name: &str) -> Option<bool> {
593 self.search(name)
594 .map(|n| match self.values[n].access_mode() {
595 AccessMode::ReadWrite => false,
596 AccessMode::ReadOnly => true,
597 })
598 }
599 /// Update the value of the named entry in the [`Scope`] if it already exists and is not constant.
600 /// Push a new entry with the value into the [`Scope`] if the name doesn't exist or if the
601 /// existing entry is constant.
602 ///
603 /// Search starts backwards from the last, and only the first entry matching the specified name is updated.
604 ///
605 /// # Example
606 ///
607 /// ```
608 /// use rhai::Scope;
609 ///
610 /// let mut my_scope = Scope::new();
611 ///
612 /// my_scope.set_or_push("x", 42_i64);
613 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
614 /// assert_eq!(my_scope.len(), 1);
615 ///
616 /// my_scope.set_or_push("x", 0_i64);
617 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 0);
618 /// assert_eq!(my_scope.len(), 1);
619 ///
620 /// my_scope.set_or_push("y", 123_i64);
621 /// assert_eq!(my_scope.get_value::<i64>("y").expect("y should exist"), 123);
622 /// assert_eq!(my_scope.len(), 2);
623 /// ```
624 #[inline]
625 pub fn set_or_push(
626 &mut self,
627 name: impl AsRef<str> + Into<Identifier>,
628 value: impl Variant + Clone,
629 ) -> &mut Self {
630 match self
631 .search(name.as_ref())
632 .map(|n| (n, self.values[n].access_mode()))
633 {
634 None | Some((.., AccessMode::ReadOnly)) => {
635 self.push(name, value);
636 }
637 Some((index, AccessMode::ReadWrite)) => {
638 let value_ref = self.values.get_mut(index).unwrap();
639 *value_ref = Dynamic::from(value);
640 }
641 }
642 self
643 }
644 /// Update the value of the named entry in the [`Scope`].
645 ///
646 /// Search starts backwards from the last, and only the first entry matching the specified name is updated.
647 /// If no entry matching the specified name is found, a new one is added.
648 ///
649 /// # Panics
650 ///
651 /// Panics when trying to update the value of a constant.
652 ///
653 /// # Example
654 ///
655 /// ```
656 /// use rhai::Scope;
657 ///
658 /// let mut my_scope = Scope::new();
659 ///
660 /// my_scope.push("x", 42_i64);
661 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
662 ///
663 /// my_scope.set_value("x", 0_i64);
664 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 0);
665 /// ```
666 #[inline]
667 pub fn set_value(
668 &mut self,
669 name: impl AsRef<str> + Into<Identifier>,
670 value: impl Variant + Clone,
671 ) -> &mut Self {
672 match self
673 .search(name.as_ref())
674 .map(|n| (n, self.values[n].access_mode()))
675 {
676 None => {
677 self.push(name, value);
678 }
679 Some((.., AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()),
680 Some((index, AccessMode::ReadWrite)) => {
681 let value_ref = self.values.get_mut(index).unwrap();
682 *value_ref = Dynamic::from(value);
683 }
684 }
685 self
686 }
687 /// Get a reference to an entry in the [`Scope`].
688 ///
689 /// If the entry by the specified name is not found, [`None`] is returned.
690 ///
691 /// # Example
692 ///
693 /// ```
694 /// use rhai::Scope;
695 ///
696 /// let mut my_scope = Scope::new();
697 ///
698 /// my_scope.push("x", 42_i64);
699 ///
700 /// let value = my_scope.get("x").expect("x should exist");
701 ///
702 /// assert_eq!(value.as_int().unwrap(), 42);
703 ///
704 /// assert!(my_scope.get("z").is_none());
705 /// ```
706 #[inline(always)]
707 #[must_use]
708 pub fn get(&self, name: &str) -> Option<&Dynamic> {
709 self.search(name).map(|index| &self.values[index])
710 }
711 /// Get a reference to an entry in the [`Scope`] based on the index.
712 ///
713 /// # Panics
714 ///
715 /// Panics if the index is out of bounds.
716 #[inline(always)]
717 #[allow(dead_code)]
718 pub(crate) fn get_entry_by_index(&self, index: usize) -> (&str, &Dynamic, &[ImmutableString]) {
719 (
720 &self.names[index],
721 &self.values[index],
722 if self.aliases.len() > index {
723 &self.aliases[index]
724 } else {
725 &[]
726 },
727 )
728 }
729 /// Remove the last entry in the [`Scope`] by the specified name and return its value.
730 ///
731 /// If the entry by the specified name is not found, [`None`] is returned.
732 ///
733 /// # Example
734 ///
735 /// ```
736 /// use rhai::Scope;
737 ///
738 /// let mut my_scope = Scope::new();
739 ///
740 /// my_scope.push("x", 123_i64); // first 'x'
741 /// my_scope.push("x", 42_i64); // second 'x', shadows first
742 ///
743 /// assert_eq!(my_scope.len(), 2);
744 ///
745 /// let value = my_scope.remove::<i64>("x").expect("x should exist");
746 ///
747 /// assert_eq!(value, 42);
748 ///
749 /// assert_eq!(my_scope.len(), 1);
750 ///
751 /// let value = my_scope.get_value::<i64>("x").expect("x should still exist");
752 ///
753 /// assert_eq!(value, 123);
754 /// ```
755 #[inline(always)]
756 #[must_use]
757 pub fn remove<T: Variant + Clone>(&mut self, name: &str) -> Option<T> {
758 self.search(name).and_then(|index| {
759 self.names.remove(index);
760 if self.aliases.len() > index {
761 self.aliases.remove(index);
762 }
763 self.values.remove(index).try_cast()
764 })
765 }
766 /// Get a mutable reference to the value of an entry in the [`Scope`].
767 ///
768 /// If the entry by the specified name is not found, or if it is read-only,
769 /// [`None`] is returned.
770 ///
771 /// # Example
772 ///
773 /// ```
774 /// use rhai::Scope;
775 ///
776 /// let mut my_scope = Scope::new();
777 ///
778 /// my_scope.push("x", 42_i64);
779 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
780 ///
781 /// let ptr = my_scope.get_mut("x").expect("x should exist");
782 /// *ptr = 123_i64.into();
783 ///
784 /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 123);
785 ///
786 /// my_scope.push_constant("z", 1_i64);
787 /// assert!(my_scope.get_mut("z").is_none());
788 /// ```
789 #[inline]
790 #[must_use]
791 pub fn get_mut(&mut self, name: &str) -> Option<&mut Dynamic> {
792 self.search(name)
793 .and_then(move |n| match self.values[n].access_mode() {
794 AccessMode::ReadWrite => Some(self.get_mut_by_index(n)),
795 AccessMode::ReadOnly => None,
796 })
797 }
798 /// Get a mutable reference to the value of an entry in the [`Scope`] based on the index.
799 ///
800 /// # Panics
801 ///
802 /// Panics if the index is out of bounds.
803 #[inline(always)]
804 pub(crate) fn get_mut_by_index(&mut self, index: usize) -> &mut Dynamic {
805 &mut self.values[index]
806 }
807 /// Add an alias to an entry in the [`Scope`].
808 ///
809 /// # Panics
810 ///
811 /// Panics if the index is out of bounds.
812 #[cfg(not(feature = "no_module"))]
813 #[inline]
814 pub(crate) fn add_alias_by_index(&mut self, index: usize, alias: ImmutableString) -> &mut Self {
815 if self.aliases.len() <= index {
816 self.aliases.resize(index + 1, <_>::default());
817 }
818 let aliases = self.aliases.get_mut(index).unwrap();
819 if !aliases.contains(&alias) {
820 aliases.push(alias);
821 }
822 self
823 }
824 /// Add an alias to a variable in the [`Scope`] so that it is exported under that name.
825 /// This is an advanced API.
826 ///
827 /// Variable aliases are used, for example, in [`Module::eval_ast_as_new`][crate::Module::eval_ast_as_new]
828 /// to create a new module with exported variables under different names.
829 ///
830 /// If the alias is empty, then the variable is exported under its original name.
831 ///
832 /// Multiple aliases can be added to any variable.
833 ///
834 /// Only the last variable matching the name (and not other shadowed versions) is aliased by this call.
835 #[cfg(not(feature = "no_module"))]
836 #[inline]
837 pub fn set_alias(
838 &mut self,
839 name: impl AsRef<str> + Into<Identifier>,
840 alias: impl Into<ImmutableString>,
841 ) {
842 if let Some(index) = self.search(name.as_ref()) {
843 let alias = match alias.into() {
844 x if x.is_empty() => name.into().into(),
845 x => x,
846 };
847 self.add_alias_by_index(index, alias);
848 }
849 }
850 /// Clone the [`Scope`], keeping only the last instances of each variable name.
851 /// Shadowed variables are omitted in the copy.
852 #[inline]
853 #[must_use]
854 pub fn clone_visible(&self) -> Self {
855 let len = self.len();
856 let mut scope = Self::new();
857
858 self.names.iter().rev().enumerate().for_each(|(i, name)| {
859 if scope.names.contains(name) {
860 return;
861 }
862
863 let index = len - 1 - i;
864 let v1 = &self.values[index];
865
866 scope.push_entry(name.clone(), v1.access_mode(), v1.clone());
867
868 if self.aliases.len() > index {
869 scope.aliases.resize(scope.len() - 1, <_>::default());
870 scope.aliases.push(self.aliases[index].clone());
871 }
872 });
873
874 scope
875 }
876 /// Get an iterator to entries in the [`Scope`].
877 /// Shared values are flatten-cloned.
878 ///
879 /// # Example
880 ///
881 /// ```
882 /// use rhai::{Dynamic, Scope};
883 ///
884 /// let mut my_scope = Scope::new();
885 ///
886 /// my_scope.push("x", 42_i64);
887 /// my_scope.push_constant("foo", "hello");
888 ///
889 /// let mut iter = my_scope.iter();
890 ///
891 /// let (name, is_constant, value) = iter.next().expect("value should exist");
892 /// assert_eq!(name, "x");
893 /// assert!(!is_constant);
894 /// assert_eq!(value.cast::<i64>(), 42);
895 ///
896 /// let (name, is_constant, value) = iter.next().expect("value should exist");
897 /// assert_eq!(name, "foo");
898 /// assert!(is_constant);
899 /// assert_eq!(value.cast::<String>(), "hello");
900 /// ```
901 #[inline(always)]
902 pub fn iter(&self) -> impl Iterator<Item = (&str, bool, Dynamic)> {
903 self.iter_inner()
904 .map(|(name, constant, value)| (name.as_str(), constant, value.flatten_clone()))
905 }
906 /// Get an iterator to entries in the [`Scope`].
907 /// Shared values are not expanded.
908 #[inline(always)]
909 pub fn iter_raw(&self) -> impl Iterator<Item = (&str, bool, &Dynamic)> {
910 self.iter_rev_inner()
911 .map(|(name, constant, value)| (name.as_str(), constant, value))
912 }
913 /// Get an iterator to entries in the [`Scope`].
914 /// Shared values are not expanded.
915 #[inline]
916 pub(crate) fn iter_inner(&self) -> impl Iterator<Item = (&ImmutableString, bool, &Dynamic)> {
917 self.names
918 .iter()
919 .zip(self.values.iter())
920 .map(|(name, value)| (name, value.is_read_only(), value))
921 }
922 /// Get a reverse iterator to entries in the [`Scope`].
923 /// Shared values are not expanded.
924 #[inline]
925 pub(crate) fn iter_rev_inner(
926 &self,
927 ) -> impl Iterator<Item = (&ImmutableString, bool, &Dynamic)> {
928 self.names
929 .iter()
930 .rev()
931 .zip(self.values.iter().rev())
932 .map(|(name, value)| (name, value.is_read_only(), value))
933 }
934 /// Remove a range of entries within the [`Scope`].
935 ///
936 /// # Panics
937 ///
938 /// Panics if the range is out of bounds.
939 #[inline]
940 #[allow(dead_code)]
941 pub(crate) fn remove_range(&mut self, start: usize, len: usize) {
942 self.values.drain(start..start + len).for_each(|_| {});
943 self.names.drain(start..start + len).for_each(|_| {});
944
945 if self.aliases.len() > start {
946 if self.aliases.len() <= start + len {
947 self.aliases.truncate(start);
948 } else {
949 self.aliases.drain(start..start + len).for_each(|_| {});
950 }
951 }
952 }
953}
954
955impl<K: Into<Identifier>> Extend<(K, Dynamic)> for Scope<'_> {
956 #[inline]
957 fn extend<T: IntoIterator<Item = (K, Dynamic)>>(&mut self, iter: T) {
958 for (name, value) in iter {
959 self.push_entry(name.into().into(), AccessMode::ReadWrite, value);
960 }
961 }
962}
963
964impl<K: Into<Identifier>> FromIterator<(K, Dynamic)> for Scope<'_> {
965 #[inline]
966 fn from_iter<T: IntoIterator<Item = (K, Dynamic)>>(iter: T) -> Self {
967 let mut scope = Self::new();
968 scope.extend(iter);
969 scope
970 }
971}
972
973impl<K: Into<Identifier>> Extend<(K, bool, Dynamic)> for Scope<'_> {
974 #[inline]
975 fn extend<T: IntoIterator<Item = (K, bool, Dynamic)>>(&mut self, iter: T) {
976 for (name, is_constant, value) in iter {
977 self.push_entry(
978 name.into().into(),
979 if is_constant {
980 AccessMode::ReadOnly
981 } else {
982 AccessMode::ReadWrite
983 },
984 value,
985 );
986 }
987 }
988}
989
990impl<K: Into<Identifier>> FromIterator<(K, bool, Dynamic)> for Scope<'_> {
991 #[inline]
992 fn from_iter<T: IntoIterator<Item = (K, bool, Dynamic)>>(iter: T) -> Self {
993 let mut scope = Self::new();
994 scope.extend(iter);
995 scope
996 }
997}