extern crate textnonce;
use std::collections::HashMap;
use super::ast;
#[derive(Serialize, Deserialize)]
#[derive(Clone, Debug)]
pub enum Value {
Int(i32),
Str(String),
Object(Obj),
}
impl PartialEq for Value {
fn eq(&self, other: &Value) -> bool {
match self {
&Value::Int(x) => {
match other {
&Value::Int(y) => x == y,
_ => false,
}
}
&Value::Str(ref x) => {
match other {
&Value::Str(ref y) => x == y,
_ => false,
}
}
&Value::Object(ref x) => {
match other {
&Value::Object(ref y) => x.eq(y),
_ => false,
}
}
}
}
}
impl Value {
pub fn from_int(i: i32) -> Value {
Value::Int(i)
}
pub fn from_str(s: &str) -> Value {
Value::Str(s.to_string())
}
pub fn from_obj(o: Obj) -> Value {
Value::Object(o)
}
pub fn from_flat_map(m: HashMap<String, String>) -> Obj {
let mut result = Obj::new();
for (k, v) in m.iter() {
let id = Identifier::from_str(&k);
id.set(&mut result, Value::from_str(v));
}
result
}
pub fn to_string(&self) -> String {
match self {
&Value::Int(ref i) => i.to_string(),
&Value::Str(ref s) => s.to_string(),
&Value::Object(_) => "{...}".to_string(), }
}
pub fn to_env(o: &Obj) -> Env {
Value::to_env_prefix(o, "").into_iter().collect()
}
fn to_env_prefix(o: &Obj, prefix: &str) -> Vec<(String, String)> {
o.iter()
.map(|(k, v)| {
let fqprefix = match prefix {
"" => k.to_string(),
_ => vec![prefix, k].join("__").to_string(),
};
match v {
&Value::Object(ref child) => Value::to_env_prefix(child, &fqprefix),
_ => vec![(fqprefix.clone(), v.to_string())],
}
})
.flat_map(|v| v.into_iter())
.collect()
}
}
pub type Obj = HashMap<String, Value>;
#[derive(Serialize, Deserialize)]
#[derive(Clone, Debug)]
pub struct Message {
pub id: String,
pub src_remote: Option<String>,
pub src_agent: String,
pub src_role: Option<String>,
pub dst_remote: Option<String>,
pub dst_agent: String,
pub in_reply_to: Option<String>,
pub topic: String,
pub contents: Obj,
}
impl Message {
pub fn new(topic: &str, contents: Obj) -> Message {
Message {
id: textnonce::TextNonce::sized_urlsafe(32)
.unwrap()
.into_string(),
src_remote: None,
src_agent: "".to_string(),
src_role: None,
dst_remote: None,
dst_agent: "".to_string(),
topic: topic.to_string(),
in_reply_to: None,
contents: contents,
}
}
pub fn new_id(mut self) -> Message {
self.id = textnonce::TextNonce::sized_urlsafe(32)
.unwrap()
.into_string();
self
}
pub fn src_remote(mut self, src_remote: &str) -> Message {
self.src_remote = Some(src_remote.to_string());
self
}
pub fn src_agent(mut self, src_agent: &str) -> Message {
self.src_agent = src_agent.to_string();
self
}
pub fn src_role(mut self, src_role: Option<String>) -> Message {
self.src_role = src_role.clone();
self
}
pub fn dst_remote(mut self, dst_remote: Option<String>) -> Message {
self.dst_remote = dst_remote.clone();
self
}
pub fn dst_agent(mut self, dst_agent: &str) -> Message {
self.dst_agent = dst_agent.to_string();
self
}
pub fn in_reply_to(mut self, in_reply_to: Option<String>) -> Message {
self.in_reply_to = in_reply_to.clone();
self
}
}
pub type Env = HashMap<String, String>;
#[derive(Serialize, Deserialize)]
#[derive(Clone, Debug)]
pub struct Identifier(Vec<String>);
impl Identifier {
pub fn from_ast(i_ast: &ast::Identifier) -> Identifier {
Identifier(i_ast.clone())
}
pub fn from_str(s: &str) -> Identifier {
let v: Vec<String> = s.split(".").map(|x| x.to_string()).collect();
Identifier(v)
}
pub fn get<'b>(&self, root: &'b Obj) -> Option<&'b Value> {
if self.0.is_empty() {
return None;
}
let mut cur = root;
for i in 0..self.0.len() {
match cur.get(&self.0[i]) {
Some(v) => {
match v {
&Value::Object(ref o) => {
cur = o;
}
_ => {}
}
if i == self.0.len() - 1 {
return Some(v);
}
}
None => {
return None;
}
}
}
return None;
}
pub fn is_set(&self, root: &Obj) -> bool {
match self.get(root) {
Some(_) => true,
None => false,
}
}
pub fn set(&self, root: &mut Obj, value: Value) {
Identifier::set_slice(&self.0, root, value);
}
fn set_slice(path: &[String], o: &mut Obj, value: Value) {
if path.is_empty() {
return;
}
let (next, rest) = path.split_first().unwrap();
if rest.is_empty() {
o.insert(next.to_string(), value);
return;
}
match o.get_mut(next) {
Some(v) => {
match v {
&mut Value::Object(ref mut child) => {
Identifier::set_slice(rest, child, value);
return;
}
_ => {}
}
}
None => {}
}
o.insert(next.to_string(), Value::Object(Obj::new()));
Identifier::set_slice(path, o, value);
}
pub fn unset(&self, root: &mut Obj) {
Identifier::unset_slice(&self.0, root)
}
fn unset_slice(path: &[String], o: &mut Obj) {
if path.is_empty() {
return;
}
let (next, rest) = path.split_first().unwrap();
if rest.is_empty() {
o.remove(next);
return;
}
match o.get_mut(next) {
Some(v) => {
match v {
&mut Value::Object(ref mut child) => {
Identifier::unset_slice(rest, child);
return;
}
_ => {}
}
}
None => {}
}
}
}