mirror of
https://github.com/Zenithsiz/zbuild.git
synced 2026-02-03 22:23:53 +00:00
139 lines
3.4 KiB
Rust
139 lines
3.4 KiB
Rust
//! Build locks
|
|
|
|
// Imports
|
|
use {
|
|
crate::{rules::Target, util::CowStr, AppError},
|
|
std::{assert_matches::assert_matches, collections::HashMap, sync::Arc, time::SystemTime},
|
|
tokio::sync::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard, RwLock},
|
|
};
|
|
|
|
/// Build result
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct BuildResult {
|
|
/// Build time
|
|
pub build_time: SystemTime,
|
|
|
|
/// If this task was the one who built it
|
|
// TODO: Rename to something here
|
|
pub built_here: bool,
|
|
|
|
/// If built from a rule
|
|
pub built: bool,
|
|
}
|
|
|
|
/// Build state
|
|
#[derive(Clone, Debug)]
|
|
pub struct BuildState<'s> {
|
|
/// Targets' result
|
|
targets_res: HashMap<Target<'s, CowStr<'s>>, Result<BuildResult, Arc<AppError>>>,
|
|
}
|
|
|
|
/// Build lock
|
|
#[derive(Clone, Debug)]
|
|
pub struct BuildLock<'s> {
|
|
/// State
|
|
state: Arc<RwLock<BuildState<'s>>>,
|
|
}
|
|
|
|
impl<'s> BuildLock<'s> {
|
|
/// Creates a new build lock
|
|
pub fn new() -> Self {
|
|
Self {
|
|
state: Arc::new(RwLock::new(BuildState {
|
|
targets_res: HashMap::new(),
|
|
})),
|
|
}
|
|
}
|
|
|
|
/// Locks the build lock for building
|
|
pub async fn lock_build(&self) -> BuildLockBuildGuard<'s> {
|
|
BuildLockBuildGuard {
|
|
state: Arc::clone(&self.state).write_owned().await,
|
|
}
|
|
}
|
|
|
|
/// Locks the build lock as a dependency
|
|
pub async fn lock_dep(&self) -> BuildLockDepGuard<'s> {
|
|
BuildLockDepGuard {
|
|
state: Arc::clone(&self.state).read_owned().await,
|
|
}
|
|
}
|
|
|
|
/// Retrieves all targets' result by consuming the lock
|
|
pub fn into_res(self) -> Vec<(Target<'s, CowStr<'s>>, Result<BuildResult, AppError>)> {
|
|
// TODO: Not panic here
|
|
Arc::try_unwrap(self.state)
|
|
.expect("Leftover references when unwrapping build lock")
|
|
.into_inner()
|
|
.targets_res
|
|
.into_iter()
|
|
.map(|(target, build)| (target, build.map_err(AppError::Shared)))
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
/// Build lock build guard
|
|
#[derive(Debug)]
|
|
pub struct BuildLockBuildGuard<'s> {
|
|
/// State
|
|
state: OwnedRwLockWriteGuard<BuildState<'s>>,
|
|
}
|
|
|
|
impl<'s> BuildLockBuildGuard<'s> {
|
|
/// Retrieves a target's result
|
|
///
|
|
/// Waits for any builders to finish
|
|
pub fn res(&self, target: &Target<'s, CowStr<'s>>) -> Option<Result<BuildResult, AppError>> {
|
|
self.state
|
|
.targets_res
|
|
.get(target)
|
|
.cloned()
|
|
.map(|res| res.map_err(AppError::Shared))
|
|
}
|
|
|
|
/// Downgrades this build lock into a dependency lock
|
|
pub fn into_dep(self) -> BuildLockDepGuard<'s> {
|
|
BuildLockDepGuard {
|
|
state: self.state.downgrade(),
|
|
}
|
|
}
|
|
|
|
/// Resets this build.
|
|
pub fn reset(&mut self, target: &Target<'s, CowStr<'s>>) {
|
|
// Note: We don't care about the previous build result
|
|
let _: Option<Result<BuildResult, _>> = self.state.targets_res.remove(target);
|
|
}
|
|
|
|
/// Finishes a build
|
|
pub fn finish(
|
|
&mut self,
|
|
target: &Target<'s, CowStr<'s>>,
|
|
res: Result<BuildResult, AppError>,
|
|
) -> Result<BuildResult, AppError> {
|
|
let res = res.map_err(Arc::new);
|
|
let prev_res = self.state.targets_res.insert(target.clone(), res.clone());
|
|
assert_matches!(prev_res, None, "Build was already finished");
|
|
res.map_err(AppError::Shared)
|
|
}
|
|
}
|
|
|
|
/// Build lock dependency guard
|
|
#[derive(Debug)]
|
|
pub struct BuildLockDepGuard<'s> {
|
|
/// State
|
|
state: OwnedRwLockReadGuard<BuildState<'s>>,
|
|
}
|
|
|
|
impl<'s> BuildLockDepGuard<'s> {
|
|
/// Retrieves a target's result
|
|
///
|
|
/// Waits for any builders to finish
|
|
pub fn res(&self, target: &Target<'s, CowStr<'s>>) -> Option<Result<BuildResult, AppError>> {
|
|
self.state
|
|
.targets_res
|
|
.get(target)
|
|
.cloned()
|
|
.map(|res| res.map_err(AppError::Shared))
|
|
}
|
|
}
|