use std::fmt::{Debug, Formatter, self};
use std::convert::TryInto;
use syn::{
Type, Ident, Path, Lit, LitStr, LitByteStr, LitBool, LitChar, LitInt, LitFloat, TypePath,
PathSegment,
};
use syn::parse::{Parse, Parser};
use proc_macro2::Span;
use quote::{ToTokens};
use crate::{Error, ValueClass};
#[derive(Clone)]
pub enum ArgValue {
Literal(Lit),
Type(Type),
None,
}
impl Debug for ArgValue {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ArgValue::Literal(lit) => write!(f, "ArgValue::Literal({})", lit.to_token_stream()),
ArgValue::Type(ty) => write!(f, "ArgValue::Type({})", ty.to_token_stream()),
ArgValue::None => f.write_str("ArgValue::None"),
}
}
}
impl From<&str> for ArgValue {
fn from(val: &str) -> Self {
ArgValue::Literal(Lit::Str(LitStr::new(val, Span::call_site())))
}
}
impl From<String> for ArgValue {
fn from(val: String) -> Self {
ArgValue::Literal(Lit::Str(LitStr::new(&val, Span::call_site())))
}
}
impl From<&[u8]> for ArgValue {
fn from(val: &[u8]) -> Self {
ArgValue::Literal(Lit::ByteStr(LitByteStr::new(val, Span::call_site())))
}
}
impl From<Vec<u8>> for ArgValue {
fn from(val: Vec<u8>) -> Self {
ArgValue::Literal(Lit::ByteStr(LitByteStr::new(&val, Span::call_site())))
}
}
impl From<char> for ArgValue {
fn from(val: char) -> Self {
ArgValue::Literal(Lit::Char(LitChar::new(val, Span::call_site())))
}
}
impl From<usize> for ArgValue {
fn from(val: usize) -> Self {
ArgValue::Literal(Lit::Int(LitInt::new(&val.to_string(), Span::call_site())))
}
}
impl From<isize> for ArgValue {
fn from(val: isize) -> Self {
ArgValue::Literal(Lit::Int(LitInt::new(&val.to_string(), Span::call_site())))
}
}
impl From<f64> for ArgValue {
fn from(val: f64) -> Self {
ArgValue::Literal(Lit::Float(LitFloat::new(
&val.to_string(),
Span::call_site(),
)))
}
}
impl From<Option<LitStr>> for ArgValue {
fn from(val: Option<LitStr>) -> Self {
match val {
Some(val) => ArgValue::Literal(Lit::Str(val)),
None => ArgValue::None,
}
}
}
impl From<Ident> for ArgValue {
fn from(ident: Ident) -> Self {
Path::from(PathSegment::parse.parse(quote! { #ident }.into()).unwrap()).into()
}
}
impl From<Path> for ArgValue {
fn from(path: Path) -> Self {
ArgValue::Type(Type::Path(TypePath { qself: None, path }))
}
}
impl From<Option<LitByteStr>> for ArgValue {
fn from(val: Option<LitByteStr>) -> Self {
match val {
Some(val) => ArgValue::Literal(Lit::ByteStr(val)),
None => ArgValue::None,
}
}
}
impl From<Option<LitBool>> for ArgValue {
fn from(val: Option<LitBool>) -> Self {
match val {
Some(val) => ArgValue::Literal(Lit::Bool(val)),
None => ArgValue::None,
}
}
}
impl From<Option<LitChar>> for ArgValue {
fn from(val: Option<LitChar>) -> Self {
match val {
Some(val) => ArgValue::Literal(Lit::Char(val)),
None => ArgValue::None,
}
}
}
impl From<Option<LitInt>> for ArgValue {
fn from(val: Option<LitInt>) -> Self {
match val {
Some(val) => ArgValue::Literal(Lit::Int(val)),
None => ArgValue::None,
}
}
}
impl From<Option<LitFloat>> for ArgValue {
fn from(val: Option<LitFloat>) -> Self {
match val {
Some(val) => ArgValue::Literal(Lit::Float(val)),
None => ArgValue::None,
}
}
}
impl TryInto<String> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<String, Self::Error> {
match self {
ArgValue::Literal(Lit::Str(s)) => Ok(s.value()),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Vec<u8>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Vec<u8>, Self::Error> {
match self {
ArgValue::Literal(Lit::ByteStr(s)) => Ok(s.value()),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<bool> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<bool, Self::Error> {
match self {
ArgValue::Literal(Lit::Bool(b)) => Ok(b.value),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<char> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<char, Self::Error> {
match self {
ArgValue::Literal(Lit::Char(c)) => Ok(c.value()),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<LitStr> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<LitStr, Self::Error> {
match self {
ArgValue::Literal(Lit::Str(s)) => Ok(s),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<LitByteStr> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<LitByteStr, Self::Error> {
match self {
ArgValue::Literal(Lit::ByteStr(s)) => Ok(s),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<LitBool> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<LitBool, Self::Error> {
match self {
ArgValue::Literal(Lit::Bool(s)) => Ok(s),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<LitChar> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<LitChar, Self::Error> {
match self {
ArgValue::Literal(Lit::Char(c)) => Ok(c),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<LitInt> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<LitInt, Self::Error> {
match self {
ArgValue::Literal(Lit::Int(i)) => Ok(i),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<LitFloat> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<LitFloat, Self::Error> {
match self {
ArgValue::Literal(Lit::Float(f)) => Ok(f),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Ident> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Ident, Self::Error> {
match self {
ArgValue::Type(Type::Path(ty)) => {
if let Some(ident) = ty.path.get_ident() {
Ok(ident.clone())
} else {
Err(Error::ArgValueMustBeType)
}
}
_ => Err(Error::ArgValueMustBeType),
}
}
}
impl TryInto<Path> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Path, Self::Error> {
match self {
ArgValue::Type(Type::Path(ty)) => Ok(ty.path),
_ => Err(Error::ArgValueMustBeType),
}
}
}
impl TryInto<Option<LitStr>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<LitStr>, Self::Error> {
match self {
ArgValue::Literal(Lit::Str(s)) => Ok(Some(s)),
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Option<LitByteStr>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<LitByteStr>, Self::Error> {
match self {
ArgValue::Literal(Lit::ByteStr(s)) => Ok(Some(s)),
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Option<LitBool>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<LitBool>, Self::Error> {
match self {
ArgValue::Literal(Lit::Bool(b)) => Ok(Some(b)),
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Option<LitChar>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<LitChar>, Self::Error> {
match self {
ArgValue::Literal(Lit::Char(c)) => Ok(Some(c)),
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Option<LitInt>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<LitInt>, Self::Error> {
match self {
ArgValue::Literal(Lit::Int(i)) => Ok(Some(i)),
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Option<LitFloat>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<LitFloat>, Self::Error> {
match self {
ArgValue::Literal(Lit::Float(f)) => Ok(Some(f)),
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeLiteral),
}
}
}
impl TryInto<Option<Ident>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<Ident>, Self::Error> {
match self {
ArgValue::Type(Type::Path(ty)) => {
if let Some(ident) = ty.path.get_ident() {
Ok(Some(ident.clone()))
} else {
Err(Error::ArgValueMustBeType)
}
}
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeType),
}
}
}
impl TryInto<Option<Path>> for ArgValue {
type Error = Error;
fn try_into(self) -> Result<Option<Path>, Self::Error> {
match self {
ArgValue::Type(Type::Path(ty)) => Ok(Some(ty.path)),
ArgValue::None => Ok(None),
_ => Err(Error::ArgValueMustBeType),
}
}
}
impl ArgValue {
#[inline]
pub fn literal_value(&self) -> Result<Lit, Error> {
match self {
ArgValue::Literal(lit) => Ok(lit.clone()),
ArgValue::Type(_) | ArgValue::None => Err(Error::ArgValueMustBeLiteral),
}
}
#[inline]
pub fn type_value(&self) -> Result<Type, Error> {
match self {
ArgValue::Literal(_) | ArgValue::None => Err(Error::ArgValueMustBeType),
ArgValue::Type(ty) => Ok(ty.clone()),
}
}
#[inline]
pub fn is_none(&self) -> bool {
match self {
ArgValue::None => true,
_ => false,
}
}
#[inline]
pub fn is_some(&self) -> bool {
match self {
ArgValue::None => false,
_ => true,
}
}
#[inline]
pub fn value_class(&self) -> Option<ValueClass> {
match self {
ArgValue::Literal(lit) => Some(ValueClass::from(lit)),
ArgValue::Type(ty) => Some(ValueClass::from(ty)),
ArgValue::None => None,
}
}
}