From be4b3ead9704f28c1e7e327f1f081716a73a4bf1 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 23 Jun 2022 14:46:53 +1000 Subject: [PATCH] Add new fn `get_desired_targets` & newtype `DesiredTargets` so that if `opts.targets` is `None`, the future returned by `detect_targets` can be run in parallel by using `tokio::spawn` with other async code in `entry`, such as `fetch_crate_cratesio`. Signed-off-by: Jiahao XU --- src/target.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/target.rs b/src/target.rs index ac6b6be9..4c3eb5e6 100644 --- a/src/target.rs +++ b/src/target.rs @@ -1,10 +1,68 @@ use std::io::{BufRead, Cursor}; use std::process::Output; +use std::sync::Arc; + use tokio::process::Command; +use tokio::sync::OnceCell; /// Compiled target triple, used as default for binary fetching pub const TARGET: &str = env!("TARGET"); +#[derive(Debug)] +enum DesiredTargetsInner { + AutoDetect(Arc>>), + Initialized(Vec), +} + +#[derive(Debug)] +pub struct DesiredTargets(DesiredTargetsInner); + +impl DesiredTargets { + fn initialized(targets: Vec) -> Self { + Self(DesiredTargetsInner::Initialized(targets)) + } + + fn auto_detect() -> Self { + let arc = Arc::new(OnceCell::new()); + + let once_cell = arc.clone(); + tokio::spawn(async move { + once_cell.get_or_init(detect_targets).await; + }); + + Self(DesiredTargetsInner::AutoDetect(arc)) + } + + pub async fn get(&self) -> &[String] { + use DesiredTargetsInner::*; + + match &self.0 { + Initialized(targets) => targets, + + // This will mostly just wait for the spawned task, + // on rare occausion though, it will poll the future + // returned by `detect_targets`. + AutoDetect(once_cell) => once_cell.get_or_init(detect_targets).await, + } + } +} + +/// If opts_targets is `Some`, then it will be used. +/// Otherwise, call `detect_targets` using `tokio::spawn` to detect targets. +/// +/// Since `detect_targets` internally spawns a process and wait for it, +/// it's pretty costy. +/// +/// Calling it through `tokio::spawn` would enable other tasks, such as +/// fetching the crate tarballs, to be executed concurrently. +pub fn get_desired_targets(opts_targets: &Option) -> DesiredTargets { + if let Some(targets) = opts_targets.as_ref() { + DesiredTargets::initialized(targets.split(',').map(|t| t.to_string()).collect()) + } else { + DesiredTargets::auto_detect() + } +} + /// Detect the targets supported at runtime, /// which might be different from `TARGET` which is detected /// at compile-time.