rune/macros/
storage.rs

1use core::fmt;
2
3use crate as rune;
4use crate::alloc;
5use crate::alloc::prelude::*;
6use crate::alloc::{HashMap, String, Vec};
7use crate::ast;
8
9/// A synthetic identifier which can be used to reference something in storage.
10#[derive(TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[try_clone(copy)]
12#[repr(transparent)]
13pub struct SyntheticId(usize);
14
15impl fmt::Display for SyntheticId {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        self.0.fmt(f)
18    }
19}
20
21impl fmt::Debug for SyntheticId {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        self.0.fmt(f)
24    }
25}
26
27/// The kind of a synthetic token.
28#[derive(Debug, Clone, Copy)]
29#[non_exhaustive]
30pub enum SyntheticKind {
31    /// A synthetic label.
32    Label,
33    /// A synthetic string.
34    String,
35    /// A synthetic byte string.
36    ByteString,
37    /// A synthetic identifier,
38    Ident,
39    /// A synthetic number.
40    Number,
41}
42
43impl fmt::Display for SyntheticKind {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        match self {
46            SyntheticKind::Label => "label".fmt(f),
47            SyntheticKind::String => "string".fmt(f),
48            SyntheticKind::ByteString => "byte string".fmt(f),
49            SyntheticKind::Ident => "identifier".fmt(f),
50            SyntheticKind::Number => "number".fmt(f),
51        }
52    }
53}
54
55/// Storage for synthetic language items.
56#[derive(Default)]
57pub(crate) struct Storage {
58    /// Stored strings.
59    strings: Vec<String>,
60    /// Reverse lookup for existing strings.
61    strings_rev: HashMap<String, SyntheticId>,
62    /// Stored byte strings.
63    byte_strings: Vec<Vec<u8>>,
64    /// Reverse lookup for existing byte strings.
65    byte_strings_rev: HashMap<Vec<u8>, SyntheticId>,
66    /// Numbers stored.
67    numbers: Vec<ast::Number>,
68}
69
70impl Storage {
71    /// Construct a new number.
72    ///
73    /// The number will be stored in this storage, and will be synthetic
74    /// (rather than from the source).
75    pub(crate) fn insert_number<N>(&mut self, number: N) -> alloc::Result<SyntheticId>
76    where
77        ast::Number: From<N>,
78    {
79        let id = SyntheticId(self.numbers.len());
80        self.numbers.try_push(number.into())?;
81        Ok(id)
82    }
83
84    /// Insert the given text into storage and return its id.
85    ///
86    /// This will reuse old storage slots that already contains the given
87    /// string.
88    pub(crate) fn insert_str(&mut self, string: &str) -> alloc::Result<SyntheticId> {
89        if let Some(id) = self.strings_rev.get(string).copied() {
90            return Ok(id);
91        }
92
93        let id = SyntheticId(self.strings.len());
94        let string = string.try_to_owned()?;
95        self.strings.try_push(string.try_clone()?)?;
96        self.strings_rev.try_insert(string, id)?;
97        Ok(id)
98    }
99
100    /// Insert the given owned string into storage and return its id.
101    ///
102    /// This will reuse old storage slots that already contains the given
103    /// string.
104    pub(crate) fn insert_string(&mut self, string: String) -> alloc::Result<SyntheticId> {
105        if let Some(id) = self.strings_rev.get(&string).copied() {
106            return Ok(id);
107        }
108
109        let id = SyntheticId(self.strings.len());
110        self.strings.try_push(string.try_clone()?)?;
111        self.strings_rev.try_insert(string, id)?;
112        Ok(id)
113    }
114
115    /// Insert the given text into storage and return its id.
116    ///
117    /// This will reuse old storage slots that already contains the given
118    /// byte string.
119    pub(crate) fn insert_byte_string(&mut self, bytes: &[u8]) -> alloc::Result<SyntheticId> {
120        if let Some(id) = self.byte_strings_rev.get(bytes).copied() {
121            return Ok(id);
122        }
123
124        let id = SyntheticId(self.byte_strings.len());
125        self.byte_strings.try_push(Vec::try_from(bytes)?)?;
126        self.byte_strings_rev
127            .try_insert(Vec::try_from(bytes)?, id)?;
128        Ok(id)
129    }
130
131    /// Get the content of the string with the specified id.
132    pub(crate) fn get_string(&self, id: SyntheticId) -> Option<&str> {
133        self.strings.get(id.0).map(|s| s.as_ref())
134    }
135
136    /// Get the content of the byte string with the specified id.
137    pub(crate) fn get_byte_string(&self, id: SyntheticId) -> Option<&[u8]> {
138        self.byte_strings.get(id.0).map(|b| b.as_ref())
139    }
140
141    /// Get the content of the number with the specified id.
142    pub(crate) fn get_number(&self, id: SyntheticId) -> Option<&ast::Number> {
143        self.numbers.get(id.0)
144    }
145}