cuicui_chirp/parser/ast/
build.rs

1use std::marker::PhantomData;
2
3use super::{as_usize, header, Ast};
4
5pub(in crate::parser) struct AstBuilder {
6    ast: Vec<header::Block>,
7    #[cfg(not(feature = "more_unsafe"))]
8    zero_header: Vec<(usize, &'static str)>,
9}
10pub(in crate::parser) struct Buffer<'a, const N: usize>(pub(super) &'a mut [header::Block; N]);
11
12impl AstBuilder {
13    pub fn new() -> Self {
14        Self {
15            ast: Vec::with_capacity(128),
16            #[cfg(not(feature = "more_unsafe"))]
17            zero_header: Vec::new(),
18        }
19    }
20    pub fn write_header<T, const N: usize>(&mut self, writer: T)
21    where
22        T: std::fmt::Debug + for<'a> WriteHeader<Buffer<'a> = Buffer<'a, N>>,
23    {
24        let header = self.reserve_header::<T>();
25        self.write(header, writer);
26    }
27    pub fn reserve_header<T: WriteHeader>(&mut self) -> AstBuilderHead<T> {
28        let index = self.ast.len();
29        self.ast.extend((0..T::SIZE).map(|_| header::Block(0)));
30        #[cfg(not(feature = "more_unsafe"))]
31        {
32            self.zero_header.push((index, std::any::type_name::<T>()));
33        }
34        AstBuilderHead { index, p: PhantomData }
35    }
36    #[cfg_attr(feature = "more_unsafe", allow(unused_mut))]
37    pub fn write<T, const N: usize>(&mut self, mut head: AstBuilderHead<T>, writer: T)
38    where
39        T: std::fmt::Debug + for<'a> WriteHeader<Buffer<'a> = Buffer<'a, N>>,
40    {
41        #[cfg(not(feature = "more_unsafe"))]
42        {
43            self.zero_header.pop();
44        }
45        let (start, end) = (head.index, head.index + as_usize(T::SIZE));
46        bevy::log::trace!("{start} - {writer:?}");
47        writer.write_header(Buffer((&mut self.ast[start..end]).try_into().unwrap()));
48    }
49    pub fn build(self) -> Ast {
50        #[cfg(not(feature = "more_unsafe"))]
51        {
52            for (index, name) in &self.zero_header {
53                bevy::log::error!(
54                    "{index} - {name}: Created header that never was initialized. \
55                        This is a cuicui_chirp bug, please open an issue at\n\n\
56                        https://github.com/nicopap/cuicui_layout/issues/new\n",
57                );
58            }
59            assert!(
60                self.zero_header.is_empty(),
61                "Proceeding would be unsound, aborting.."
62            );
63        }
64        Ast(self.ast.into())
65    }
66}
67
68pub(in crate::parser) struct AstBuilderHead<T: WriteHeader> {
69    index: usize,
70    p: PhantomData<T>,
71}
72
73pub(in crate::parser) trait WriteHeader: Sized {
74    const SIZE: u32;
75    type Buffer<'a>;
76
77    fn write_header(self, builder: Self::Buffer<'_>);
78}