1#![doc = include_str!("../README.md")]
2
3mod display;
4#[cfg(feature = "http")]
5pub mod http;
6pub mod http_server;
7mod runtime;
8mod service_types;
9pub mod tcp;
10
11pub use display::{AverDisplay, aver_display};
12pub use runtime::{
13 append_text, console_error, console_print, console_warn, delete_dir, delete_file, env_get,
14 env_set, list_dir, make_dir, path_exists, read_line, read_text, string_slice, time_now,
15 time_sleep, time_unix_ms, write_text,
16};
17pub use service_types::{Header, HttpRequest, HttpResponse, TcpConnection};
18
19use std::fmt;
20use std::hash::{Hash, Hasher};
21use std::iter::FusedIterator;
22use std::rc::Rc;
23
24pub struct AverList<T> {
25 inner: Rc<AverListInner<T>>,
26}
27
28enum AverListInner<T> {
29 Flat {
30 items: Rc<Vec<T>>,
31 start: usize,
32 },
33 Prepend {
34 head: T,
35 tail: AverList<T>,
36 len: usize,
37 },
38 Concat {
39 left: AverList<T>,
40 right: AverList<T>,
41 len: usize,
42 },
43}
44
45#[derive(Clone)]
46enum ListCursor<'a, T> {
47 Node(&'a AverList<T>),
48 Slice(&'a [T], usize),
49}
50
51pub struct AverListIter<'a, T> {
52 stack: Vec<ListCursor<'a, T>>,
53 remaining: usize,
54}
55
56impl<T> Clone for AverList<T> {
57 fn clone(&self) -> Self {
58 Self {
59 inner: Rc::clone(&self.inner),
60 }
61 }
62}
63
64impl<T> AverList<T> {
65 pub fn empty() -> Self {
66 Self::from_vec(vec![])
67 }
68
69 pub fn from_vec(items: Vec<T>) -> Self {
70 Self {
71 inner: Rc::new(AverListInner::Flat {
72 items: Rc::new(items),
73 start: 0,
74 }),
75 }
76 }
77
78 pub fn len(&self) -> usize {
79 match self.inner.as_ref() {
80 AverListInner::Flat { items, start } => items.len().saturating_sub(*start),
81 AverListInner::Prepend { len, .. } | AverListInner::Concat { len, .. } => *len,
82 }
83 }
84
85 pub fn is_empty(&self) -> bool {
86 self.len() == 0
87 }
88
89 pub fn get(&self, index: usize) -> Option<&T> {
90 self.iter().nth(index)
91 }
92
93 pub fn first(&self) -> Option<&T> {
94 self.iter().next()
95 }
96
97 pub fn as_slice(&self) -> Option<&[T]> {
98 match self.inner.as_ref() {
99 AverListInner::Flat { items, start } => Some(items.get(*start..).unwrap_or(&[])),
100 AverListInner::Prepend { .. } | AverListInner::Concat { .. } => None,
101 }
102 }
103
104 pub fn iter(&self) -> AverListIter<'_, T> {
105 AverListIter {
106 stack: vec![ListCursor::Node(self)],
107 remaining: self.len(),
108 }
109 }
110
111 pub fn tail(&self) -> Option<Self> {
112 match self.inner.as_ref() {
113 AverListInner::Flat { items, start } => {
114 if *start >= items.len() {
115 None
116 } else {
117 Some(Self {
118 inner: Rc::new(AverListInner::Flat {
119 items: Rc::clone(items),
120 start: start + 1,
121 }),
122 })
123 }
124 }
125 AverListInner::Prepend { tail, .. } => Some(tail.clone()),
126 AverListInner::Concat { left, right, .. } => {
127 let left_len = left.len();
128 if left_len == 0 {
129 right.tail()
130 } else if left_len == 1 {
131 Some(right.clone())
132 } else {
133 let left_tail = left.tail().expect("non-empty left side must have a tail");
134 Some(Self::concat(&left_tail, right))
135 }
136 }
137 }
138 }
139
140 pub fn prepend(item: T, list: &Self) -> Self {
141 if list.is_empty() {
142 return Self::from_vec(vec![item]);
143 }
144 Self {
145 inner: Rc::new(AverListInner::Prepend {
146 head: item,
147 tail: list.clone(),
148 len: list.len() + 1,
149 }),
150 }
151 }
152
153 pub fn concat(left: &Self, right: &Self) -> Self {
154 if left.is_empty() {
155 return right.clone();
156 }
157 if right.is_empty() {
158 return left.clone();
159 }
160 Self {
161 inner: Rc::new(AverListInner::Concat {
162 left: left.clone(),
163 right: right.clone(),
164 len: left.len() + right.len(),
165 }),
166 }
167 }
168
169 pub fn append(list: &Self, item: T) -> Self {
170 Self::concat(list, &Self::from_vec(vec![item]))
171 }
172
173 pub fn to_vec(&self) -> Vec<T>
174 where
175 T: Clone,
176 {
177 let mut out = Vec::with_capacity(self.len());
178 out.extend(self.iter().cloned());
179 out
180 }
181
182 pub fn reverse(&self) -> Self
183 where
184 T: Clone,
185 {
186 let mut out = self.to_vec();
187 out.reverse();
188 Self::from_vec(out)
189 }
190
191 pub fn contains(&self, item: &T) -> bool
192 where
193 T: PartialEq,
194 {
195 self.iter().any(|x| x == item)
196 }
197}
198
199impl<'a, T> Iterator for AverListIter<'a, T> {
200 type Item = &'a T;
201
202 fn next(&mut self) -> Option<Self::Item> {
203 while let Some(cursor) = self.stack.pop() {
204 match cursor {
205 ListCursor::Slice(items, index) => {
206 if let Some(item) = items.get(index) {
207 self.stack.push(ListCursor::Slice(items, index + 1));
208 self.remaining = self.remaining.saturating_sub(1);
209 return Some(item);
210 }
211 }
212 ListCursor::Node(list) => match list.inner.as_ref() {
213 AverListInner::Flat { items, start } => {
214 let slice = items.get(*start..).unwrap_or(&[]);
215 if !slice.is_empty() {
216 self.stack.push(ListCursor::Slice(slice, 0));
217 }
218 }
219 AverListInner::Prepend { head, tail, .. } => {
220 self.stack.push(ListCursor::Node(tail));
221 self.remaining = self.remaining.saturating_sub(1);
222 return Some(head);
223 }
224 AverListInner::Concat { left, right, .. } => {
225 self.stack.push(ListCursor::Node(right));
226 self.stack.push(ListCursor::Node(left));
227 }
228 },
229 }
230 }
231 None
232 }
233
234 fn size_hint(&self) -> (usize, Option<usize>) {
235 (self.remaining, Some(self.remaining))
236 }
237}
238
239impl<T> ExactSizeIterator for AverListIter<'_, T> {
240 fn len(&self) -> usize {
241 self.remaining
242 }
243}
244
245impl<T> FusedIterator for AverListIter<'_, T> {}
246
247impl<'a, T> IntoIterator for &'a AverList<T> {
248 type Item = &'a T;
249 type IntoIter = AverListIter<'a, T>;
250
251 fn into_iter(self) -> Self::IntoIter {
252 self.iter()
253 }
254}
255
256impl<T: Clone> IntoIterator for AverList<T> {
257 type Item = T;
258 type IntoIter = std::vec::IntoIter<T>;
259
260 fn into_iter(self) -> Self::IntoIter {
261 self.to_vec().into_iter()
262 }
263}
264
265impl<T: fmt::Debug> fmt::Debug for AverList<T> {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 f.debug_list().entries(self.iter()).finish()
268 }
269}
270
271impl<T: PartialEq> PartialEq for AverList<T> {
272 fn eq(&self, other: &Self) -> bool {
273 self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
274 }
275}
276
277impl<T: Eq> Eq for AverList<T> {}
278
279impl<T: Hash> Hash for AverList<T> {
280 fn hash<H: Hasher>(&self, state: &mut H) {
281 8u8.hash(state);
282 self.len().hash(state);
283 for item in self.iter() {
284 item.hash(state);
285 }
286 }
287}
288
289pub fn list_uncons<T>(list: &AverList<T>) -> Option<(&T, AverList<T>)> {
290 let head = list.first()?;
291 let tail = list.tail().expect("non-empty list must have a tail");
292 Some((head, tail))
293}
294
295pub fn string_join<S: AsRef<str>>(parts: &AverList<S>, sep: &str) -> String {
296 let mut iter = parts.iter();
297 let Some(first) = iter.next() else {
298 return String::new();
299 };
300 let mut out = first.as_ref().to_string();
301 for part in iter {
302 out.push_str(sep);
303 out.push_str(part.as_ref());
304 }
305 out
306}
307
308#[cfg(test)]
309mod tests {
310 use super::{AverList, aver_display, env_set, string_slice};
311
312 #[test]
313 fn prepend_and_tail_share_structure() {
314 let base = AverList::from_vec(vec![2, 3]);
315 let full = AverList::prepend(1, &base);
316 assert_eq!(full.first(), Some(&1));
317 assert_eq!(full.tail().unwrap(), base);
318 }
319
320 #[test]
321 fn concat_and_iter_preserve_order() {
322 let left = AverList::from_vec(vec![1, 2]);
323 let right = AverList::from_vec(vec![3, 4]);
324 let joined = AverList::concat(&left, &right);
325 assert_eq!(joined.to_vec(), vec![1, 2, 3, 4]);
326 }
327
328 #[test]
329 fn aver_display_quotes_strings_inside_lists() {
330 let parts = AverList::from_vec(vec!["a".to_string(), "b".to_string()]);
331 assert_eq!(aver_display(&parts), "[\"a\", \"b\"]");
332 }
333
334 #[test]
335 fn string_slice_uses_code_point_indices() {
336 assert_eq!(string_slice("zażółć", 1, 4), "ażó");
337 }
338
339 #[test]
340 fn env_set_rejects_invalid_keys() {
341 assert_eq!(
342 env_set("", "x"),
343 Err("Env.set: key must not be empty".to_string())
344 );
345 assert_eq!(
346 env_set("A=B", "x"),
347 Err("Env.set: key must not contain '='".to_string())
348 );
349 }
350}