1use std::{
2 collections::hash_map::Entry,
3 error, fmt,
4 io::{self},
5};
6
7use rustc_hash::FxHashMap;
8use smol_str::SmolStr;
9
10use crate::{parser, Id, IdKind};
11
12#[derive(Debug, Clone, Copy)]
13pub struct ModuleIndex(usize);
14
15#[derive(Debug)]
16pub struct Map {
17 index: FxHashMap<SmolStr, ModuleIndex>,
18 items: Vec<Box<Module>>,
19}
20
21impl Map {
22 pub fn new() -> Self {
23 Self {
24 index: FxHashMap::default(),
25 items: Vec::new(),
26 }
27 }
28
29 pub fn get_by_index(&self, index: ModuleIndex) -> Option<&Module> {
30 self.items.get(index.0).map(|m| &**m)
31 }
32
33 pub fn get_mut_by_index(&mut self, index: ModuleIndex) -> Option<&mut Module> {
34 self.items.get_mut(index.0).map(|m| &mut **m)
35 }
36
37 pub fn get_by_id(&self, id: &str) -> Option<&Module> {
38 if let Some(index) = self.index.get(id) {
39 self.get_by_index(*index)
40 } else {
41 None
42 }
43 }
44
45 pub fn get_mut_by_id(&mut self, id: &str) -> Option<&mut Module> {
46 if let Some(index) = self.index.get(id) {
47 self.get_mut_by_index(*index)
48 } else {
49 None
50 }
51 }
52
53 pub fn import<R: io::BufRead>(&mut self, reader: &mut R) -> Result<(), Error> {
55 let mut contents = String::new();
56 reader.read_to_string(&mut contents)?;
57 let mut p = parser::Parser::new(&contents);
58 let mut module_index = ModuleIndex(0);
59 while let Some((kind, module_id, local_id, global_id)) = p.next_id()? {
60 if let Some(module_id) = module_id {
61 let i = match self.index.entry(SmolStr::from(module_id).clone()) {
62 Entry::Occupied(entry) => *entry.get(),
63 Entry::Vacant(entry) => {
64 let index = ModuleIndex(self.items.len());
65 self.items
66 .push(Box::new(Module::new(entry.key().clone(), index)));
67 *entry.insert(index)
68 }
69 };
70 module_index = i;
71 }
72 if let Some(module) = self.get_mut_by_index(module_index) {
73 let id = Id::new(kind, module.id.clone(), local_id.into(), global_id.into());
74 match kind {
75 IdKind::Class => insert_id(&mut module.classes, id)?,
76 IdKind::Var => insert_id(&mut module.vars, id)?,
77 IdKind::Keyframes => insert_id(&mut module.keyframes, id)?,
78 }
79 }
80 }
81 Ok(())
82 }
83}
84
85fn insert_id<'a>(map: &mut FxHashMap<SmolStr, Id>, id: Id) -> Result<(), Error> {
86 match map.entry(id.local_id.clone()) {
87 Entry::Occupied(..) => Err(Error::DuplicateEntry(id)),
88 Entry::Vacant(v) => {
89 v.insert(id);
90 Ok(())
91 }
92 }
93}
94
95#[derive(Debug)]
96pub struct Module {
97 pub id: SmolStr,
98 pub index: ModuleIndex,
99 pub classes: FxHashMap<SmolStr, Id>,
100 pub vars: FxHashMap<SmolStr, Id>,
101 pub keyframes: FxHashMap<SmolStr, Id>,
102}
103
104impl Module {
105 pub fn new(id: SmolStr, index: ModuleIndex) -> Self {
106 Self {
107 id,
108 index,
109 classes: FxHashMap::default(),
110 vars: FxHashMap::default(),
111 keyframes: FxHashMap::default(),
112 }
113 }
114}
115
116#[derive(Debug)]
117pub enum Error {
118 IOError(io::Error),
119 ParserError(parser::Error),
120 DuplicateEntry(Id),
121}
122
123impl From<io::Error> for Error {
124 fn from(value: io::Error) -> Self {
125 Error::IOError(value)
126 }
127}
128
129impl From<parser::Error> for Error {
130 fn from(value: parser::Error) -> Self {
131 Error::ParserError(value)
132 }
133}
134
135impl error::Error for Error {}
136
137impl fmt::Display for Error {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match self {
140 Error::IOError(err) => err.fmt(f),
141 Error::ParserError(err) => err.fmt(f),
142 Error::DuplicateEntry(id) => write!(f, "Duplicate entry: '{}'", id),
143 }
144 }
145}