use std::fmt::{Debug, Display, Formatter};
use quote::ToTokens;
use syn::{Path, Type, TypeParamBound, TypePath};
use syn::__private::TokenStream2;
use crate::ast::AddPunctuated;
use crate::kind::{CallbackKind, SmartPointerKind};
use crate::ext::{AsType, MaybeAngleBracketedArgs, MaybeGenericType};
#[derive(Clone, PartialEq, Eq)]
pub enum GenericTypeKind {
Map(Type),
Group(Type),
Result(Type),
Box(Type),
SmartPointer(SmartPointerKind),
Cow(Type),
AnyOther(Type),
Array(Type),
Slice(Type),
Tuple(Type),
Optional(Type),
Callback(CallbackKind),
TraitBounds(AddPunctuated<TypeParamBound>),
}
impl Debug for GenericTypeKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("GenericTypeKind::{}({})", match self {
GenericTypeKind::Map(_) => "Map",
GenericTypeKind::Group(_) => "Group",
GenericTypeKind::Result(_) => "Result",
GenericTypeKind::Box(_) => "Box",
GenericTypeKind::Cow(_) => "Cow",
GenericTypeKind::SmartPointer(_) => "SmartPointer",
GenericTypeKind::AnyOther(_) => "AnyOther",
GenericTypeKind::Array(_) => "Array",
GenericTypeKind::Slice(_) => "Slice",
GenericTypeKind::Tuple(_) => "Tuple",
GenericTypeKind::Callback(_) => "Callback",
GenericTypeKind::TraitBounds(_) => "TraitBounds",
GenericTypeKind::Optional(_) => "Optional"
}, self.to_token_stream()))
}
}
impl Display for GenericTypeKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
impl ToTokens for GenericTypeKind {
fn to_tokens(&self, tokens: &mut TokenStream2) {
match self {
GenericTypeKind::Map(ty) |
GenericTypeKind::Group(ty) |
GenericTypeKind::Result(ty) |
GenericTypeKind::Box(ty) |
GenericTypeKind::Array(ty) |
GenericTypeKind::Slice(ty) |
GenericTypeKind::AnyOther(ty) |
GenericTypeKind::Optional(ty) |
GenericTypeKind::Cow(ty) |
GenericTypeKind::Tuple(ty) => ty.to_tokens(tokens),
GenericTypeKind::SmartPointer(kind) => kind.to_tokens(tokens),
GenericTypeKind::Callback(kind) => kind.to_tokens(tokens),
GenericTypeKind::TraitBounds(bounds) => bounds.to_tokens(tokens),
}
}
}
impl GenericTypeKind {
pub fn ty(&self) -> Option<&Type> {
match self {
GenericTypeKind::Map(ty) |
GenericTypeKind::Group(ty) |
GenericTypeKind::Result(ty) |
GenericTypeKind::Box(ty) |
GenericTypeKind::Array(ty) |
GenericTypeKind::Slice(ty) |
GenericTypeKind::AnyOther(ty) |
GenericTypeKind::Cow(ty) |
GenericTypeKind::Tuple(ty) => Some(ty),
GenericTypeKind::Optional(Type::Path(TypePath { path: Path { segments, .. }, .. })) =>
segments.last()
.and_then(MaybeAngleBracketedArgs::maybe_angle_bracketed_args)
.and_then(MaybeGenericType::maybe_generic_type),
GenericTypeKind::Callback(kind) => Some(kind.as_type()),
GenericTypeKind::TraitBounds(_) => {
None
},
GenericTypeKind::SmartPointer(ptr) => Some(ptr.as_type()),
conversion => panic!("TODO: Non-supported generic kind: {}", conversion),
}
}
}