turtle-build 0.5.13

Ninja-compatible build system for high-level programming languages
Documentation
use super::{file_cache::FileCache, options::RunOptions};
use crate::{
    BuildError,
    build_graph::BuildGraph,
    context::Context,
    ir::{BuildId, Config, DynamicConfig, Pool},
};
use alloc::sync::Arc;
use core::pin::Pin;
use futures::future::Shared;
use rapidhash::{RapidHashMap, fast::RandomState};
use scc::HashIndex;
use tokio::sync::{Mutex, OnceCell, Semaphore, SemaphorePermit};

type BuildFuture = Shared<Pin<Box<dyn Future<Output = Result<bool, BuildError>> + Send>>>;

pub struct RunContext {
    build: Arc<Context>,
    config: Arc<Config>,
    build_futures: HashIndex<BuildId, BuildFuture, RandomState>,
    build_graph: Mutex<BuildGraph>,
    dynamic_configs: RapidHashMap<Arc<str>, OnceCell<DynamicConfig>>,
    file_cache: FileCache,
    header_inputs: RapidHashMap<BuildId, Vec<Arc<str>>>,
    pools: RapidHashMap<Arc<str>, Semaphore>,
    options: RunOptions,
}

impl RunContext {
    pub fn new(
        build: Arc<Context>,
        config: Arc<Config>,
        build_graph: BuildGraph,
        header_inputs: RapidHashMap<BuildId, Vec<Arc<str>>>,
        options: RunOptions,
    ) -> Self {
        Self {
            file_cache: FileCache::new(build.file_system().clone(), config.outputs().len()),
            build,
            build_graph: build_graph.into(),
            dynamic_configs: config
                .outputs()
                .values()
                .filter_map(|build| Some((build.dynamic_module()?.clone(), Default::default())))
                .collect(),
            header_inputs,
            pools: config
                .pools()
                .iter()
                .map(|(name, depth)| {
                    (
                        name.clone(),
                        Semaphore::new(depth.get().min(Semaphore::MAX_PERMITS)),
                    )
                })
                .collect(),
            build_futures: HashIndex::with_capacity_and_hasher(
                config.outputs().len(),
                Default::default(),
            ),
            config,
            options,
        }
    }

    pub fn build(&self) -> &Context {
        &self.build
    }

    pub fn config(&self) -> &Config {
        &self.config
    }

    pub const fn build_futures(&self) -> &HashIndex<BuildId, BuildFuture, RandomState> {
        &self.build_futures
    }

    pub const fn build_graph(&self) -> &Mutex<BuildGraph> {
        &self.build_graph
    }

    pub fn dynamic_config(&self, path: &str) -> &OnceCell<DynamicConfig> {
        &self.dynamic_configs[path]
    }

    pub const fn file_cache(&self) -> &FileCache {
        &self.file_cache
    }

    pub fn header_inputs(&self, id: BuildId) -> &[Arc<str>] {
        self.header_inputs.get(&id).map_or_default(Vec::as_slice)
    }

    pub async fn pool(
        &self,
        pool: Option<&Pool>,
    ) -> Result<Option<SemaphorePermit<'_>>, BuildError> {
        let Some(Pool::Limited(name)) = pool else {
            return Ok(None);
        };

        Ok(Some(self.pools[name].acquire().await?))
    }

    pub const fn options(&self) -> &RunOptions {
        &self.options
    }
}