Skip to main content

aver_rt/
lib.rs

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}