]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys_common/process.rs
Rollup merge of #77900 - Thomasdezeeuw:fdatasync, r=dtolnay
[rust.git] / library / std / src / sys_common / process.rs
1 #![allow(dead_code)]
2 #![unstable(feature = "process_internals", issue = "none")]
3
4 use crate::collections::BTreeMap;
5 use crate::env;
6 use crate::ffi::{OsStr, OsString};
7 use crate::sys::process::EnvKey;
8
9 // Stores a set of changes to an environment
10 #[derive(Clone, Debug)]
11 pub struct CommandEnv {
12     clear: bool,
13     saw_path: bool,
14     vars: BTreeMap<EnvKey, Option<OsString>>,
15 }
16
17 impl Default for CommandEnv {
18     fn default() -> Self {
19         CommandEnv { clear: false, saw_path: false, vars: Default::default() }
20     }
21 }
22
23 impl CommandEnv {
24     // Capture the current environment with these changes applied
25     pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
26         let mut result = BTreeMap::<EnvKey, OsString>::new();
27         if !self.clear {
28             for (k, v) in env::vars_os() {
29                 result.insert(k.into(), v);
30             }
31         }
32         for (k, maybe_v) in &self.vars {
33             if let &Some(ref v) = maybe_v {
34                 result.insert(k.clone(), v.clone());
35             } else {
36                 result.remove(k);
37             }
38         }
39         result
40     }
41
42     // Apply these changes directly to the current environment
43     pub fn apply(&self) {
44         if self.clear {
45             for (k, _) in env::vars_os() {
46                 env::remove_var(k);
47             }
48         }
49         for (key, maybe_val) in self.vars.iter() {
50             if let Some(ref val) = maybe_val {
51                 env::set_var(key, val);
52             } else {
53                 env::remove_var(key);
54             }
55         }
56     }
57
58     pub fn is_unchanged(&self) -> bool {
59         !self.clear && self.vars.is_empty()
60     }
61
62     pub fn capture_if_changed(&self) -> Option<BTreeMap<EnvKey, OsString>> {
63         if self.is_unchanged() { None } else { Some(self.capture()) }
64     }
65
66     // The following functions build up changes
67     pub fn set(&mut self, key: &OsStr, value: &OsStr) {
68         self.maybe_saw_path(&key);
69         self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
70     }
71
72     pub fn remove(&mut self, key: &OsStr) {
73         self.maybe_saw_path(&key);
74         if self.clear {
75             self.vars.remove(key);
76         } else {
77             self.vars.insert(key.to_owned().into(), None);
78         }
79     }
80
81     pub fn clear(&mut self) {
82         self.clear = true;
83         self.vars.clear();
84     }
85
86     pub fn have_changed_path(&self) -> bool {
87         self.saw_path || self.clear
88     }
89
90     fn maybe_saw_path(&mut self, key: &OsStr) {
91         if !self.saw_path && key == "PATH" {
92             self.saw_path = true;
93         }
94     }
95
96     pub fn iter(&self) -> CommandEnvs<'_> {
97         let iter = self.vars.iter();
98         CommandEnvs { iter }
99     }
100 }
101
102 /// An iterator over the command environment variables.
103 ///
104 /// This struct is created by
105 /// [`Command::get_envs`][crate::process::Command::get_envs]. See its
106 /// documentation for more.
107 #[unstable(feature = "command_access", issue = "44434")]
108 #[derive(Debug)]
109 pub struct CommandEnvs<'a> {
110     iter: crate::collections::btree_map::Iter<'a, EnvKey, Option<OsString>>,
111 }
112
113 #[unstable(feature = "command_access", issue = "44434")]
114 impl<'a> Iterator for CommandEnvs<'a> {
115     type Item = (&'a OsStr, Option<&'a OsStr>);
116     fn next(&mut self) -> Option<Self::Item> {
117         self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref()))
118     }
119     fn size_hint(&self) -> (usize, Option<usize>) {
120         self.iter.size_hint()
121     }
122 }
123
124 #[unstable(feature = "command_access", issue = "44434")]
125 impl<'a> ExactSizeIterator for CommandEnvs<'a> {
126     fn len(&self) -> usize {
127         self.iter.len()
128     }
129     fn is_empty(&self) -> bool {
130         self.iter.is_empty()
131     }
132 }