1use mical_cli_syntax::ast;
2use smallvec::{SmallVec, ToSmallVec};
3
4mod text_arena;
5use text_arena::{TextArena, TextId};
6
7mod error;
8pub use error::Error;
9
10mod eval;
11pub mod json;
12
13pub struct Config {
14 arena: TextArena,
15 entries: Vec<(TextId, ValueRaw)>,
17 sorted_indices: Vec<u32>,
19 group_order: Vec<(u32, u32)>,
22}
23
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub enum Value<'s> {
26 Bool(bool),
27 Integer(&'s str),
28 String(&'s str),
29}
30
31#[derive(Copy, Clone, PartialEq, Eq)]
32pub(crate) enum ValueRaw {
33 Bool(bool),
34 Integer(TextId),
35 String(TextId),
36}
37
38impl ValueRaw {
39 fn to_value<'s>(self, arena: &'s TextArena) -> Value<'s> {
40 match self {
41 ValueRaw::Bool(b) => Value::Bool(b),
42 ValueRaw::Integer(id) => Value::Integer(&arena[id]),
43 ValueRaw::String(id) => Value::String(&arena[id]),
44 }
45 }
46}
47
48impl Config {
49 pub fn from_source_file(source_file: ast::SourceFile) -> (Self, Vec<Error>) {
50 let eval::Output { arena, entries, errors } = eval::eval_source_file(&source_file);
51 let (sorted_indices, group_order) = Self::build_indices(&arena, &entries);
52 (Config { arena, entries, sorted_indices, group_order }, errors)
53 }
54
55 pub fn from_kv_entries<'a>(items: impl IntoIterator<Item = (&'a str, Value<'a>)>) -> Self {
56 let mut arena = TextArena::new();
57 let mut entries = Vec::new();
58 for (key, val) in items {
59 let key_id = arena.alloc(key);
60 let raw = match val {
61 Value::Bool(b) => ValueRaw::Bool(b),
62 Value::Integer(s) => ValueRaw::Integer(arena.alloc(s)),
63 Value::String(s) => ValueRaw::String(arena.alloc(s)),
64 };
65 entries.push((key_id, raw));
66 }
67 let (sorted_indices, group_order) = Self::build_indices(&arena, &entries);
68 Config { arena, entries, sorted_indices, group_order }
69 }
70
71 fn build_indices(
72 arena: &TextArena,
73 entries: &[(TextId, ValueRaw)],
74 ) -> (Vec<u32>, Vec<(u32, u32)>) {
75 let sorted_indices = {
76 let mut indices = (0..entries.len() as u32).collect::<Vec<_>>();
77 indices.sort_unstable_by(|&a, &b| {
78 arena[entries[a as usize].0].cmp(&arena[entries[b as usize].0])
79 });
80 indices
81 };
82 let group_order = {
83 let mut groups: Vec<(u32, u32, u32)> = Vec::new(); let mut i = 0;
85 while i < sorted_indices.len() {
86 let group_start = i;
87 let cur_key_id = entries[sorted_indices[i] as usize].0;
88 let mut min_idx = sorted_indices[i];
89 i += 1;
90 while i < sorted_indices.len() {
91 let next_key_id = entries[sorted_indices[i] as usize].0;
92 if arena[cur_key_id] != arena[next_key_id] {
93 break;
94 }
95 min_idx = min_idx.min(sorted_indices[i]); i += 1;
97 }
98 groups.push((group_start as u32, (i - group_start) as u32, min_idx));
99 }
100 groups.sort_unstable_by_key(|&(_, _, first)| first);
101 groups.into_iter().map(|(s, c, _)| (s, c)).collect()
102 };
103 (sorted_indices, group_order)
104 }
105
106 pub fn query<'a>(&'a self, key: &str) -> impl Iterator<Item = Value<'a>> + 'a {
108 let lo = self.sorted_indices.partition_point(|i| {
109 let key_id = self.entries[*i as usize].0;
110 &self.arena[key_id] < key
111 });
112 let hi = self.sorted_indices[lo..].partition_point(|i| {
113 let key_id = self.entries[*i as usize].0;
114 &self.arena[key_id] <= key
115 }) + lo;
116 let idxs: SmallVec<[u32; 2]> = {
117 const _: () = {
118 assert!(size_of::<SmallVec<[u32; 2]>>() == size_of::<SmallVec<[u32; 1]>>());
119 assert!(size_of::<SmallVec<[u32; 3]>>() > size_of::<SmallVec<[u32; 1]>>());
120 };
121 let mut v = self.sorted_indices[lo..hi].to_smallvec();
122 v.sort_unstable(); v
124 };
125 idxs.into_iter().map(move |i| {
126 let (_, raw) = self.entries[i as usize];
127 raw.to_value(&self.arena)
128 })
129 }
130
131 pub fn query_prefix<'a>(
133 &'a self,
134 prefix: &str,
135 ) -> impl Iterator<Item = (&'a str, Value<'a>)> + 'a {
136 let lo = self.sorted_indices.partition_point(|i| {
137 let key_id = self.entries[*i as usize].0;
138 &self.arena[key_id] < prefix
139 });
140 let hi = self.sorted_indices.partition_point(|i| {
141 let key_id = self.entries[*i as usize].0;
142 let key = &self.arena[key_id];
143 key.starts_with(prefix) || key < prefix
144 });
145 self.iter_range(lo, hi)
146 }
147
148 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a str, Value<'a>)> + 'a {
150 let n = self.sorted_indices.len();
151 self.iter_range(0, n)
152 }
153
154 fn iter_range<'a>(
155 &'a self,
156 lo: usize,
157 hi: usize,
158 ) -> impl Iterator<Item = (&'a str, Value<'a>)> + 'a {
159 let matching =
160 self.group_order.iter().filter(move |&(gs, _)| *gs >= lo as u32 && *gs < hi as u32);
161 matching.into_iter().flat_map(move |(group_start, count)| {
162 let idxs: SmallVec<[u32; 2]> = {
163 const _: () = {
164 assert!(size_of::<SmallVec<[u32; 2]>>() == size_of::<SmallVec<[u32; 1]>>());
165 assert!(size_of::<SmallVec<[u32; 3]>>() > size_of::<SmallVec<[u32; 1]>>());
166 };
167 let (group_start, count) = (*group_start as usize, *count as usize);
168 let mut v = self.sorted_indices[group_start..(group_start + count)].to_smallvec();
169 v.sort_unstable(); v
171 };
172 idxs.into_iter().map(move |i| {
173 let (key_id, raw) = self.entries[i as usize];
174 (&self.arena[key_id], raw.to_value(&self.arena))
175 })
176 })
177 }
178}