1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::ast;
use crate::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
/// Storage for synthetic language items.
#[derive(Clone, Default)]
pub struct Storage {
inner: Rc<RefCell<Inner>>,
}
impl Storage {
/// Construct a new empty storage.
pub(crate) fn new() -> Self {
Self::default()
}
/// Construct a new number.
///
/// The number will be stored in this storage, and will be synthetic
/// (rather than from the source).
pub fn insert_number<N>(&self, number: N) -> usize
where
ast::Number: From<N>,
{
let mut inner = self.inner.borrow_mut();
let id = inner.numbers.len();
inner.numbers.push(number.into());
id
}
/// Insert the given text into storage and return its id.
///
/// This will reuse old storage slots that already contains the given
/// string.
pub fn insert_str(&self, string: &str) -> usize {
let mut inner = self.inner.borrow_mut();
if let Some(id) = inner.strings_rev.get(string).copied() {
return id;
}
let id = inner.strings.len();
let string = string.to_owned();
inner.strings.push(string.clone());
inner.strings_rev.insert(string, id);
id
}
/// Insert the given owned string into storage and return its id.
///
/// This will reuse old storage slots that already contains the given
/// string.
pub fn insert_string(&self, string: String) -> usize {
let mut inner = self.inner.borrow_mut();
if let Some(id) = inner.strings_rev.get(&string).copied() {
return id;
}
let id = inner.strings.len();
inner.strings.push(string.clone());
inner.strings_rev.insert(string, id);
id
}
/// Insert the given text into storage and return its id.
///
/// This will reuse old storage slots that already contains the given
/// byte string.
pub fn insert_byte_string(&self, bytes: &[u8]) -> usize {
let mut inner = self.inner.borrow_mut();
if let Some(id) = inner.byte_strings_rev.get(bytes).copied() {
return id;
}
let id = inner.byte_strings.len();
inner.byte_strings.push(bytes.to_vec());
inner.byte_strings_rev.insert(bytes.to_vec(), id);
id
}
/// Get the content of the byte string with the specified id and apply the
/// given operation over it.
pub fn with_byte_string<F, O>(&self, id: usize, with: F) -> Option<O>
where
F: FnOnce(&[u8]) -> O,
{
let inner = self.inner.borrow();
let s = inner.byte_strings.get(id)?;
Some(with(s))
}
/// Get the content of the string with the specified id.
pub fn get_string(&self, id: usize) -> Option<String> {
let inner = self.inner.borrow();
inner.strings.get(id).cloned()
}
/// Get the content of the string with the specified id and apply the given
/// operation over it.
pub fn with_string<F, O>(&self, id: usize, with: F) -> Option<O>
where
F: FnOnce(&str) -> O,
{
let inner = self.inner.borrow();
let s = inner.strings.get(id)?;
Some(with(s))
}
/// Get the content of the byte string with the specified id.
pub fn get_byte_string(&self, id: usize) -> Option<Vec<u8>> {
let inner = self.inner.borrow();
inner.byte_strings.get(id).cloned()
}
/// Get the content of the number with the specified id.
pub fn get_number(&self, id: usize) -> Option<ast::Number> {
let inner = self.inner.borrow();
inner.numbers.get(id).cloned()
}
/// Get the content of the number with the specified id and apply the given
/// operation over it.
pub fn with_number<F, O>(&self, id: usize, with: F) -> Option<O>
where
F: FnOnce(&ast::Number) -> O,
{
let inner = self.inner.borrow();
let s = inner.numbers.get(id)?;
Some(with(s))
}
}
#[derive(Default)]
struct Inner {
/// Stored strings.
strings: Vec<String>,
/// Reverse lookup for existing strings.
strings_rev: HashMap<String, usize>,
/// Stored byte strings.
byte_strings: Vec<Vec<u8>>,
/// Reverse lookup for existing byte strings.
byte_strings_rev: HashMap<Vec<u8>, usize>,
/// Numbers stored.
numbers: Vec<ast::Number>,
}