1use std::{
38 env,
39 ffi::{OsStr, OsString},
40 marker::PhantomData,
41 path::{Path, PathBuf},
42};
43
44use anyhow::Ok;
45
46#[derive(Debug, Clone, Copy, Default)]
47pub struct ShellPromptState;
48
49impl ShellPromptState {
50 pub fn get_current_dir(
51 provided_current_dir: Option<PathBuf>,
52 ) -> anyhow::Result<CurrentDirState> {
53 let current_dir = if let Some(current_dir) = provided_current_dir {
54 current_dir
55 } else {
56 env::current_dir()?
57 };
58 Ok(CurrentDirState { current_dir })
59 }
60}
61
62#[derive(Debug, Clone)]
63pub struct CurrentDirState {
64 current_dir: PathBuf,
65}
66
67impl CurrentDirState {
68 pub fn match_rcs<RC>(
69 self,
70 match_rcs_cb: impl Fn(&Path) -> anyhow::Result<Vec<RC>>,
71 ) -> anyhow::Result<MatchRcs<RC>> {
72 let rcs = match_rcs_cb(&self.current_dir)?;
73 let match_rcs = if rcs.is_empty() {
74 MatchRcs::NoRcs(NoRcsState {
75 phantom: PhantomData,
76 })
77 } else {
78 MatchRcs::Rcs(RcsState { rcs })
79 };
80 Ok(match_rcs)
81 }
82}
83
84#[derive(Debug, Clone)]
85pub enum MatchRcs<RC> {
86 NoRcs(NoRcsState),
87 Rcs(RcsState<RC>),
88}
89
90#[derive(Debug, Clone)]
91pub struct NoRcsState {
92 phantom: PhantomData<()>,
93}
94
95impl NoRcsState {
96 pub fn get_env_state_var(
97 self,
98 env_state_var_key: impl AsRef<OsStr>,
99 ) -> Option<ReadyForFullResetState> {
100 get_env_state_var(env_state_var_key).map(|env_state_var_value| ReadyForFullResetState {
101 env_state_var_value,
102 })
103 }
104}
105
106#[derive(Debug, Clone)]
107pub struct ReadyForFullResetState {
108 env_state_var_value: OsString,
109}
110
111impl ReadyForFullResetState {
112 pub fn reset_env_vars(
113 self,
114 reset_env_vars_cb: impl Fn(OsString) -> anyhow::Result<()>,
115 ) -> anyhow::Result<()> {
116 reset_env_vars_cb(self.env_state_var_value)?;
117 Ok(())
118 }
119}
120
121#[derive(Debug, Clone)]
122pub struct RcsState<RC> {
123 rcs: Vec<RC>,
124}
125
126impl<RC> RcsState<RC> {
127 pub fn get_env_state_var(self, env_state_var_key: impl AsRef<OsStr>) -> GetEnvStateVar<RC> {
128 let rcs = self.rcs;
129 if let Some(env_state_var_value) = get_env_state_var(env_state_var_key) {
130 GetEnvStateVar::EnvStateVar(EnvStateVarState {
131 rcs,
132 env_state_var_value,
133 })
134 } else {
135 GetEnvStateVar::NoEnvStateVar(NoEnvStateVarState { rcs })
136 }
137 }
138}
139
140#[derive(Debug, Clone)]
141pub enum GetEnvStateVar<RC> {
142 NoEnvStateVar(NoEnvStateVarState<RC>),
143 EnvStateVar(EnvStateVarState<RC>),
144}
145
146#[derive(Debug, Clone)]
147pub struct NoEnvStateVarState<RC> {
148 rcs: Vec<RC>,
149}
150
151impl<RC> NoEnvStateVarState<RC> {
152 pub fn set_new_env_state_var(
153 self,
154 set_new_env_state_var_cb: impl Fn(Vec<RC>) -> anyhow::Result<()>,
155 ) -> anyhow::Result<()> {
156 set_new_env_state_var_cb(self.rcs)?;
157 Ok(())
158 }
159}
160
161#[derive(Debug, Clone)]
162pub struct EnvStateVarState<RC> {
163 rcs: Vec<RC>,
164 env_state_var_value: OsString,
165}
166
167impl<RC> EnvStateVarState<RC> {
168 pub fn reset_and_set_new_env_state_var<T>(
169 self,
170 reset_env_vars_cb: impl Fn(Vec<RC>, OsString) -> anyhow::Result<T>,
171 set_new_env_state_var_cb: impl Fn(T) -> anyhow::Result<()>,
172 ) -> anyhow::Result<()> {
173 let state = reset_env_vars_cb(self.rcs, self.env_state_var_value)?;
174 set_new_env_state_var_cb(state)?;
175 Ok(())
176 }
177}
178
179fn get_env_state_var(env_state_var_key: impl AsRef<OsStr>) -> Option<OsString> {
180 env::var_os(env_state_var_key)
181}