use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{
alpha1,
alphanumeric1,
char,
},
combinator::{map, value},
sequence::separated_pair,
IResult,
};
#[cfg(feature = "serde")]
use {
serde::{Deserialize, Serialize, Serializer},
std::collections::HashMap,
};
#[cfg(feature = "extra-traits")]
use std::fmt;
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Clone)]
pub struct Ndb {
pub statements: Vec<NdbStmt>,
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
#[derive(Debug, PartialEq, Clone)]
pub struct NdbStmt {
pub key: String,
pub value: NdbValue,
}
#[cfg(feature = "serde")]
impl Serialize for NdbStmt {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = HashMap::new();
map.insert(&self.key, &self.value);
map.serialize(serializer)
}
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
#[derive(Debug, PartialEq, Clone)]
pub enum NdbValue {
String(String),
Int(i64),
Bool(bool),
}
#[cfg(feature = "extra-traits")]
impl fmt::Display for NdbStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}={}", self.key, self.value)
}
}
pub fn parse_value(input: &str) -> IResult<&str, NdbValue> {
alt((
value(NdbValue::Bool(true), tag("true")),
value(NdbValue::Bool(false), tag("false")),
parse_string_or_int,
))(input)
}
#[cfg(feature = "serde")]
impl Serialize for NdbValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
NdbValue::Int(value) => serializer.serialize_i64(*value),
NdbValue::String(value) => serializer.serialize_str(value),
NdbValue::Bool(value) => serializer.serialize_bool(*value),
}
}
}
#[cfg(feature = "extra-traits")]
impl fmt::Display for NdbValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NdbValue::Bool(value) => write!(f, "{}", value),
NdbValue::String(value) => write!(f, "{}", value),
NdbValue::Int(value) => write!(f, "{}", value),
}
}
}
fn parse_string_or_int(input: &str) -> IResult<&str, NdbValue> {
map(alphanumeric1, |s: &str| {
s.parse::<i64>()
.map_or_else(|_| NdbValue::String(s.to_string()), NdbValue::Int)
})(input)
}
pub fn ndb_stmt(input: &str) -> IResult<&str, NdbStmt> {
let mut stmt = map(
separated_pair(alpha1, char('='), parse_value),
|(key, value)| NdbStmt {
key: String::from(key),
value,
},
);
stmt(input)
}
#[test]
fn parse_ndb() {
assert_eq!(
ndb_stmt("name=hello"),
Ok((
"",
NdbStmt {
key: "name".to_string(),
value: NdbValue::String("hello".to_string()),
}
))
);
assert_eq!(
ndb_stmt("name=9glenda"),
Ok((
"",
NdbStmt {
key: "name".to_string(),
value: NdbValue::String("9glenda".to_string()),
}
))
);
assert_eq!(
ndb_stmt("age=9"),
Ok((
"",
NdbStmt {
key: "age".to_string(),
value: NdbValue::Int(9),
}
))
);
assert_eq!(
ndb_stmt("age=01"),
Ok((
"",
NdbStmt {
key: "age".to_string(),
value: NdbValue::Int(1),
}
))
);
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
assert_eq!(
serde_json::to_string(&NdbStmt {
key: "name".to_string(),
value: NdbValue::String("9glenda".to_string()),
})
.unwrap(),
r#"{"name":"9glenda"}"#
)
}