Skip to main content

rune/
statics.rs

1use core::fmt;
2
3use crate::alloc::{self, Vec};
4use crate::item::IntoComponent;
5use crate::{Item, ItemBuf};
6
7/// A collection of statics to declare when building a unit.
8///
9/// A `static` item usually comes from the source being compiled, but a host
10/// which wants to hand a script a piece of state does not necessarily want that
11/// state to be declared by the script. Statics declared here are added to the
12/// unit as if the source had declared them, so a script can read and write them
13/// by name without declaring them itself.
14///
15/// Such a static has no initializer, since there is no source to evaluate. This
16/// means it starts out uninitialized and reading it before anything has
17/// assigned it is a runtime error, exactly like a `static N;` in a script. The
18/// caller is expected to populate it through [`Globals::set`] before running
19/// anything which reads it.
20///
21/// Declaring a name which the source also declares is an error, since it is
22/// ambiguous which of the two declarations a use refers to.
23///
24/// [`Globals::set`]: crate::runtime::Globals::set
25///
26/// # Examples
27///
28/// ```
29/// use rune::{Context, Source, Sources, Statics, Vm};
30/// use rune::runtime::Globals;
31/// use rune::sync::Arc;
32///
33/// let context = Context::with_default_modules()?;
34/// let runtime = Arc::try_new(context.runtime()?)?;
35///
36/// let mut sources = Sources::new();
37/// sources.insert(Source::memory(r#"
38/// pub fn main() {
39///     LIMIT += 1;
40///     LIMIT
41/// }
42/// "#)?)?;
43///
44/// let mut statics = Statics::new();
45/// statics.insert(["LIMIT"])?;
46///
47/// let unit = rune::prepare(&mut sources)
48///     .with_context(&context)
49///     .with_statics(&statics)
50///     .build()?;
51///
52/// let unit = Arc::try_new(unit)?;
53/// let globals = Globals::new(unit.clone())?;
54/// globals.set(["LIMIT"], rune::to_value(41i64)?)?;
55///
56/// let mut vm = Vm::new(runtime, unit).with_globals(globals);
57/// let output = vm.call(["main"], ())?;
58/// assert_eq!(rune::from_value::<i64>(output)?, 42);
59/// # Ok::<_, rune::support::Error>(())
60/// ```
61#[derive(Default)]
62pub struct Statics {
63    statics: Vec<Static>,
64}
65
66impl Statics {
67    /// Construct an empty collection of statics.
68    #[inline]
69    pub const fn new() -> Self {
70        Self {
71            statics: Vec::new(),
72        }
73    }
74
75    /// Declare a static with the given name.
76    ///
77    /// The name is the item the static is declared as, so `["LIMIT"]` declares
78    /// it at the root of the unit and `["config", "LIMIT"]` declares it inside
79    /// of the `config` module. Every component has to be a valid identifier.
80    ///
81    /// Declaring the same name twice does nothing the second time.
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// use rune::Statics;
87    ///
88    /// let mut statics = Statics::new();
89    /// statics.insert(["LIMIT"])?;
90    /// statics.insert(["config", "LIMIT"])?;
91    /// assert_eq!(statics.len(), 2);
92    ///
93    /// statics.insert(["LIMIT"])?;
94    /// assert_eq!(statics.len(), 2);
95    /// # Ok::<_, rune::support::Error>(())
96    /// ```
97    #[inline]
98    pub fn insert(&mut self, name: impl IntoIterator<Item: IntoComponent>) -> alloc::Result<()> {
99        let item = ItemBuf::with_item(name)?;
100
101        if self.statics.iter().any(|s| s.item == item) {
102            return Ok(());
103        }
104
105        self.statics.try_push(Static { item })?;
106        Ok(())
107    }
108
109    /// The number of statics being declared.
110    #[inline]
111    pub fn len(&self) -> usize {
112        self.statics.len()
113    }
114
115    /// Test if the collection is empty.
116    #[inline]
117    pub fn is_empty(&self) -> bool {
118        self.statics.is_empty()
119    }
120
121    /// Iterate over the statics being declared.
122    pub(crate) fn iter(&self) -> impl Iterator<Item = &Static> {
123        self.statics.iter()
124    }
125}
126
127impl fmt::Debug for Statics {
128    #[inline]
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        f.debug_list().entries(self.statics.iter()).finish()
131    }
132}
133
134/// A single static being declared.
135///
136/// This is a type of its own so that a declaration can carry more than its name
137/// in the future, such as the type it is expected to hold.
138pub(crate) struct Static {
139    item: ItemBuf,
140}
141
142impl Static {
143    /// The item the static is declared as.
144    #[inline]
145    pub(crate) fn item(&self) -> &Item {
146        &self.item
147    }
148}
149
150impl fmt::Debug for Static {
151    #[inline]
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        self.item.fmt(f)
154    }
155}