conch_runtime_pshaw/env/
args.rs1use crate::env::SubEnvironment;
2use std::borrow::Cow;
3use std::collections::VecDeque;
4use std::sync::Arc;
5
6pub trait ArgumentsEnvironment {
8 type Arg: Clone;
10
11 fn name(&self) -> &Self::Arg;
13 fn arg(&self, idx: usize) -> Option<&Self::Arg>;
16 fn args_len(&self) -> usize;
18 fn args(&self) -> Cow<'_, [Self::Arg]>;
20}
21
22impl<'a, T: ?Sized + ArgumentsEnvironment> ArgumentsEnvironment for &'a T {
23 type Arg = T::Arg;
24
25 fn name(&self) -> &Self::Arg {
26 (**self).name()
27 }
28
29 fn arg(&self, idx: usize) -> Option<&Self::Arg> {
30 (**self).arg(idx)
31 }
32
33 fn args_len(&self) -> usize {
34 (**self).args_len()
35 }
36
37 fn args(&self) -> Cow<'_, [Self::Arg]> {
38 (**self).args()
39 }
40}
41
42impl<'a, T: ?Sized + ArgumentsEnvironment> ArgumentsEnvironment for &'a mut T {
43 type Arg = T::Arg;
44
45 fn name(&self) -> &Self::Arg {
46 (**self).name()
47 }
48
49 fn arg(&self, idx: usize) -> Option<&Self::Arg> {
50 (**self).arg(idx)
51 }
52
53 fn args_len(&self) -> usize {
54 (**self).args_len()
55 }
56
57 fn args(&self) -> Cow<'_, [Self::Arg]> {
58 (**self).args()
59 }
60}
61
62pub trait SetArgumentsEnvironment: ArgumentsEnvironment {
64 type Args;
66 fn set_args(&mut self, new_args: Self::Args) -> Self::Args;
68}
69
70impl<'a, T: ?Sized + SetArgumentsEnvironment> SetArgumentsEnvironment for &'a mut T {
71 type Args = T::Args;
72
73 fn set_args(&mut self, new_args: Self::Args) -> Self::Args {
74 (**self).set_args(new_args)
75 }
76}
77
78pub trait ShiftArgumentsEnvironment {
80 fn shift_args(&mut self, amt: usize);
86}
87
88impl<'a, T: ?Sized + ShiftArgumentsEnvironment> ShiftArgumentsEnvironment for &'a mut T {
89 fn shift_args(&mut self, amt: usize) {
90 (**self).shift_args(amt)
91 }
92}
93
94#[derive(Debug, PartialEq, Eq)]
96pub struct ArgsEnv<T> {
97 name: Arc<T>,
98 args: Arc<VecDeque<T>>,
99}
100
101impl<T> ArgsEnv<T> {
102 pub fn new() -> Self
105 where
106 T: From<String>,
107 {
108 let name = ::std::env::current_exe()
109 .ok()
110 .and_then(|path| {
111 path.file_name()
112 .and_then(|os_str| os_str.to_str().map(|s| s.to_owned()))
113 })
114 .unwrap_or_default();
115
116 Self::with_name(name.into())
117 }
118
119 pub fn with_name(name: T) -> Self {
122 ArgsEnv {
123 name: name.into(),
124 args: Arc::new(VecDeque::new()),
125 }
126 }
127
128 pub fn with_name_and_args<I: IntoIterator<Item = T>>(name: T, args: I) -> Self {
131 ArgsEnv {
132 name: name.into(),
133 args: Arc::new(args.into_iter().collect()),
134 }
135 }
136}
137
138impl<T: From<String>> Default for ArgsEnv<T> {
139 fn default() -> Self {
140 Self::new()
141 }
142}
143
144impl<T> Clone for ArgsEnv<T> {
145 fn clone(&self) -> Self {
146 ArgsEnv {
147 name: self.name.clone(),
148 args: self.args.clone(),
149 }
150 }
151}
152
153impl<T> SubEnvironment for ArgsEnv<T> {
154 fn sub_env(&self) -> Self {
155 self.clone()
156 }
157}
158
159impl<T: Clone> ArgumentsEnvironment for ArgsEnv<T> {
160 type Arg = T;
161
162 fn name(&self) -> &Self::Arg {
163 &self.name
164 }
165
166 fn arg(&self, idx: usize) -> Option<&Self::Arg> {
167 if idx == 0 {
168 Some(self.name())
169 } else {
170 self.args.get(idx - 1)
171 }
172 }
173
174 fn args_len(&self) -> usize {
175 self.args.len()
176 }
177
178 fn args(&self) -> Cow<'_, [Self::Arg]> {
179 if let (first, []) = self.args.as_slices() {
180 Cow::Borrowed(first)
181 } else {
182 Cow::Owned(self.args.iter().cloned().collect())
183 }
184 }
185}
186
187impl<T: Clone> SetArgumentsEnvironment for ArgsEnv<T> {
188 type Args = Arc<VecDeque<T>>;
189
190 fn set_args(&mut self, new_args: Self::Args) -> Self::Args {
191 ::std::mem::replace(&mut self.args, new_args)
192 }
193}
194
195impl<T: Clone> ShiftArgumentsEnvironment for ArgsEnv<T> {
196 fn shift_args(&mut self, amt: usize) {
197 if amt == 0 {
198 return;
199 }
200
201 if amt >= self.args.len() {
202 if let Some(args) = Arc::get_mut(&mut self.args) {
204 args.clear();
205 return;
206 }
207
208 self.args = Arc::new(VecDeque::new());
210 }
211
212 if let Some(args) = Arc::get_mut(&mut self.args) {
213 args.drain(0..amt);
214 return;
215 }
216
217 self.args = Arc::new(self.args.iter().skip(amt).cloned().collect());
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use crate::env::SubEnvironment;
226 use crate::RefCounted;
227
228 #[test]
229 fn test_name() {
230 let name = "shell";
231 let env = ArgsEnv::with_name(name.to_owned());
232 assert_eq!(env.name(), name);
233 assert_eq!(env.arg(0).unwrap(), name);
234
235 let env = env.sub_env();
237 assert_eq!(env.name(), name);
238 assert_eq!(env.arg(0).unwrap(), name);
239 }
240
241 #[test]
242 fn test_sub_env_no_needless_clone() {
243 let name = "shell";
244 let args = vec!["one", "two", "three"];
245 let env = ArgsEnv::with_name_and_args(name, args.clone());
246
247 let mut env = env.sub_env();
248 assert!(env.name.get_mut().is_none());
249 assert!(env.args.get_mut().is_none());
250 }
251
252 #[test]
253 fn test_args() {
254 let name = "shell";
255 let args = vec!["one", "two", "three"];
256 let env = ArgsEnv::with_name_and_args(name, args.clone());
257
258 assert_eq!(env.args_len(), args.len());
259
260 assert_eq!(env.arg(0), Some(&name));
261 assert_eq!(env.arg(1), Some(&args[0]));
262 assert_eq!(env.arg(2), Some(&args[1]));
263 assert_eq!(env.arg(3), Some(&args[2]));
264 assert_eq!(env.arg(4), None);
265
266 assert_eq!(env.args(), args);
267 }
268
269 #[test]
270 fn test_set_args() {
271 let args_old = vec!["1", "2", "3"];
272 let mut env = ArgsEnv::with_name_and_args("shell", args_old.clone());
273
274 {
275 let args_new = vec!["4", "5", "6"];
276 assert_eq!(env.args(), args_old);
277 let prev = env.set_args(VecDeque::from(args_new.clone()).into());
278 assert_eq!(*prev, args_old);
279 assert_eq!(env.args(), args_new);
280
281 env.set_args(prev);
282 }
283
284 assert_eq!(env.args(), args_old);
285 }
286
287 #[test]
288 fn test_shift_args() {
289 let mut env = ArgsEnv::with_name_and_args("shell", vec!["1", "2", "3", "4", "5", "6"]);
290 let _copy = env.sub_env();
291
292 env.shift_args(0);
293 assert_eq!(env.args(), vec!("1", "2", "3", "4", "5", "6"));
294 assert!(env.name.get_mut().is_none()); env.shift_args(1);
297 assert_eq!(env.args(), vec!("2", "3", "4", "5", "6"));
298
299 env.shift_args(1);
300 assert_eq!(env.args(), vec!("3", "4", "5", "6"));
301
302 env.shift_args(2);
303 assert_eq!(env.args(), vec!("5", "6"));
304
305 env.shift_args(100);
306 assert_eq!(env.args(), Vec::<&str>::new());
307 }
308}