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}