use crate::{lit_to_string, display_lit};
use syn::{Lit};
use std::str::FromStr;
use std::fmt::{Display, Formatter, Write};
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone)]
pub struct NameValue {
pub name: String,
pub value: Value,
}
impl Display for NameValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}={}", self.name, self.value)
}
}
impl Hash for NameValue {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(self.name.as_bytes());
}
}
impl Eq for NameValue {}
impl PartialEq for NameValue {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Value {
Literal(Lit),
Array(Vec<Lit>),
}
impl Value {
pub fn is_literal(&self) -> bool {
matches!(self, Value::Literal(_))
}
pub fn is_array(&self) -> bool {
matches!(self, Value::Array(_))
}
pub fn is_string(&self) -> bool {
match self {
Value::Literal(lit) => matches!(lit, Lit::Str(_) | Lit::ByteStr(_)),
_ => false,
}
}
pub fn is_char(&self) -> bool {
matches!(self, Value::Literal(Lit::Char(_)))
}
pub fn is_bool(&self) -> bool {
matches!(self, Value::Literal(Lit::Bool(_)))
}
pub fn is_integer(&self) -> bool {
match self {
Value::Literal(lit) => matches!(lit, Lit::Int(_) | Lit::Byte(_)),
_ => false,
}
}
pub fn is_float(&self) -> bool {
matches!(self, Value::Literal(Lit::Float(_)))
}
pub fn is_numeric(&self) -> bool {
self.is_integer() || self.is_float()
}
pub fn to_string_literal(&self) -> Option<String> {
if let Value::Literal(lit) = self {
return match lit {
Lit::Str(x) => Some(x.value()),
Lit::ByteStr(x) => unsafe { Some(String::from_utf8_unchecked(x.value())) },
_ => None,
};
}
None
}
pub fn to_char_literal(&self) -> Option<char> {
if let Value::Literal(lit) = self {
return match lit {
Lit::Char(x) => Some(x.value()),
_ => None,
};
}
None
}
pub fn to_bool_literal(&self) -> Option<bool> {
if let Value::Literal(lit) = self {
return match lit {
Lit::Bool(x) => Some(x.value),
_ => None,
};
}
None
}
pub fn to_byte_literal(&self) -> Option<u8> {
if let Value::Literal(lit) = self {
return match lit {
Lit::Byte(x) => Some(x.value()),
_ => None,
};
}
None
}
pub fn to_integer_literal<N>(&self) -> Option<N>
where
N: FromStr,
N::Err: Display,
{
match self {
Value::Literal(lit) => match lit {
Lit::Byte(n) => {
let s = n.value().to_string();
N::from_str(s.as_str()).ok()
}
Lit::Int(n) => n.base10_parse().ok(),
_ => None,
},
_ => None,
}
}
pub fn to_float_literal<N>(&self) -> Option<N>
where
N: FromStr,
N::Err: Display,
{
match self {
Value::Literal(Lit::Float(n)) => n.base10_parse().ok(),
_ => None,
}
}
pub fn as_literal(&self) -> Option<&Lit> {
match self {
Value::Literal(x) => Some(x),
_ => None,
}
}
pub fn as_array(&self) -> Option<&[Lit]> {
match self {
Value::Array(x) => Some(x.as_slice()),
_ => None,
}
}
pub fn parse_literal<T: FromStr>(&self) -> Option<T> {
match self {
Value::Literal(x) => {
let value = lit_to_string(x);
T::from_str(&value).ok()
}
_ => None,
}
}
pub fn parse_array<T: FromStr>(&self) -> Option<Vec<T>> {
match self {
Value::Array(array) => {
let mut ret = Vec::new();
for arg in array {
let value = lit_to_string(arg);
let n = T::from_str(&value).ok()?;
ret.push(n);
}
Some(ret)
}
_ => None,
}
}
pub fn display<W: Write>(
&self,
formatter: &mut W,
use_array_brackets: bool,
) -> std::fmt::Result {
match self {
Value::Literal(lit) => display_lit(formatter, lit),
Value::Array(array) => {
let result = array
.iter()
.map(|s| lit_to_string(s))
.collect::<Vec<String>>();
if use_array_brackets {
write!(formatter, "[{}]", result.join(", "))
} else {
write!(formatter, "{}", result.join(", "))
}
}
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.display(f, true)
}
}