rust_env/lib.rs
1//!# rust-env
2//!
3//! rust-env is a package to make managing env
4//! a lot easier in rust
5
6use std::env::vars;
7use std::fs::{read_to_string, write};
8
9#[allow(dead_code)]
10struct SPair(String, String);
11
12/// Using this trait you can extend the behavior
13/// of Env struct
14/// # Example
15/// ```
16/// use rust_env::{EnvFrame, Hash};
17///
18/// struct MyEnv {
19/// data: Vec<Hash>,
20/// global: Vec<Hash>,
21/// path: String
22/// }
23///
24/// impl EnvFrame for MyEnv {
25/// //write your code
26/// }
27///```
28
29pub trait EnvFrame {
30 fn marshal(val: Vec<Hash>) -> String;
31 fn parse(content: String) -> Vec<Hash>;
32 fn new(name: String) -> Env;
33 fn get(&self, k: &str) -> Wrapper;
34 fn get_debug(self) -> Vec<Hash>;
35 fn set(&mut self, k: &str, v: Hash);
36 fn debug(self);
37 fn upload(path: &str, pairs: Vec<Hash>) -> Env;
38 fn global_env(&mut self);
39 fn get_local(&self, k: &str) -> Wrapper;
40 fn get_global(&self, k: &str) -> Wrapper;
41}
42
43#[allow(non_snake_case)]
44#[allow(dead_code)]
45pub fn Str(a: &str, b: &str) -> Hash {
46 Hash::Str(a.to_string(), b.to_string())
47}
48
49#[allow(non_snake_case)]
50#[allow(dead_code)]
51pub fn Vct(a: &str, v: Vec<&str>) -> Hash {
52 let mut v_: Vec<String> = vec![];
53
54 for e in v.into_iter() {
55 v_.push(e.to_string());
56 }
57
58 Hash::Vec(a.to_string(), v_)
59}
60
61fn get_d(d: Vec<Hash>, key: String) -> Wrapper {
62 for h in d.into_iter() {
63
64 match h {
65 Hash ::Str(k, v)
66 if k == key => {
67 return Wrapper::Str(v)
68 },
69 Hash ::Vec(k, v)
70 if k == key => {
71 return Wrapper::Vec(v)
72 },
73 _ => continue
74 }
75 }
76
77 return Wrapper::Empty;
78}
79
80#[derive(Debug, Clone)]
81/// This enum mainly rap two type of data
82/// String and `Vec<String>`
83/// See docs of `struct Env` of this package for learn more
84pub enum Wrapper {
85 Str(String),
86 Vec(Vec<String>),
87 Empty
88}
89
90/// This enum is mainly A key-value pair
91/// `String` and `Vec<String>`
92/// See docs of `struct Env` of this package for learn more
93/// Here's The enum looks like
94/// # Example
95/// ```
96/// pub enum Hash {
97/// Str(String, String),
98/// Vec(String, Vec<String>),
99/// Placeholder
100/// }
101///```
102
103#[derive(Debug, Clone)]
104pub enum Hash {
105 Str(String, String),
106 Vec(String, Vec<String>),
107 Placeholder
108}
109
110pub struct Env {
111 data: Vec<Hash>,
112 global: Vec<Hash>,
113 path: String
114}
115
116impl Env {
117 #[allow(dead_code)]
118 ///It parse a env string
119 ///Here's a example
120 /// # Example
121 ///```
122 /// use rust_env::{Env, Hash};
123 ///
124 /// let env: Vec<Hash> = Env::parse("PORT=6778\nHOST=127.0.0.1");
125 /// ```
126 pub fn parse(content: &str) -> Vec<Hash> {
127 let s = content.to_string();
128 let lines = s.split("\n").collect::<Vec<&str>>();
129 let mut res: Vec<Hash> = Vec::new();
130
131 for _lines in lines.iter() {
132 let pair_ = _lines.split("=").collect::<Vec<&str>>();
133 let raw_value = pair_[1];
134
135 #[allow(unused_assignments)]
136 let mut value: Hash = Hash::Placeholder;
137
138 match raw_value.find(";") {
139 Some(_) => {
140 let raw = raw_value.split(";").collect::<Vec<&str>>();
141 let mut str_vec: Vec<String> = Vec::new();
142
143 for r in raw.into_iter() {
144 str_vec.push(r.to_string());
145 }
146 value = Hash::Vec(
147 pair_[0].to_string(),
148 str_vec)
149 }
150 None => {
151 value = Hash::Str(pair_[0].to_string(),
152 pair_[1].to_string())
153 }
154 }
155
156 res.push(value);
157 }
158
159 return res;
160 }
161
162 /// that will Marshal a piece of data like this
163 /// # Example
164 /// ```
165 /// use rust_env::{Env, Hash, Str};
166 ///
167 /// let d: Vec<Hash> = vec![
168 /// Str("PORT", "6779")
169 /// ];
170 ///
171 /// assert_eq!(Env::marshal(d), "PORT=6779".to_string())
172 /// ```
173 pub fn marshal(val: Vec<Hash>) -> String {
174 let mut hash = String::new();
175
176 for v in val.into_iter() {
177 hash.push_str(match v.clone() {
178 Hash::Str(a, _) => a,
179 Hash::Vec(a, _) => a,
180 _ => String::new()
181 }.as_str());
182 hash.push('=');
183 hash.push_str(match v.clone() {
184 Hash::Str(_, b) => b,
185 Hash::Vec(_, v) => {
186 let mut s = String::new();
187
188 for v in v.clone() {
189 s.push_str(v.as_str());
190 s.push(';')
191 }
192
193 s
194 },
195 Hash::Placeholder=> String::new()
196 }.as_str());
197 }
198
199 return hash;
200 }
201
202 /// New function create a new Env;
203 ///
204 /// # Example
205 /// ```
206 /// use rust_env::Env;
207 /// let env = Env::new("./.env");
208 ///
209 /// //debug
210 /// env.debug();
211 #[allow(dead_code)]
212 pub fn new(name: &str) -> Env {
213 let content = read_to_string(name.clone()).expect("Invalid path");
214 let local = Env::parse(content.as_str());
215
216 Self {
217 data: local,
218 path: name.to_string().clone(),
219 global: Vec::new()
220 }
221 }
222
223 #[allow(dead_code)]
224 /// It will return the entire env
225 /// local and global
226 /// # Example
227 /// ```
228 /// use rust_env::{Env, Hash};
229 ///
230 /// let env = Env::new("./.env");
231 /// let e: Vec<Hash> = env.get_debug();
232 /// ```
233
234 pub fn get_debug(self) -> Vec<Hash> { return self.data.clone() }
235 #[allow(dead_code)]
236
237 /// it will set a prop to your local env
238 /// Here's an example
239 /// # Example
240 /// ```
241 /// use rust_env::{Env, Str, Wrapper};
242 ///
243 /// let mut env = Env::new("./.env");
244 /// env.set(Str("PORT", "6778"));
245 /// ```
246 pub fn set(&mut self, h: Hash) {
247
248 self.data.push(h.clone());
249 let hash = Env::marshal(vec![h]);
250
251 write(&self.path, hash).expect(
252 "Invalid path to write")
253 }
254
255 /// It's similar to the `set` function
256 /// But you'll put raw string as parameter
257 /// # Example
258 /// ```
259 /// use rust_env::Env;
260 /// use rust_env::Str;
261 ///
262 /// let mut env = Env::new("./.env");
263 /// //Using set function
264 /// env.set(Str("PORT", "6778"));
265 ///
266 /// //Using raw function
267 /// env.raw("PORT=6778");
268
269 pub fn raw(&mut self, e: &str) {
270 let mut h = Env::parse(e);
271 self.data.append(&mut h);
272
273 }
274
275
276 #[allow(dead_code)]
277 /// It's a function to debug the entire env
278 /// # Example
279 /// ```
280 /// use rust_env::Env;
281 /// let env: Env = Env::new("./.env");
282 ///
283 /// env.debug();
284 /// ```
285
286 pub fn debug(&self) { println!("{:?}", self.data) }
287 #[allow(dead_code)]
288 /// You can # upload config data to a env file.
289 /// It's similar to the `new` function
290 /// But you can write external data to the
291 /// env file
292 /// # Example
293 /// ```
294 /// use rust_env::{Env, Str, Vct};
295 ///
296 /// let env = Env::upload("./env", vec![
297 /// Str("PORT", "6778"),
298 /// Vct("IP", vec![
299 /// "127",
300 /// "0",
301 /// "0"
302 /// ])
303 /// ]);
304 /// ```
305 pub fn upload(path: &str, pairs: Vec<Hash>) -> Env {
306 let mut data: Vec<Hash> = Vec::new();
307 let mut hash = String::new();
308
309 for pair in pairs.into_iter() {
310 match pair.clone() {
311 Hash::Str(a, b) => {
312 data.push(pair.clone());
313
314 hash.push_str(&*a);
315 hash.push('=');
316 hash.push_str(&*b);
317 hash.push_str("\n");
318 },
319 Hash::Vec(a, vector) => {
320 data.push(Hash::Vec(a.clone(), vector.clone()));
321
322 let mut raw_literal = a;
323 raw_literal.push('=');
324
325 for ve in vector.clone().into_iter() {
326 raw_literal.push_str(&*ve);
327 raw_literal.push_str(";")
328 }
329
330 hash.push_str(&*raw_literal);
331 }
332 _ => {}
333 }
334 }
335 write(path, hash).expect(
336 "Invalid path to write");
337
338 Self {
339 data,
340 global: Vec::new(),
341 path: path.to_string()
342 }
343 }
344
345 ///You can upload the global env data on the environment
346 ///# Example
347 ///```
348 /// use rust_env::Env;
349 ///
350 /// let mut env: Env = Env::upload("./.env", vec![
351 /// //put your local config
352 /// ]);
353 ///
354 /// env.debug();
355 /// env.global_env();
356 /// env.debug();
357 #[allow(dead_code)]
358 pub fn global_env(&mut self) {
359 for (k, v) in vars() {
360 self.global.push(Hash::Str(k, v));
361 }
362 }
363
364 #[allow(dead_code)]
365 /// get_local is similar to `get_hash`
366 /// But, You can just gt the local config
367 /// Not the global
368 /// # Example
369 /// ```
370 /// use rust_env::Wrapper;
371 ///
372 /// let port = match get_local("PORT") {
373 /// Wrapper::Str(v) => v,
374 /// e => e
375 /// };
376 pub fn get_local(&self, k: &str) -> Wrapper {
377 get_d(self.data[..].to_vec(), k.to_string())
378 }
379
380 #[allow(dead_code)]
381 /// get_global is similar to `get_hash`
382 /// But, You can just gt the local config
383 /// Not the global
384 /// # Example
385 /// ```
386 /// use rust_env::Wrapper;
387 ///
388 /// let path = match get_global("PATH") {
389 /// Wrapper::Str(v) => v,
390 /// e => e
391 /// };
392 pub fn get_global(&self, k: &str) -> Wrapper { get_d(self.global[..].to_vec(), k.to_string()) }
393
394 /// It will print the global env
395 #[allow(dead_code)]
396 pub fn debug_global(&self) { println!("{:?}", self.global) }
397
398 /// It will print the local env
399 /// # Example
400 /// ```
401 /// use rust_env::Env;
402 ///
403 /// let mut env = Env::new("./.env");
404 /// env.global_env();
405 ///
406 /// //printing just global env
407 /// env.debug_global();
408 ///
409 /// //printing just local env
410 /// env.debug_local()
411 /// ```
412 #[allow(dead_code)]
413 pub fn debug_local(&self) { println!("{:?}", self.data) }
414
415 #[allow(dead_code)]
416 /// You can get data from the Env
417 /// # Example
418 /// ```
419 /// use rust_env::Wrapper;
420 /// let port = match env.get_hash("PORT") {
421 /// Wrapper::Str(d) => d,
422 /// _ => String::new()
423 /// };
424 ///
425 /// let ip = match env.get_hash("IP") {
426 /// Wrapper::Vec(v) => v,
427 /// e => e
428 /// };
429 /// ```
430 /// `get_hash` returns a Wrapper enum
431 pub fn get_hash(&mut self, k: &str) -> Wrapper {
432 return match get_d(self.global[..].to_vec(), k.to_string()) {
433 Wrapper::Empty => get_d(self.data[..].to_vec(), k.to_string()),
434 e => e
435 };
436 }
437}