1use mical_cli_syntax::ast;
2use smallvec::{SmallVec, ToSmallVec};
3
4mod text_arena;
5use text_arena::{TextArena, TextId};
6
7mod error;
8pub use error::ConfigError;
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<ConfigError>) {
50 let ctx = eval::eval(&source_file);
51 let eval::EvalContext { arena, entries, errors, .. } = ctx;
52
53 let (sorted_indices, group_order) = Self::build_indices(&arena, &entries);
54 (Config { arena, entries, sorted_indices, group_order }, errors)
55 }
56
57 pub fn from_kv_entries<'a>(items: impl IntoIterator<Item = (&'a str, Value<'a>)>) -> Self {
58 let mut arena = TextArena::new();
59 let mut entries = Vec::new();
60 for (key, val) in items {
61 let key_id = arena.alloc(key);
62 let raw = match val {
63 Value::Bool(b) => ValueRaw::Bool(b),
64 Value::Integer(s) => ValueRaw::Integer(arena.alloc(s)),
65 Value::String(s) => ValueRaw::String(arena.alloc(s)),
66 };
67 entries.push((key_id, raw));
68 }
69 let (sorted_indices, group_order) = Self::build_indices(&arena, &entries);
70 Config { arena, entries, sorted_indices, group_order }
71 }
72
73 fn build_indices(
74 arena: &TextArena,
75 entries: &[(TextId, ValueRaw)],
76 ) -> (Vec<u32>, Vec<(u32, u32)>) {
77 let sorted_indices = {
78 let mut indices = (0..entries.len() as u32).collect::<Vec<_>>();
79 indices.sort_unstable_by(|&a, &b| {
80 arena[entries[a as usize].0].cmp(&arena[entries[b as usize].0])
81 });
82 indices
83 };
84 let group_order = {
85 let mut groups: Vec<(u32, u32, u32)> = Vec::new(); let mut i = 0;
87 while i < sorted_indices.len() {
88 let group_start = i;
89 let cur_key_id = entries[sorted_indices[i] as usize].0;
90 let mut min_idx = sorted_indices[i];
91 i += 1;
92 while i < sorted_indices.len() {
93 let next_key_id = entries[sorted_indices[i] as usize].0;
94 if arena[cur_key_id] != arena[next_key_id] {
95 break;
96 }
97 min_idx = min_idx.min(sorted_indices[i]); i += 1;
99 }
100 groups.push((group_start as u32, (i - group_start) as u32, min_idx));
101 }
102 groups.sort_unstable_by_key(|&(_, _, first)| first);
103 groups.into_iter().map(|(s, c, _)| (s, c)).collect()
104 };
105 (sorted_indices, group_order)
106 }
107
108 pub fn query<'a>(&'a self, key: &str) -> impl Iterator<Item = Value<'a>> + 'a {
110 let lo = self.sorted_indices.partition_point(|i| {
111 let key_id = self.entries[*i as usize].0;
112 &self.arena[key_id] < key
113 });
114 let hi = self.sorted_indices[lo..].partition_point(|i| {
115 let key_id = self.entries[*i as usize].0;
116 &self.arena[key_id] <= key
117 }) + lo;
118 let idxs: SmallVec<[u32; 2]> = {
119 const _: () = {
120 assert!(size_of::<SmallVec<[u32; 2]>>() == size_of::<SmallVec<[u32; 1]>>());
121 assert!(size_of::<SmallVec<[u32; 3]>>() > size_of::<SmallVec<[u32; 1]>>());
122 };
123 let mut v = self.sorted_indices[lo..hi].to_smallvec();
124 v.sort_unstable(); v
126 };
127 idxs.into_iter().map(move |i| {
128 let (_, raw) = self.entries[i as usize];
129 raw.to_value(&self.arena)
130 })
131 }
132
133 pub fn query_prefix<'a>(
135 &'a self,
136 prefix: &str,
137 ) -> impl Iterator<Item = (&'a str, Value<'a>)> + 'a {
138 let lo = self.sorted_indices.partition_point(|i| {
139 let key_id = self.entries[*i as usize].0;
140 &self.arena[key_id] < prefix
141 });
142 let hi = self.sorted_indices.partition_point(|i| {
143 let key_id = self.entries[*i as usize].0;
144 let key = &self.arena[key_id];
145 key.starts_with(prefix) || key < prefix
146 });
147 self.iter_range(lo, hi)
148 }
149
150 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a str, Value<'a>)> + 'a {
152 let n = self.sorted_indices.len();
153 self.iter_range(0, n)
154 }
155
156 fn iter_range<'a>(
157 &'a self,
158 lo: usize,
159 hi: usize,
160 ) -> impl Iterator<Item = (&'a str, Value<'a>)> + 'a {
161 let matching =
162 self.group_order.iter().filter(move |&(gs, _)| *gs >= lo as u32 && *gs < hi as u32);
163 matching.into_iter().flat_map(move |(group_start, count)| {
164 let idxs: SmallVec<[u32; 2]> = {
165 const _: () = {
166 assert!(size_of::<SmallVec<[u32; 2]>>() == size_of::<SmallVec<[u32; 1]>>());
167 assert!(size_of::<SmallVec<[u32; 3]>>() > size_of::<SmallVec<[u32; 1]>>());
168 };
169 let (group_start, count) = (*group_start as usize, *count as usize);
170 let mut v = self.sorted_indices[group_start..(group_start + count)].to_smallvec();
171 v.sort_unstable(); v
173 };
174 idxs.into_iter().map(move |i| {
175 let (key_id, raw) = self.entries[i as usize];
176 (&self.arena[key_id], raw.to_value(&self.arena))
177 })
178 })
179 }
180}