rust_env/lib.rs
1//! # rust-env
2//!
3//! `rust-env` is a lightweight environment configuration library for Rust.
4//!
5//! It helps you manage `.env`-style configuration files with support for:
6//! - Key-value pairs
7//! - Vector (list) values using `;` separators
8//! - Runtime OS environment variables
9//! - Reading and writing environment files
10//!
11//! ---
12//!
13//! # Features
14//!
15//! - Parse `.env` files into structured data
16//! - Support for string and vector values
17//! - Access local and global environment variables
18//! - Modify and persist environment files
19//! - Simple helper API for extracting values
20//!
21//! ---
22//!
23//! # Value Model
24//!
25//! Internally, `rust-env` represents data using:
26//!
27//! - `Str(key, value)`
28//! - `Vec(key, Vec<String>)`
29//! - `Comment(String)`
30//!
31//! ---
32//!
33//! # Example
34//!
35//! ```rust
36//! use rust_env::Env;
37//!
38//! let mut env = Env::new("./.env");
39//!
40//! let port = env.get_pair("PORT");
41//! env.set(Str("PORT", "8080"));
42//! ```
43//!
44//! ---
45//!
46//! # Local vs Global
47//!
48//! - **Local**: values loaded from `.env` file
49//! - **Global**: OS environment variables
50//!
51//! When using merged lookup:
52//! ```text
53//! global > local
54//! ```
55//!
56//! ---
57//!
58//! # Notes
59//!
60//! - All values are stored as strings internally
61//! - Vector values are separated using `;`
62//! - File writes occur immediately when using `set`
63//!
64//! ---
65//!
66//! # Version History
67//!
68//! ## v0.2.0
69//! - Added `match_str` and `match_vec` helpers
70//! - Refactored codebase into multiple files
71//! - Fixed 3 known bugs
72//!
73//! ---
74//!
75//! # Experimental
76//!
77//! Experimental features such as a future markup language (RML) are **not part of this crate**.
78//!
79//! They may be developed separately in the future.
80
81use std::env::vars;
82use std::fs::{read_to_string, write};
83
84use crate::Pair::Comment;
85
86#[derive(Debug, Clone)]
87/// This enum mainly rap two type of data
88/// String and `Vec<String>`
89/// See docs of `struct Env` of this package for learn more
90pub enum Wrapper {
91 Str(String),
92 Vec(Vec<String>),
93 Empty
94}
95
96
97#[derive(Clone, Debug, PartialEq)]
98pub enum Pair {
99 Str(String, String),
100 Vec(String, Vec<String>),
101 Comment(String)
102}
103
104#[allow(dead_code)]
105struct SPair(String, String);
106
107/// The main environment container used by `rust-env`.
108///
109/// `Env` manages both:
110/// - Local environment variables loaded from a `.env` file
111/// - Global environment variables from the operating system
112///
113/// It provides functionality to:
114/// - Parse environment files into structured data
115/// - Retrieve values (local, global, or merged)
116/// - Modify environment entries
117/// - Persist changes back to a file
118///
119/// # Internal Representation
120///
121/// Environment data is stored as a vector of `Pair`:
122///
123/// - `Pair::Str(key, value)` → single value
124/// - `Pair::Vec(key, values)` → list of values (semicolon-separated in file)
125/// - `Pair::Comment(text)` → comments in the file
126///
127/// # Fields
128///
129/// - `data`: Local environment variables loaded from file
130/// - `global`: OS environment variables captured at runtime
131/// - `path`: Path to the associated `.env` file
132///
133/// # Behavior Notes
134///
135/// - Local data comes from the file at `path`
136/// - Global data is loaded via `std::env::vars()`
137/// - `set()` writes changes immediately to disk
138/// - Lookup functions may fall back between global/local depending on method
139///
140/// # Example
141///
142/// ```rust
143/// use rust_env::{Env, Str};
144///
145/// let mut env = Env::new("./.env");
146///
147/// // Get a value
148/// let port = env.get_pair("PORT");
149///
150/// // Set a value
151/// env.set(Str("PORT", "8080"));
152///
153/// // Load OS environment variables
154/// env.global_env();
155///
156/// // Debug print local env
157/// env.debug_local();
158/// ```
159///
160/// # Notes
161///
162/// - This struct is not thread-safe by default
163/// - All values are stored internally as strings
164/// - Vector values use `;` as delimiter in files
165pub struct Env {
166 pub data: Vec<Pair>,
167 pub global: Vec<Pair>,
168 pub path: String
169}
170
171/// A trait that defines the core behavior of an environment system.
172///
173/// This trait is mainly intended for advanced use cases where users want to
174/// implement a custom environment backend while keeping compatibility with
175/// the `rust-env` API.
176///
177/// Most users do NOT need to implement this trait directly.
178///
179/// # Purpose
180///
181/// `EnvFrame` allows you to:
182/// - Define custom storage for environment data
183/// - Customize parsing and serialization logic
184/// - Extend or replace default `Env` behavior
185///
186/// # Example
187///
188/// ```rust
189/// use rust_env::{EnvFrame, Pair};
190///
191/// struct CustomEnv {
192/// data: Vec<Pair>,
193/// global: Vec<Pair>,
194/// path: String,
195/// }
196///
197/// impl EnvFrame for CustomEnv {
198/// // implement custom behavior here
199/// }
200/// ```
201///
202/// # Note
203///
204/// This trait is intended for advanced extensibility only.
205/// Standard usage should rely on `Env`.
206pub trait EnvFrame {
207 fn marshal(val: Vec<Pair>) -> String;
208 fn parse(content: String) -> Vec<Pair>;
209 fn new(name: String) -> Env;
210 fn load(&mut self, e: &str);
211 fn get(&self, k: &str) -> Wrapper;
212 fn get_debug(self) -> Vec<Pair>;
213 fn set(&mut self, k: &str, v: Pair);
214 fn debug(self);
215 fn upload(path: &str, Pairs: Vec<Pair>) -> Env;
216 fn global_env(&mut self);
217 fn get_local(&self, k: &str) -> Wrapper;
218 fn get_global(&self, k: &str) -> Wrapper;
219}
220
221#[allow(non_snake_case)]
222#[allow(dead_code)]
223pub fn Str(a: &str, b: &str) -> Pair {
224 Pair::Str(a.to_string(), b.to_string())
225}
226
227pub fn get_d(d: Vec<Pair>, key: String) -> Wrapper {
228 for h in d.into_iter() {
229
230 match h {
231 Pair ::Str(k, v)
232 if k == key => {
233 return Wrapper::Str(v)
234 },
235 Pair ::Vec(k, v)
236 if k == key => {
237 return Wrapper::Vec(v)
238 },
239 _ => continue
240 }
241 }
242
243 return Wrapper::Empty;
244}
245
246/// On version 0.2.0 of rust-env DX improved
247/// You don't need to match a `Wrapper` variant
248/// Instead use `match_str` and `match vec`
249/// Here's a example
250/// # Example
251/// ```
252/// use rust_env::{Env, match_str, match_vec, Wrapper};
253///
254/// let env = Env::new("./config.env");
255///
256/// //On version 0.1.0
257/// let addr = match env.get_local("ADDR") {
258/// Wrapper::Str(e) => e,
259/// Wrapper::Vec(v) => panic!("Can't use vec instead of string"),
260/// _ => String::new()
261/// };
262/// let ip = match env.get_local("ip") {
263/// Wrapper::Vec(e) => e,
264/// Wrapper::Str(v) => panic!("Can't use string instead of vec"),
265/// _ => String::new()
266/// };
267///
268/// //Now (v0.2.0)
269///
270/// let addr: String = match_str(env.get_local("ADDR"));
271/// let ip: Vec<String> = match_vec(env.get_local("IP"));
272/// ```
273
274#[allow(dead_code)]
275pub fn match_str(w: Wrapper) -> String {
276 return match w {
277 Wrapper::Str(s) => s,
278 Wrapper::Vec(_) => {
279 panic!("Can't extract string from Wrapper::Vec");
280 }
281 _ => String::new()
282 }
283}
284
285/// On version 0.2.0 of rust-env DX improved
286/// You don't need to match a `Wrapper` variant
287/// Instead use `match_str` and `match vec`
288/// Here's a example
289/// # Example
290/// ```
291/// use rust_env::{Env, match_str, match_vec, Wrapper};
292///
293/// let env = Env::new("./config.env");
294///
295/// //On version 0.1.0
296/// let addr = match env.get_local("ADDR") {
297/// Wrapper::Str(e) => e,
298/// Wrapper::Vec(v) => panic!("Can't use vec instead of string"),
299/// _ => String::new()
300/// };
301/// let ip = match env.get_local("ip") {
302/// Wrapper::Vec(e) => e,
303/// Wrapper::Str(v) => panic!("Can't use string instead of vec"),
304/// _ => String::new()
305/// };
306///
307/// //Now (v0.2.0)
308///
309/// let addr: String = match_str(env.get_local("ADDR"));
310/// let ip: Vec<String> = match_vec(env.get_local("IP"));
311/// ```
312#[allow(dead_code)]
313pub fn match_vec(w: Wrapper) -> Vec<String> {
314 return match w {
315 Wrapper::Vec(s) => s,
316 Wrapper::Str(_) => {
317 panic!("Can't extract string from Wrapper::Str")
318 }
319 _ => Vec::new()
320 }
321}
322
323fn has(b: Vec<Pair>, h: Pair) -> bool {
324 let mut res = false;
325
326 for vals in b.into_iter() {
327 if vals == h {
328 res = true;
329 break;
330 }
331 }
332
333 res
334}
335
336impl Env {
337 #[allow(dead_code)]
338 /// Parses a raw environment string into a list of `Pair` values.
339 ///
340 /// This function converts `.env`-style text into structured data.
341 ///
342 /// # Format Rules
343 ///
344 /// Each line is expected to follow:
345 ///
346 /// ```text
347 /// KEY=VALUE
348 /// ```
349 ///
350 /// Supported formats:
351 ///
352 /// - Single value:
353 /// ```text
354 /// PORT=8080
355 /// ```
356 ///
357 /// - Vector value (semicolon-separated):
358 /// ```text
359 /// IP=127;0;0;1
360 /// ```
361 ///
362 /// # Behavior
363 ///
364 /// - Lines without `=` are ignored
365 /// - Empty keys are ignored
366 /// - Values containing `;` are treated as vectors
367 /// - Whitespace around values is trimmed
368 ///
369 /// # Returns
370 ///
371 /// A `Vec<Pair>` representing parsed environment entries.
372 ///
373 /// # Example
374 ///
375 /// ```rust
376 /// use rust_env::Env;
377 ///
378 /// let data = Env::parse("PORT=8080\nIP=127;0;0;1");
379 /// ```
380 ///
381 /// # Notes
382 ///
383 /// - This function does not read from files directly
384 /// - It only parses in-memory strings
385 /// - Comments are not fully supported unless explicitly handled
386 pub fn parse(content: &str) -> Vec<Pair> {
387 let s = content.to_string();
388 let lines = s.split("\n").collect::<Vec<&str>>();
389 let mut res: Vec<Pair> = Vec::new();
390
391 for _lines in lines.iter() {
392 let Pair_ = _lines.split_once("=").unwrap_or_default();
393
394 if Pair_.0 == "" {
395 if _lines.starts_with("#") {
396 res.push(Comment(String::from(&_lines[1..])));
397 continue;
398 }
399 continue;
400 }
401
402 let raw_value = Pair_.1;
403 let mut value: Pair = Pair::Comment(String::new());
404
405 match raw_value.find(";") {
406 Some(_) => {
407 let raw = raw_value.split(";").collect::<Vec<&str>>();
408 let mut str_vec: Vec<String> = Vec::new();
409
410 for r in raw.into_iter() {
411 str_vec.push(r.to_string());
412 }
413 value = Pair::Vec(
414 Pair_.0.to_string(),
415 str_vec)
416 }
417 None => {
418 value = Pair::Str(Pair_.0.to_string(),
419 Pair_.1.trim().to_string())
420 }
421 }
422
423 res.push(value);
424 }
425
426 return res;
427 }
428
429 /// Converts a vector of `Pair` values into a valid `.env` formatted string.
430 ///
431 /// This is the inverse of `parse()`.
432 ///
433 /// It serializes structured environment data back into text form.
434 ///
435 /// # Output Format
436 ///
437 /// - `Pair::Str(key, value)` →
438 /// ```text
439 /// KEY=VALUE
440 /// ```
441 ///
442 /// - `Pair::Vec(key, values)` →
443 /// ```text
444 /// KEY=a;b;c
445 /// ```
446 ///
447 /// - `Pair::Comment(text)` →
448 /// ```text
449 /// #text
450 /// ```
451 ///
452 /// # Behavior
453 ///
454 /// - Values in vectors are joined using `;`
455 /// - Keys and values are written exactly as stored
456 /// - No escaping is applied for special characters
457 ///
458 /// # Returns
459 ///
460 /// A formatted `.env` string.
461 ///
462 /// # Example
463 ///
464 /// ```rust
465 /// use rust_env::{Env, Str};
466 ///
467 /// let data = vec![
468 /// Str("PORT", "8080"),
469 /// ];
470 ///
471 /// let out = Env::marshal(data);
472 /// ```
473 ///
474 /// # Notes
475 ///
476 /// - This function does not write to files
477 /// - Formatting is minimal and not lossless (comments/order may be simplified)
478
479 pub fn marshal(val: Vec<Pair>) -> String {
480 let mut Pair = String::new();
481
482 for v in val.into_iter() {
483 Pair.push_str(match v.clone() {
484 Pair::Str(a, _) => a,
485 Pair::Vec(a, _) => a,
486 _ => String::new()
487 }.as_str());
488 Pair.push('=');
489 Pair.push_str(match v.clone() {
490 Pair::Str(_, b) => b,
491 Pair::Vec(_, v) => {
492 let mut s = String::new();
493
494 for v in v.clone() {
495 s.push_str(v.as_str());
496 s.push(';')
497 }
498
499 s
500 },
501 Pair::Comment(s) => format!("#{s}")
502 }.as_str());
503 }
504
505 return Pair;
506 }
507
508 /// Creates a new `Env` instance from a `.env` file.
509 ///
510 /// This function reads the file at the given path and parses its contents
511 /// into structured environment data.
512 ///
513 /// # Behavior
514 ///
515 /// - Loads local environment variables from the file
516 /// - Parses content using `.env` rules (`KEY=VALUE`)
517 /// - Stores results in `self.data`
518 /// - Initializes an empty global environment store
519 ///
520 /// # Arguments
521 ///
522 /// - `name`: Path to the `.env` file
523 ///
524 /// # Returns
525 ///
526 /// A fully initialized `Env` instance containing:
527 /// - `data`: parsed local environment variables
528 /// - `global`: empty until `global_env()` is called
529 /// - `path`: stored file path
530 ///
531 /// # Example
532 ///
533 /// ```rust
534 /// use rust_env::Env;
535 ///
536 /// let env = Env::new("./.env");
537 /// ```
538 ///
539 /// # Notes
540 ///
541 /// - Panics if the file path is invalid or unreadable
542 /// - This does NOT load OS environment variables automatically
543 /// - Use `global_env()` to populate global environment data
544 pub fn new(name: &str) -> Env {
545 let content = read_to_string(name.clone()).expect("Invalid path");
546 let local = Env::parse(content.as_str());
547
548 Self {
549 data: local,
550 path: name.to_string().clone(),
551 global: Vec::new()
552 }
553 }
554
555 #[allow(dead_code)]
556 /// It will return the entire env
557 /// local and global
558 /// # Example
559 /// ```
560 /// use rust_env::{Env, Pair};
561 ///
562 /// let env = Env::new("./.env");
563 /// let e: Vec<Pair> = env.get_debug();
564 /// ```
565
566 pub fn get_debug(self) -> Vec<Pair> { return self.data.clone() }
567 #[allow(dead_code)]
568
569 /// Creates a new `Env` instance from a `.env` file.
570 ///
571 /// This function reads the file at the given path and parses its contents
572 /// into structured environment data.
573 ///
574 /// # Behavior
575 ///
576 /// - Loads local environment variables from the file
577 /// - Parses content using `.env` rules (`KEY=VALUE`)
578 /// - Stores results in `self.data`
579 /// - Initializes an empty global environment store
580 ///
581 /// # Arguments
582 ///
583 /// - `name`: Path to the `.env` file
584 ///
585 /// # Returns
586 ///
587 /// A fully initialized `Env` instance containing:
588 /// - `data`: parsed local environment variables
589 /// - `global`: empty until `global_env()` is called
590 /// - `path`: stored file path
591 ///
592 /// # Example
593 ///
594 /// ```rust
595 /// use rust_env::Env;
596 ///
597 /// let env = Env::new("./.env");
598 /// ```
599 ///
600 /// # Notes
601 ///
602 /// - Panics if the file path is invalid or unreadable
603 /// - This does NOT load OS environment variables automatically
604 /// - Use `global_env()` to populate global environment data
605 pub fn set(&mut self, h: Pair) {
606
607 if !has(self.data.clone(), h.clone()) {
608 self.data.push(h.clone());
609 }
610 let Pair = Env::marshal(vec![h]);
611
612 write(&self.path, Pair).expect(
613 "Invalid path to write")
614 }
615
616 /// Loads environment data into the current `Env` instance.
617 ///
618 /// This function parses a raw `.env`-style string and merges it into
619 /// the existing local environment data.
620 ///
621 /// It is similar to `set`, but operates on multiple entries at once
622 /// and does not directly write to disk.
623 ///
624 /// # Behavior
625 ///
626 /// - Parses the input string using `.env` rules (`KEY=VALUE`)
627 /// - Supports vector values using `;` separators
628 /// - Ignores duplicate keys already present in `self.data`
629 /// - Only updates in-memory state (does NOT persist to file)
630 ///
631 /// # Arguments
632 ///
633 /// - `e`: A raw environment string (e.g. `"PORT=8080\nIP=127;0;0;1"`)
634 ///
635 /// # Example
636 ///
637 /// ```rust
638 /// use rust_env::Env;
639 ///
640 /// let mut env = Env::new("./.env");
641 ///
642 /// env.load("PORT=8080\nHOST=127.0.0.1");
643 /// env.debug();
644 /// ```
645 ///
646 /// # Notes
647 ///
648 /// - This does NOT modify the file on disk
649 /// - Use `set` or `upload` for persistent changes
650 /// - Duplicate keys are ignored based on existing local data
651 #[allow(dead_code)]
652 pub fn load(&mut self, e: &str) {
653 let h = Env::parse(e);
654
655 for Pair in h.into_iter() {
656 if !has(self.data.clone(), Pair.clone()) {
657 self.data.push(Pair.clone())
658 }
659 }
660 }
661
662
663 #[allow(dead_code)]
664 /// It's a function to debug the entire env
665 /// # Example
666 /// ```
667 /// use rust_env::Env;
668 /// let env: Env = Env::new("./.env");
669 ///
670 /// env.debug();
671 /// ```
672
673 pub fn debug(&self) { println!("{:?}", self.data) }
674 #[allow(dead_code)]
675 /// This function allows one to marshal env pairs and write them to a certain file
676 /// It's similar to the `new` function
677 /// But you can write external data to the
678 /// env file
679 /// # Example
680 /// ```
681 /// use rust_env::{Env, Str, Vct};
682 ///
683 /// let env = Env::upload("./env", vec![
684 /// Str("PORT", "6778"),
685 /// Vct("IP", vec![
686 /// "127",
687 /// "0",
688 /// "0"
689 /// ])
690 /// ]);
691 /// ```
692 pub fn upload(path: &str, Pairs: Vec<Pair>) -> Env {
693 let mut data: Vec<Pair> = Vec::new();
694 let mut out = String::new();
695
696 for Pair in Pairs.into_iter() {
697 match Pair.clone() {
698 Pair::Str(a, b) => {
699 data.push(Pair.clone());
700
701 out.push_str(&*a);
702 out.push('=');
703 out.push_str(&*b);
704 out.push_str("\n");
705 },
706 Pair::Vec(a, vector) => {
707 data.push(Pair::Vec(a.clone(), vector.clone()));
708
709 let mut raw_literal = a;
710 raw_literal.push('=');
711
712 for ve in vector.clone().into_iter() {
713 raw_literal.push_str(&*ve);
714 raw_literal.push_str(";")
715 }
716
717 out.push_str(&*raw_literal);
718 }
719 _ => {}
720 }
721 }
722 write(path, out).expect(
723 "Invalid path to write");
724
725 Self {
726 data,
727 global: Vec::new(),
728 path: path.to_string()
729 }
730 }
731
732 ///You can upload the global env data on the environment
733 ///# Example
734 ///```
735 /// use rust_env::Env;
736 ///
737 /// let mut env: Env = Env::upload("./.env", vec![
738 /// //put your local config
739 /// ]);
740 ///
741 /// env.debug();
742 /// env.global_env();
743 /// env.debug();
744 #[allow(dead_code)]
745 pub fn global_env(&mut self) {
746 for (k, v) in vars() {
747 self.global.push(Pair::Str(k, v));
748 }
749 }
750
751 #[allow(dead_code)]
752 /// get_local is similar to `get_Pair`
753 /// But, You can just gt the local config
754 /// Not the global
755 /// # Example
756 /// ```
757 /// use rust_env::Wrapper;
758 ///
759 /// let port = match get_local("PORT") {
760 /// Wrapper::Str(v) => v,
761 /// e => e
762 /// };
763 pub fn get_local(&self, k: &str) -> Wrapper {
764 get_d(self.data[..].to_vec(), k.to_string())
765 }
766
767 #[allow(dead_code)]
768 /// Retrieves a value from the global (OS-level) environment variables.
769 ///
770 /// This function searches only in the runtime environment provided by
771 /// `std::env::vars()`, which is captured when `global_env()` is called.
772 ///
773 /// # Behavior
774 ///
775 /// - Searches only global environment variables
776 /// - Does NOT fall back to local `.env` data
777 /// - Returns the first matching key if found
778 ///
779 /// # Returns
780 ///
781 /// A `Wrapper` enum:
782 /// - `Wrapper::Str(String)` for single values
783 /// - `Wrapper::Vec(Vec<String>)` (rare, depending on parsing rules)
784 /// - `Wrapper::Empty` if the key does not exist
785 ///
786 /// # Arguments
787 ///
788 /// - `k`: The environment variable key to search for
789 ///
790 /// # Example
791 ///
792 /// ```rust
793 /// use rust_env::{Env, Wrapper};
794 ///
795 /// let mut env = Env::new("./.env");
796 /// env.global_env(); // load OS environment variables
797 ///
798 /// match env.get_global("PATH") {
799 /// Wrapper::Str(v) => println!("PATH = {}", v),
800 /// Wrapper::Empty => println!("Not found"),
801 /// _ => println!("Unexpected format"),
802 /// }
803 /// ```
804 ///
805 /// # Notes
806 ///
807 /// - This only works after calling `global_env()`
808 /// - Values come from the OS environment at runtime
809 /// - This does not read from `.env` files
810 /// - Lookup is linear (O(n))
811 pub fn get_global(&self, k: &str) -> Wrapper { get_d(self.global[..].to_vec(), k.to_string()) }
812
813 /// It will print the global env
814 #[allow(dead_code)]
815 pub fn debug_global(&self) { println!("{:?}", self.global) }
816
817 /// It will print the local env
818 /// # Example
819 /// ```
820 /// use rust_env::Env;
821 ///
822 /// let mut env = Env::new("./.env");
823 /// env.global_env();
824 ///
825 /// //printing just global env
826 /// env.debug_global();
827 ///
828 /// //printing just local env
829 /// env.debug_local()
830 /// ```
831 #[allow(dead_code)]
832 pub fn debug_local(&self) { println!("{:?}", self.data) }
833
834 #[allow(dead_code)]
835 /// Retrieves a value from the environment, checking both global and local scopes.
836 ///
837 /// This function performs a merged lookup:
838 ///
839 /// 1. Checks global environment variables (OS-level)
840 /// 2. Falls back to local `.env` data if not found
841 ///
842 /// # Lookup Order
843 ///
844 /// ```text
845 /// global → local
846 /// ```
847 ///
848 /// # Behavior
849 ///
850 /// - Returns the first matching key found
851 /// - If the value is a string, returns `Wrapper::Str`
852 /// - If the value is a list, returns `Wrapper::Vec`
853 /// - If the key does not exist, returns `Wrapper::Empty`
854 ///
855 /// # Arguments
856 ///
857 /// - `k`: The key to search for
858 ///
859 /// # Returns
860 ///
861 /// A `Wrapper` enum containing:
862 /// - `Wrapper::Str(String)` for single values
863 /// - `Wrapper::Vec(Vec<String>)` for list values
864 /// - `Wrapper::Empty` if not found
865 ///
866 /// # Example
867 ///
868 /// ```rust
869 /// use rust_env::{Env, Wrapper};
870 ///
871 /// let mut env = Env::new("./.env");
872 /// env.global_env();
873 ///
874 /// match env.get_pair("PORT") {
875 /// Wrapper::Str(v) => println!("PORT = {}", v),
876 /// Wrapper::Vec(v) => println!("List = {:?}", v),
877 /// Wrapper::Empty => println!("Not found"),
878 /// }
879 /// ```
880 ///
881 /// # Notes
882 ///
883 /// - Global variables override local ones
884 /// - This function does not modify state
885 /// - Lookup is linear (O(n)) in both environments
886 pub fn get_pair(&mut self, k: &str) -> Wrapper {
887 return match get_d(self.global[..].to_vec(), k.to_string()) {
888 Wrapper::Empty => get_d(self.data[..].to_vec(), k.to_string()),
889 e => e
890 };
891 }
892}
893