1#![feature(arbitrary_self_types)]
2#![feature(arbitrary_self_types_pointers)]
3
4mod command_line;
5mod custom;
6mod dotenv;
7mod filter;
8
9use std::{env, sync::Mutex};
10
11use anyhow::Result;
12use turbo_rcstr::RcStr;
13use turbo_tasks::{FxIndexMap, Vc};
14
15pub use self::{
16 command_line::CommandLineProcessEnv, custom::CustomProcessEnv, dotenv::DotenvProcessEnv,
17 filter::FilterProcessEnv,
18};
19
20#[turbo_tasks::value(transparent)]
21pub struct EnvMap(#[turbo_tasks(trace_ignore)] FxIndexMap<RcStr, RcStr>);
22
23#[turbo_tasks::value_impl]
24impl EnvMap {
25 #[turbo_tasks::function]
26 pub fn empty() -> Vc<Self> {
27 EnvMap(FxIndexMap::default()).cell()
28 }
29}
30
31#[turbo_tasks::value_impl]
32impl ProcessEnv for EnvMap {
33 #[turbo_tasks::function]
34 fn read_all(self: Vc<Self>) -> Vc<EnvMap> {
35 self
36 }
37
38 #[turbo_tasks::function]
39 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
40 case_insensitive_read(self, name)
41 }
42}
43
44#[turbo_tasks::value_trait]
45pub trait ProcessEnv {
46 fn read_all(self: Vc<Self>) -> Vc<EnvMap>;
53
54 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
56 case_insensitive_read(self.read_all(), name)
57 }
58}
59
60pub fn sorted_env_vars() -> FxIndexMap<RcStr, RcStr> {
61 let mut vars = env::vars()
62 .map(|(k, v)| (k.into(), v.into()))
63 .collect::<FxIndexMap<_, _>>();
64 vars.sort_keys();
65 vars
66}
67
68#[turbo_tasks::function]
69pub async fn case_insensitive_read(map: Vc<EnvMap>, name: RcStr) -> Result<Vc<Option<RcStr>>> {
70 Ok(Vc::cell(
71 to_uppercase_map(map)
72 .await?
73 .get(&RcStr::from(name.to_uppercase()))
74 .cloned(),
75 ))
76}
77
78#[turbo_tasks::function]
79async fn to_uppercase_map(map: Vc<EnvMap>) -> Result<Vc<EnvMap>> {
80 let map = &*map.await?;
81 let mut new = FxIndexMap::with_capacity_and_hasher(map.len(), Default::default());
82 for (k, v) in map {
83 new.insert(k.to_uppercase().into(), v.clone());
84 }
85 Ok(Vc::cell(new))
86}
87
88pub static GLOBAL_ENV_LOCK: Mutex<()> = Mutex::new(());
89
90pub fn register() {
91 turbo_tasks::register();
92 include!(concat!(env!("OUT_DIR"), "/register.rs"));
93}