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}