ahtml/
flat.rs

1use anyhow::Result;
2
3use crate::allocator::{AId, ASlice, AVec, AllocatorType, Element, HtmlAllocator, Node, ToASlice};
4
5pub enum Flat<T> {
6    None,
7    One(AId<T>),
8    Two(AId<T>, AId<T>),
9    Slice(ASlice<T>),
10}
11
12impl<T: AllocatorType> Flat<T> {
13    pub fn to_vec(self, allocator: &HtmlAllocator) -> Result<AVec<'_, T>> {
14        match self {
15            Flat::None => Ok(allocator.new_vec()),
16            Flat::One(a) => {
17                let mut v = allocator.new_vec();
18                v.push(a)?;
19                Ok(v)
20            }
21            Flat::Two(a, b) => {
22                let mut v = allocator.new_vec();
23                v.push(a)?;
24                v.push(b)?;
25                Ok(v)
26            }
27            Flat::Slice(sl) => {
28                let mut vec = allocator.new_vec();
29                for v in sl.iter_aid(allocator) {
30                    vec.push(v)?;
31                }
32                Ok(vec)
33            }
34        }
35    }
36}
37
38impl<T: AllocatorType> ToASlice<T> for Flat<T> {
39    fn to_aslice(self, allocator: &HtmlAllocator) -> Result<ASlice<T>> {
40        match self {
41            Flat::None => Ok(allocator.empty_slice()),
42            Flat::One(a) => {
43                let mut v = allocator.new_vec();
44                v.push(a)?;
45                Ok(v.as_slice())
46            }
47            Flat::Two(a, b) => {
48                let mut v = allocator.new_vec();
49                v.push(a)?;
50                v.push(b)?;
51                Ok(v.as_slice())
52            }
53            Flat::Slice(sl) => Ok(sl),
54        }
55    }
56}
57
58impl<'a, T: AllocatorType> AVec<'a, T> {
59    pub fn push_flat(&mut self, flat: Flat<T>) -> Result<()> {
60        match flat {
61            Flat::None => Ok(()),
62            Flat::One(aid) => self.push(aid),
63            Flat::Two(a, b) => {
64                self.push(a)?;
65                self.push(b)?;
66                Ok(())
67            }
68            Flat::Slice(slice) => self.extend_from_slice(&slice, self.allocator()),
69        }
70    }
71}
72
73impl<'a, T: AllocatorType> ASlice<T> {
74    pub fn try_flat_map<F: Fn(AId<T>) -> Result<Flat<T>>>(
75        &self,
76        f: F,
77        capacity: Option<u32>, // None means self.len() will be used
78        allocator: &'a HtmlAllocator,
79    ) -> Result<AVec<'a, T>> {
80        let cap = capacity.unwrap_or_else(|| self.len());
81        let mut v = allocator.new_vec_with_capacity(cap)?;
82        let end = self.start + self.len;
83        for i in self.start..end {
84            let id = allocator
85                .get_id(i)
86                .expect("slice should always point to allocated storage");
87            v.push_flat(f(id)?)?; // XX .with_context on f's output?
88        }
89        Ok(v)
90    }
91}
92
93impl Element {
94    pub fn try_flat_map_body<'a, T: AllocatorType>(
95        &self,
96        f: impl Fn(AId<Node>) -> Result<Flat<Node>>,
97        allocator: &'a HtmlAllocator,
98    ) -> Result<Element> {
99        let body2 = self.body.try_flat_map(f, None, allocator)?;
100        Ok(Element {
101            meta: self.meta,
102            attr: self.attr.clone(),
103            body: body2.as_slice(),
104        })
105    }
106}