use std::env::vars;
use std::fs::{read_to_string, write};
use crate::Pair::Comment;
#[derive(Debug, Clone)]
pub enum Wrapper {
Str(String),
Vec(Vec<String>),
Empty
}
#[derive(Clone, Debug, PartialEq)]
pub enum Pair {
Str(String, String),
Vec(String, Vec<String>),
Comment(String)
}
#[allow(dead_code)]
struct SPair(String, String);
pub struct Env {
pub data: Vec<Pair>,
pub global: Vec<Pair>,
pub path: String
}
pub trait EnvFrame {
fn marshal(val: Vec<Pair>) -> String;
fn parse(content: String) -> Vec<Pair>;
fn new(name: String) -> Env;
fn load(&mut self, e: &str);
fn get(&self, k: &str) -> Wrapper;
fn get_debug(self) -> Vec<Pair>;
fn set(&mut self, k: &str, v: Pair);
fn debug(self);
fn upload(path: &str, Pairs: Vec<Pair>) -> Env;
fn global_env(&mut self);
fn get_local(&self, k: &str) -> Wrapper;
fn get_global(&self, k: &str) -> Wrapper;
}
#[allow(non_snake_case)]
#[allow(dead_code)]
pub fn Str(a: &str, b: &str) -> Pair {
Pair::Str(a.to_string(), b.to_string())
}
pub fn get_d(d: Vec<Pair>, key: String) -> Wrapper {
for h in d.into_iter() {
match h {
Pair ::Str(k, v)
if k == key => {
return Wrapper::Str(v)
},
Pair ::Vec(k, v)
if k == key => {
return Wrapper::Vec(v)
},
_ => continue
}
}
return Wrapper::Empty;
}
#[allow(dead_code)]
pub fn match_str(w: Wrapper) -> String {
return match w {
Wrapper::Str(s) => s,
Wrapper::Vec(_) => {
panic!("Can't extract string from Wrapper::Vec");
}
_ => String::new()
}
}
#[allow(dead_code)]
pub fn match_vec(w: Wrapper) -> Vec<String> {
return match w {
Wrapper::Vec(s) => s,
Wrapper::Str(_) => {
panic!("Can't extract string from Wrapper::Str")
}
_ => Vec::new()
}
}
fn has(b: Vec<Pair>, h: Pair) -> bool {
let mut res = false;
for vals in b.into_iter() {
if vals == h {
res = true;
break;
}
}
res
}
impl Env {
#[allow(dead_code)]
pub fn parse(content: &str) -> Vec<Pair> {
let s = content.to_string();
let lines = s.split("\n").collect::<Vec<&str>>();
let mut res: Vec<Pair> = Vec::new();
for _lines in lines.iter() {
let Pair_ = _lines.split_once("=").unwrap_or_default();
if Pair_.0 == "" {
if _lines.starts_with("#") {
res.push(Comment(String::from(&_lines[1..])));
continue;
}
continue;
}
let raw_value = Pair_.1;
let mut value: Pair = Pair::Comment(String::new());
match raw_value.find(";") {
Some(_) => {
let raw = raw_value.split(";").collect::<Vec<&str>>();
let mut str_vec: Vec<String> = Vec::new();
for r in raw.into_iter() {
str_vec.push(r.to_string());
}
value = Pair::Vec(
Pair_.0.to_string(),
str_vec)
}
None => {
value = Pair::Str(Pair_.0.to_string(),
Pair_.1.trim().to_string())
}
}
res.push(value);
}
return res;
}
pub fn marshal(val: Vec<Pair>) -> String {
let mut Pair = String::new();
for v in val.into_iter() {
Pair.push_str(match v.clone() {
Pair::Str(a, _) => a,
Pair::Vec(a, _) => a,
_ => String::new()
}.as_str());
Pair.push('=');
Pair.push_str(match v.clone() {
Pair::Str(_, b) => b,
Pair::Vec(_, v) => {
let mut s = String::new();
for v in v.clone() {
s.push_str(v.as_str());
s.push(';')
}
s
},
Pair::Comment(s) => format!("#{s}")
}.as_str());
}
return Pair;
}
pub fn new(name: &str) -> Env {
let content = read_to_string(name.clone()).expect("Invalid path");
let local = Env::parse(content.as_str());
Self {
data: local,
path: name.to_string().clone(),
global: Vec::new()
}
}
#[allow(dead_code)]
pub fn get_debug(self) -> Vec<Pair> { return self.data.clone() }
#[allow(dead_code)]
pub fn set(&mut self, h: Pair) {
if !has(self.data.clone(), h.clone()) {
self.data.push(h.clone());
}
let Pair = Env::marshal(vec![h]);
write(&self.path, Pair).expect(
"Invalid path to write")
}
#[allow(dead_code)]
pub fn load(&mut self, e: &str) {
let h = Env::parse(e);
for Pair in h.into_iter() {
if !has(self.data.clone(), Pair.clone()) {
self.data.push(Pair.clone())
}
}
}
#[allow(dead_code)]
pub fn debug(&self) { println!("{:?}", self.data) }
#[allow(dead_code)]
pub fn upload(path: &str, Pairs: Vec<Pair>) -> Env {
let mut data: Vec<Pair> = Vec::new();
let mut out = String::new();
for Pair in Pairs.into_iter() {
match Pair.clone() {
Pair::Str(a, b) => {
data.push(Pair.clone());
out.push_str(&*a);
out.push('=');
out.push_str(&*b);
out.push_str("\n");
},
Pair::Vec(a, vector) => {
data.push(Pair::Vec(a.clone(), vector.clone()));
let mut raw_literal = a;
raw_literal.push('=');
for ve in vector.clone().into_iter() {
raw_literal.push_str(&*ve);
raw_literal.push_str(";")
}
out.push_str(&*raw_literal);
}
_ => {}
}
}
write(path, out).expect(
"Invalid path to write");
Self {
data,
global: Vec::new(),
path: path.to_string()
}
}
#[allow(dead_code)]
pub fn global_env(&mut self) {
for (k, v) in vars() {
self.global.push(Pair::Str(k, v));
}
}
#[allow(dead_code)]
pub fn get_local(&self, k: &str) -> Wrapper {
get_d(self.data[..].to_vec(), k.to_string())
}
#[allow(dead_code)]
pub fn get_global(&self, k: &str) -> Wrapper { get_d(self.global[..].to_vec(), k.to_string()) }
#[allow(dead_code)]
pub fn debug_global(&self) { println!("{:?}", self.global) }
#[allow(dead_code)]
pub fn debug_local(&self) { println!("{:?}", self.data) }
#[allow(dead_code)]
pub fn get_pair(&mut self, k: &str) -> Wrapper {
return match get_d(self.global[..].to_vec(), k.to_string()) {
Wrapper::Empty => get_d(self.data[..].to_vec(), k.to_string()),
e => e
};
}
}