From b30e701c7e0d4ded6ca4cf7b84073110711dba1f Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Wed, 14 Apr 2021 17:53:37 -0600 Subject: give targets an encapsulated set like macros have --- src/makefile/target.rs | 81 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) (limited to 'src/makefile/target.rs') diff --git a/src/makefile/target.rs b/src/makefile/target.rs index 506bde8..5de280d 100644 --- a/src/makefile/target.rs +++ b/src/makefile/target.rs @@ -1,6 +1,8 @@ -use std::cell::Cell; +use std::cell::{Cell, RefCell}; +use std::collections::HashMap; use std::fmt; use std::fs::metadata; +use std::rc::Rc; use std::time::SystemTime; use eyre::{Result, WrapErr}; @@ -19,6 +21,17 @@ pub struct Target { } impl Target { + pub fn extend(&mut self, other: Target) { + assert_eq!(&self.name, &other.name); + self.prerequisites.extend(other.prerequisites); + assert!(self.commands.is_empty() || other.commands.is_empty()); + self.commands.extend(other.commands); + assert!(self.stem.is_none() || other.stem.is_none()); + self.stem = self.stem.take().or(other.stem); + let already_updated = self.already_updated.get() || other.already_updated.get(); + self.already_updated.set(already_updated); + } + fn modified_time(&self) -> Option { metadata(&self.name) .and_then(|metadata| metadata.modified()) @@ -55,7 +68,7 @@ impl Target { .unwrap_or(false) }); log::trace!( - "{:>50} exists: {}, newer than dependencies: {}", + "{:} exists: {}, newer than dependencies: {}", self.name, exists, newer_than_all_dependencies @@ -64,6 +77,7 @@ impl Target { } pub fn update(&self, file: &Makefile) -> Result<()> { + log::info!("{}: {:?}", &self.name, &self.prerequisites); for prereq in &self.prerequisites { file.update_target(prereq) .wrap_err_with(|| format!("as a dependency for target {}", self.name))?; @@ -101,3 +115,66 @@ impl fmt::Display for Target { Ok(()) } } + +// for targets that won't change out from under us (don't need refcelling) +#[derive(Clone, Default)] +pub struct StaticTargetSet { + data: HashMap, +} + +impl StaticTargetSet { + pub fn get(&self, name: &str) -> Option<&Target> { + self.data.get(name) + } + + pub fn put(&mut self, target: Target) { + if target.name == ".SUFFIXES" && target.prerequisites.is_empty() { + self.data.remove(&target.name); + } + if let Some(existing_target) = self.data.get_mut(&target.name) { + existing_target.extend(target); + } else { + self.data.insert(target.name.clone(), target); + } + } +} + +impl Into> for StaticTargetSet { + fn into(self) -> HashMap { + self.data + } +} + +// for targets that might become updated and so need refcelling +#[derive(Clone, Default)] +pub struct DynamicTargetSet { + data: HashMap>>, +} + +impl DynamicTargetSet { + pub fn get(&self, name: &str) -> Option>> { + self.data.get(name).map(|x| Rc::clone(x)) + } + + pub fn put(&mut self, target: Target) { + if let Some(existing_target) = self.data.get_mut(&target.name) { + existing_target.borrow_mut().extend(target); + } else { + self.data + .insert(target.name.clone(), Rc::new(RefCell::new(target))); + } + } + + pub fn has(&self, name: &str) -> bool { + self.data.contains_key(name) + } +} + +impl fmt::Display for DynamicTargetSet { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for target in self.data.values() { + writeln!(f, "{}", target.borrow())?; + } + Ok(()) + } +} -- cgit v1.2.3