1use {
3 std::collections::{HashMap, BTreeSet},
4 crate::{
5 makepad_live_id::*,
6 makepad_error_log::*,
7 makepad_live_tokenizer::{TokenWithLen, Delim, FullToken, LiveId, State, Cursor, live_error_origin, LiveErrorOrigin},
8 live_error::{LiveError, LiveErrorSpan, LiveFileError},
9 live_parser::LiveParser,
10 live_document::{LiveOriginal, LiveExpanded},
11 live_node::{LiveNodeOrigin, LiveNode, LiveValue, LiveType, LiveTypeInfo, LiveIdAsProp},
12 live_node_vec::{LiveNodeSliceApi, },
14 live_ptr::{LiveFileId, LivePtr, LiveModuleId, LiveFileGeneration},
15 live_token::{LiveToken, LiveTokenId, TokenWithSpan},
16 span::{TextSpan, TextPos},
17 live_expander::{LiveExpander},
18 live_component::{LiveComponentRegistries}
19 }
20};
21
22#[derive(Default)]
23pub struct LiveFile {
24 pub (crate) reexpand: bool,
25
26 pub module_id: LiveModuleId,
27 pub (crate) start_pos: TextPos,
28 pub file_name: String,
29 pub cargo_manifest_path: String,
30 pub (crate) source: String,
31 pub (crate) deps: BTreeSet<LiveModuleId>,
32
33 pub generation: LiveFileGeneration,
34 pub original: LiveOriginal,
35 pub next_original: Option<LiveOriginal>,
36 pub expanded: LiveExpanded,
37
38 pub live_type_infos: Vec<LiveTypeInfo>,
39}
40
41pub struct LiveRegistry {
42 pub (crate) file_ids: HashMap<String, LiveFileId>,
43 pub module_id_to_file_id: HashMap<LiveModuleId, LiveFileId>,
44 pub live_files: Vec<LiveFile>,
45 pub live_type_infos: HashMap<LiveType, LiveTypeInfo>,
46 pub main_module: Option<(LiveModuleId, LiveId)>,
48 pub components: LiveComponentRegistries,
49 pub package_root: Option<String>
50}
51
52impl Default for LiveRegistry {
53 fn default() -> Self {
54 Self {
55 main_module: None,
56 file_ids: HashMap::new(),
57 module_id_to_file_id: HashMap::new(),
58 live_files: Vec::new(),
59 live_type_infos: HashMap::new(),
60 components: LiveComponentRegistries::default(),
61 package_root: None
62 }
63 }
64}
65#[derive(Copy, Clone, Debug, PartialEq)]
73pub enum LiveScopeTarget {
74 LocalPtr(usize),
75 LivePtr(LivePtr)
76}
77
78
79#[derive(Clone, Debug, PartialEq)]
80pub struct LiveFileChange {
81 pub file_name: String,
82 pub content: String
83}
84
85impl LiveRegistry {
86
87 pub fn generation_valid(&self, live_ptr: LivePtr) -> bool {
88 let doc = &self.live_files[live_ptr.file_id.to_index()];
89 doc.generation == live_ptr.generation
90 }
91
92 pub fn ptr_to_node(&self, live_ptr: LivePtr) -> &LiveNode {
93 let doc = &self.live_files[live_ptr.file_id.to_index()];
94 if doc.generation != live_ptr.generation {
95 panic!("ptr_to_node generation invalid for file {} gen:{} ptr:{}", doc.file_name, doc.generation, live_ptr.generation);
96 }
97 doc.expanded.resolve_ptr(live_ptr.index as usize)
98 }
99
100 pub fn file_name_to_file_id(&self, file_name: &str) -> Option<LiveFileId> {
101 for (index, file) in self.live_files.iter().enumerate() {
102 if file.file_name == file_name {
103 return Some(LiveFileId::new(index))
104 }
105 }
106 None
107 }
108
109 pub fn file_id_to_file_name(&self, file_id: LiveFileId) -> &str {
110 &self.live_files[file_id.to_index()].file_name
111 }
112
113 pub fn file_id_to_cargo_manifest_path(&self, file_id: LiveFileId) -> String {
114 let file = &self.live_files[file_id.to_index()];
115 let manifest_path = &file.cargo_manifest_path;
116 if let Some(package_root) = &self.package_root {
117 if file.module_id.0.0 == 0 {
118 return package_root.to_string();
119 }
120 return format!("{}/{}", package_root, file.module_id.0);
121 }
122 manifest_path.to_string()
123 }
124
125 pub fn crate_name_to_cargo_manifest_path(&self, crate_name: &str) -> Option<String> {
126 let crate_name = crate_name.replace('-', "_");
127 let base_crate = LiveId::from_str_with_lut(&crate_name).unwrap();
128 for file in &self.live_files {
129 if file.module_id.0 == base_crate {
130 if let Some(package_root) = &self.package_root {
131 return Some(format!("{}/{}", package_root, crate_name));
132 }
133 return Some(file.cargo_manifest_path.to_string())
134 }
135 }
136 None
137 }
138
139 pub fn ptr_to_doc_node(&self, live_ptr: LivePtr) -> (&LiveExpanded, &LiveNode) {
140 let doc = &self.live_files[live_ptr.file_id.to_index()];
141 if doc.generation != live_ptr.generation {
142 panic!("ptr_to_doc_node generation invalid for file {} gen:{} ptr:{}", doc.file_name, doc.generation, live_ptr.generation);
143 }
144 (&doc.expanded, doc.expanded.resolve_ptr(live_ptr.index as usize))
145 }
146
147 pub fn ptr_to_doc(&self, live_ptr: LivePtr) -> &LiveExpanded {
148 let doc = &self.live_files[live_ptr.file_id.to_index()];
149 if doc.generation != live_ptr.generation {
150 panic!("ptr_to_doc generation invalid for file {} gen:{} ptr:{}", doc.file_name, doc.generation, live_ptr.generation);
151 }
152 &doc.expanded
153 }
154
155 pub fn file_id_to_file(&self, file_id: LiveFileId) -> &LiveFile {
156 &self.live_files[file_id.to_index()]
157 }
158
159 pub fn file_id_to_file_mut(&mut self, file_id: LiveFileId) -> &mut LiveFile {
160 &mut self.live_files[file_id.to_index()]
161 }
162
163 pub fn file_id_index_to_live_ptr(&self, file_id: LiveFileId, index: usize) -> LivePtr {
164 LivePtr {
165 file_id,
166 index: index as u32,
167 generation: self.live_files[file_id.to_index()].generation
168 }
169 }
170
171 pub fn ptr_to_nodes_index(&self, live_ptr: LivePtr) -> (&[LiveNode], usize) {
172 let doc = &self.live_files[live_ptr.file_id.to_index()];
173 if doc.generation != live_ptr.generation {
174 panic!("ptr_to_nodes_index generation invalid for file {} gen:{} ptr:{}", doc.file_name, doc.generation, live_ptr.generation);
175 }
176 (&doc.expanded.nodes, live_ptr.index as usize)
177 }
178
179 pub fn path_str_to_file_id(&self, path: &str) -> Option<LiveFileId> {
180 for (index, file) in self.live_files.iter().enumerate() {
181 if file.file_name == path {
182 return Some(LiveFileId(index as u16))
183 }
184 }
185 None
186 }
187
188
189 pub fn token_id_to_origin_doc(&self, token_id: LiveTokenId) -> &LiveOriginal {
190 &self.live_files[token_id.file_id().unwrap().to_index()].original
191 }
192
193 pub fn token_id_to_token(&self, token_id: LiveTokenId) -> &TokenWithSpan {
194 &self.live_files[token_id.file_id().unwrap().to_index()].original.tokens[token_id.token_index()]
195 }
196
197 pub fn token_id_to_expanded_doc(&self, token_id: LiveTokenId) -> &LiveExpanded {
198 &self.live_files[token_id.file_id().unwrap().to_index()].expanded
199 }
200
201 pub fn module_id_to_file_id(&self, module_id: LiveModuleId) -> Option<LiveFileId> {
202 self.module_id_to_file_id.get(&module_id).cloned()
203 }
204
205 pub fn file_id_to_module_id(&self, file_id: LiveFileId) -> Option<LiveModuleId> {
206 if let Some((k,_v)) = self.module_id_to_file_id.iter().find(|(_k,v)| **v == file_id){
207 return Some(*k)
208 }
209 None
210 }
211
212 pub fn live_node_as_string(&self, node: &LiveNode) -> Option<String> {
213 match &node.value {
214 LiveValue::Str(v) => {
215 Some(v.to_string())
216 }
217 LiveValue::String(v) => {
218 Some(v.as_str().to_string())
219 }
220 LiveValue::InlineString(v) => {
221 Some(v.as_str().to_string())
222 }
223 LiveValue::Dependency (v) => {
224 Some(v.as_str().to_string())
225 }
226 _ => None
227 }
228 }
229
230 pub fn get_node_prefix(&self, origin: LiveNodeOrigin) -> Option<LiveId> {
232 if !origin.node_has_prefix() {
233 return None
234 }
235 let first_def = origin.first_def().unwrap();
236 let token_index = first_def.token_index();
237 if token_index == 0 {
238 return None;
239 }
240 let doc = &self.live_files[first_def.file_id().unwrap().to_index()].original;
241 let token = &doc.tokens[token_index - 1];
242 if let LiveToken::Ident(id) = token.token {
243 return Some(id)
244 }
245 None
246 }
247
248 pub fn module_id_to_expanded_nodes(&self, module_id: LiveModuleId) -> Option<&[LiveNode]> {
249 if let Some(file_id) = self.module_id_to_file_id.get(&module_id) {
250 let doc = &self.live_files[file_id.to_index()].expanded;
251 return Some(&doc.nodes)
252 }
253 None
254 }
255
256 pub fn module_id_and_name_to_ptr(&self, module_id: LiveModuleId, name: LiveId) -> Option<LivePtr> {
257 if let Some(file_id) = self.module_id_to_file_id.get(&module_id) {
258 let live = &self.live_files[file_id.to_index()];
259 let doc = &live.expanded;
260 if name != LiveId::empty() {
261 if doc.nodes.is_empty() {
262 error!("module_path_id_to_doc zero nodelen {}", self.file_id_to_file_name(*file_id));
263 return None
264 }
265 if let Some(index) = doc.nodes.child_by_name(0, name.as_instance()) {
266 return Some(LivePtr {file_id: *file_id, index: index as u32, generation: live.generation});
267 }
268 else {
269 return None
270 }
271 }
272 else {
273 return Some(LivePtr {file_id: *file_id, index: 0, generation: live.generation});
274 }
275 }
276 None
277 }
278 pub fn find_module_id_name(&self, item: LiveId, module_id: LiveModuleId) -> Option<LiveScopeTarget> {
312 if let Some(file_id) = self.module_id_to_file_id(module_id) {
314 let file = self.file_id_to_file(file_id);
315 if file.expanded.nodes.is_empty() {
316 log!("Looking for {} but its not expanded yet, dependency order bug", file.file_name);
317 return None
318 }
319 if let Some(index) = file.expanded.nodes.child_by_name(0, item.as_instance()) {
320 return Some(LiveScopeTarget::LivePtr(
321 LivePtr {file_id, index: index as u32, generation: file.generation}
322 ))
323 }
324 }
325 None
326 }
327
328 pub fn find_scope_target(&self, item: LiveId, nodes: &[LiveNode]) -> Option<LiveScopeTarget> {
329 if let LiveValue::Root {id_resolve} = &nodes[0].value {
330 id_resolve.get(&item).cloned()
331 }
332 else {
333 log!("Can't find scope target on rootnode without id_resolve");
334 None
335 }
336 }
337
338
339 pub fn find_scope_target_one_level_or_global(&self, item: LiveId, index: usize, nodes: &[LiveNode]) -> Option<LiveScopeTarget> {
340 if let Some(index) = nodes.scope_up_down_by_name(index, item.as_instance(), 1) {
341 Some(LiveScopeTarget::LocalPtr(index))
342 } else {
343 self.find_scope_target(item, nodes)
344 }
345 }
346
347 pub fn find_scope_ptr_via_expand_index(&self, file_id: LiveFileId, index: usize, item: LiveId) -> Option<LivePtr> {
348 let file = self.file_id_to_file(file_id);
353 match self.find_scope_target_one_level_or_global(item, index, &file.expanded.nodes) {
354 Some(LiveScopeTarget::LocalPtr(index)) => Some(LivePtr {file_id, index: index as u32, generation: file.generation}),
355 Some(LiveScopeTarget::LivePtr(ptr)) => Some(ptr),
356 None => None
357 }
358 }
359
360 pub fn live_error_to_live_file_error(&self, live_error: LiveError) -> LiveFileError {
361 match live_error.span {
362 LiveErrorSpan::Text(text_span) => {
363 let live_file = &self.live_files[text_span.file_id.to_index()];
364 LiveFileError {
365 origin: live_error.origin,
366 file: live_file.file_name.clone(),
367 span: text_span,
368 message: live_error.message
369 }
370 }
371 LiveErrorSpan::Token(token_span) => {
372 let (file_name, span) = if let Some(file_id) = token_span.token_id.file_id() {
373 let live_file = &self.live_files[file_id.to_index()];
374 (live_file.file_name.as_str(), live_file.original.tokens[token_span.token_id.token_index()].span)
375 }
376 else {
377 ("<file id is not defined>", TextSpan::default())
378 };
379 LiveFileError {
380 origin: live_error.origin,
381 file: file_name.to_string(),
382 span,
383 message: live_error.message
384 }
385 }
386 }
387 }
388
389 pub fn token_id_to_span(&self, token_id: LiveTokenId) -> TextSpan {
390 self.live_files[token_id.file_id().unwrap().to_index()].original.token_id_to_span(token_id)
391 }
392
393 pub fn tokenize_from_str(source: &str, start_pos: TextPos, file_id: LiveFileId) -> Result<Vec<TokenWithSpan>, LiveError> {
394 let mut line_chars = Vec::new();
395 let mut state = State::default();
396 let mut scratch = String::new();
397 let mut tokens = Vec::new();
398 let mut line_count = start_pos.line;
399 for line_str in source.lines() {
400 line_chars.clear();
401 line_chars.extend(line_str.chars());
402 let mut cursor = Cursor::new(&line_chars, &mut scratch);
403 let mut last_index = 0usize;
404 loop {
405 let (next_state, full_token) = state.next(&mut cursor);
406 if let Some(full_token) = full_token {
407 let span = TextSpan {
408 file_id,
409 start: TextPos {column: last_index as u32, line: line_count},
410 end: TextPos {column: last_index as u32 + full_token.len as u32, line: line_count}
411 };
412 match full_token.token {
413 FullToken::Unknown | FullToken::OtherNumber | FullToken::Lifetime => {
414 return Err(LiveError {
415 origin: live_error_origin!(),
416 span: span.into(),
417 message: "Error tokenizing".to_string()
418 })
419 },
420 _ => if let Some(live_token) = LiveToken::from_full_token(&full_token.token) {
421 tokens.push(TokenWithSpan {span, token: live_token})
423 },
424 }
425 }
426 else {
427 break;
428 }
429 state = next_state;
430 last_index = cursor.index();
431 }
432 line_count += 1;
433 }
434 tokens.push(TokenWithSpan {span: TextSpan::default(), token: LiveToken::Eof});
435 Ok(tokens)
436 }
437
438 pub fn tokenize_from_str_live_design(source: &str, start_pos: TextPos, file_id: LiveFileId, mut negative:Option<&mut Vec<TokenWithLen>>) -> Result<Vec<TokenWithSpan>, LiveError> {
439 let mut line_chars = Vec::new();
440 let mut state = State::default();
441 let mut scratch = String::new();
442 let mut tokens = Vec::new();
443 let mut line_count = start_pos.line;
444 #[derive(Debug)]
445 enum Parse{
446 Before,
447 After,
448 Bang,
449 Brace,
450 Body(usize),
451 }
452 let mut parse = Parse::Before;
453
454 'outer: for line_str in source.lines() {
455 line_chars.clear();
456 line_chars.extend(line_str.chars());
457 let mut cursor = Cursor::new(&line_chars, &mut scratch);
458 let mut last_index = 0usize;
459 loop {
460 let (next_state, full_token) = state.next(&mut cursor);
461 if let Some(full_token) = full_token {
462 match parse{
464 Parse::Before=>{
465 if let FullToken::Ident(live_id!(live_design)) = &full_token.token{
466 parse = Parse::Bang;
467 }
468 else if let Some(negative) = &mut negative{
469 negative.push(full_token);
470 }
471 }
472 Parse::Bang=> if let FullToken::Punct(live_id!(!)) = &full_token.token{
473 parse = Parse::Brace;
474 }
475 else if let FullToken::Whitespace = &full_token.token{
476 }
477 else{
478 parse = Parse::Before;
479 }
480 Parse::Brace=> if let FullToken::Open(Delim::Brace) = &full_token.token{
481 parse = Parse::Body(0);
482 }
483 else if let FullToken::Whitespace = &full_token.token{
484 }
485 else{
486 parse = Parse::Before;
487 }
488 Parse::Body(depth)=>{
489 if let FullToken::Open(Delim::Brace) = &full_token.token{
490 parse = Parse::Body(depth + 1)
491 }
492 if let FullToken::Close(Delim::Brace) = &full_token.token{
493 if depth == 0{
494 last_index = cursor.index();
495 parse = Parse::After;
496 continue;
497 }
498 parse = Parse::Body(depth - 1);
499 }
500 let span = TextSpan {
501 file_id,
502 start: TextPos {column: last_index as u32, line: line_count},
503 end: TextPos {column: last_index as u32 + full_token.len as u32, line: line_count}
504 };
505 if let Some(live_token) = LiveToken::from_full_token(&full_token.token) {
506 tokens.push(TokenWithSpan {span, token: live_token})
507 }
508 }
509 Parse::After=>{
510 if let Some(negative) = &mut negative{
511 negative.push(full_token);
512 }
513 else{
514 break 'outer;
515 }
516 }
517 }
518 }
519 else {
520 break;
521 }
522 state = next_state;
523 last_index = cursor.index();
524 }
525 line_count += 1;
526 }
527 tokens.push(TokenWithSpan {span: TextSpan::default(), token: LiveToken::Eof});
528 Ok(tokens)
529 }
530
531 pub fn process_file_changes(&mut self, changes: Vec<LiveFileChange>, errors:&mut Vec<LiveError >){
532 let mut any_changes = false;
533 for change in changes {
534 if let Some(file_id) = self.file_name_to_file_id(&change.file_name){
535 let module_id = self.file_id_to_module_id(file_id).unwrap();
536 let live_file = self.file_id_to_file_mut(file_id);
537 match Self::tokenize_from_str_live_design(&change.content, TextPos::default(), file_id, None) {
538 Err(msg) => errors.push(msg), Ok(new_tokens) => {
540 let mut parser = LiveParser::new(&new_tokens, &live_file.live_type_infos, file_id);
541 match parser.parse_live_document() {
542 Err(msg) => {
543 errors.push(msg);
544 },
545 Ok(mut ld) => { for node in &mut ld.nodes {
547 match &mut node.value {
548 LiveValue::Import(live_import) => {
549 if live_import.module_id.0 == live_id!(crate) { live_import.module_id.0 = module_id.0
551 };
552 }
553 _=>()
554 }
555 }
556 any_changes = true;
557 ld.tokens = new_tokens;
558 live_file.original = ld;
559 live_file.reexpand = true;
560 live_file.generation.next_gen();
561 }
562 };
563 }
564 }
565 }
566 }
567 if any_changes{
568 self.expand_all_documents(errors);
570 }
571 }
572
573 pub fn register_live_file(
574 &mut self,
575 file_name: &str,
576 cargo_manifest_path: &str,
577 own_module_id: LiveModuleId,
578 source: String,
579 live_type_infos: Vec<LiveTypeInfo>,
580 start_pos: TextPos,
581 ) -> Result<LiveFileId, LiveFileError> {
582
583 if self.file_ids.get(file_name).is_some() {
585 panic!("cant register same file twice {}", file_name);
586 }
587 let file_id = LiveFileId::new(self.live_files.len());
588
589 let tokens = match Self::tokenize_from_str(&source, start_pos, file_id) {
590 Err(msg) => return Err(msg.into_live_file_error(file_name)), Ok(lex_result) => lex_result
592 };
593
594 let mut parser = LiveParser::new(&tokens, &live_type_infos, file_id);
595
596 let mut original = match parser.parse_live_document() {
597 Err(msg) => return Err(msg.into_live_file_error(file_name)), Ok(ld) => ld
599 };
600
601 original.tokens = tokens;
602
603 for live_type_info in &live_type_infos {
605 if let Some(info) = self.live_type_infos.get(&live_type_info.live_type) {
606 if info.module_id != live_type_info.module_id
607 || info.live_type != live_type_info.live_type {
608 panic!()
609 }
610 };
611 self.live_type_infos.insert(live_type_info.live_type, live_type_info.clone());
612 }
613
614 let mut deps = BTreeSet::new();
615
616 for node in &mut original.nodes {
617 match &mut node.value {
618 LiveValue::Import(live_import) => {
619 if live_import.module_id.0 == live_id!(crate) { live_import.module_id.0 = own_module_id.0
621 };
622 deps.insert(live_import.module_id);
623 }, LiveValue::Class {live_type, ..} => { let infos = self.live_type_infos.get(live_type).unwrap();
632 for sub_type in infos.fields.clone() {
633 let sub_module_id = sub_type.live_type_info.module_id;
634 if sub_module_id != own_module_id {
635 deps.insert(sub_module_id);
636 }
637 }
638 }
639 _ => {
640 }
641 }
642 }
643
644 let live_file = LiveFile {
645 cargo_manifest_path: cargo_manifest_path.to_string(),
646 reexpand: true,
647 module_id: own_module_id,
648 file_name: file_name.to_string(),
649 start_pos,
650 deps,
651 source,
652 generation: LiveFileGeneration::default(),
653 live_type_infos,
654 original,
655 next_original: None,
656 expanded: LiveExpanded::new()
657 };
658 self.module_id_to_file_id.insert(own_module_id, file_id);
659
660 self.file_ids.insert(file_name.to_string(), file_id);
661 self.live_files.push(live_file);
662
663 Ok(file_id)
664 }
665
666 pub fn expand_all_documents(&mut self, errors: &mut Vec<LiveError>) {
667 let mut dep_order = Vec::new();
671
672 fn recur_insert_dep(parent_index: usize, dep_order: &mut Vec<LiveModuleId>, current: LiveModuleId, files: &Vec<LiveFile>) {
673 let file = if let Some(file) = files.iter().find( | v | v.module_id == current) {
674 file
675 }
676 else {
677 return
678 };
679 let final_index = if let Some(index) = dep_order.iter().position( | v | *v == current) {
680 if index > parent_index { dep_order.remove(index);
682 dep_order.insert(parent_index, current);
683 parent_index
684 }
685 else {
686 index
687 }
688 }
689 else {
690 dep_order.insert(parent_index, current);
691 parent_index
692 };
693
694 for dep in &file.deps {
695 recur_insert_dep(final_index, dep_order, *dep, files);
696 }
697 }
698
699 for file in &self.live_files {
700 recur_insert_dep(dep_order.len(), &mut dep_order, file.module_id, &self.live_files);
701 }
702
703 fn recur_check_reexpand(current: LiveModuleId, files: &Vec<LiveFile>) -> bool {
705 let file = if let Some(file) = files.iter().find( | v | v.module_id == current) {
706 file
707 }
708 else {
709 return false
710 };
711
712 if file.reexpand {
713 return true;
714 }
715
716 for dep in &file.deps {
717 if recur_check_reexpand(*dep, files) {
718 return true
719 }
720 }
721 false
722 }
723
724 for i in 0..self.live_files.len() {
725 if recur_check_reexpand(self.live_files[i].module_id, &self.live_files) {
726 self.live_files[i].reexpand = true;
727 }
728 }
729
730 for module_id in dep_order {
731 let file_id = if let Some(file_id) = self.module_id_to_file_id.get(&module_id) {
732 file_id
733 }
734 else {
735 continue
736 };
737
738 if !self.live_files[file_id.to_index()].reexpand {
739 continue;
740 }
741
742 let mut out_doc = LiveExpanded::new();
743 std::mem::swap(&mut out_doc, &mut self.live_files[file_id.to_index()].expanded);
744
745 out_doc.nodes.clear();
746
747 let in_doc = &self.live_files[file_id.to_index()].original;
748
749 let mut live_document_expander = LiveExpander {
750 live_registry: self,
751 in_crate: module_id.0,
752 in_file_id: *file_id,
753 errors
754 };
755 live_document_expander.expand(in_doc, &mut out_doc, self.live_files[file_id.to_index()].generation);
756
757 self.live_files[file_id.to_index()].reexpand = false;
758 std::mem::swap(&mut out_doc, &mut self.live_files[file_id.to_index()].expanded);
759 }
760 }
761}
762
763struct FileDepIter {
764 files_todo: Vec<LiveFileId>,
765 files_done: Vec<LiveFileId>
766}
767
768impl FileDepIter {
769 pub fn new(start: LiveFileId) -> Self {
770 Self {
771 files_todo: vec![start],
772 files_done: Vec::new()
773 }
774 }
775
776 pub fn pop_todo(&mut self) -> Option<LiveFileId> {
777 if let Some(file_id) = self.files_todo.pop() {
778 self.files_done.push(file_id);
779 Some(file_id)
780 }
781 else {
782 None
783 }
784 }
785
786 pub fn scan_next(&mut self, live_files: &[LiveFile]) {
787 let last_file_id = self.files_done.last().unwrap();
788 let module_id = live_files[last_file_id.to_index()].module_id;
789
790 for (file_index, live_file) in live_files.iter().enumerate() {
791 if live_file.deps.contains(&module_id) {
792 let dep_id = LiveFileId::new(file_index);
793 if !self.files_done.iter().any( | v | *v == dep_id) {
794 self.files_todo.push(dep_id);
795 }
796 }
797 }
798 }
799}