Skip to main content

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}