use syn;
use {FromField, FromVariant, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Body<V = (), F = ()> {
Enum(Vec<V>),
Struct(VariantData<F>),
}
impl<V, F> Body<V, F> {
pub fn empty_from(src: &syn::Body) -> Self {
match *src {
syn::Body::Enum(_) => Body::Enum(vec![]),
syn::Body::Struct(ref vd) => Body::Struct(VariantData::empty_from(vd)),
}
}
pub fn as_ref<'a>(&'a self) -> Body<&'a V, &'a F> {
match *self {
Body::Enum(ref variants) => Body::Enum(variants.into_iter().collect()),
Body::Struct(ref data) => Body::Struct(data.as_ref()),
}
}
pub fn map_enum_variants<T, U>(self, map: T) -> Body<U, F>
where T: FnMut(V) -> U
{
match self {
Body::Enum(v) => Body::Enum(v.into_iter().map(map).collect()),
Body::Struct(f) => Body::Struct(f),
}
}
pub fn map_struct_fields<T, U>(self, map: T) -> Body<V, U>
where T: FnMut(F) -> U
{
match self {
Body::Enum(v) => Body::Enum(v),
Body::Struct(f) => Body::Struct(f.map(map)),
}
}
pub fn map_struct<T, U>(self, mut map: T) -> Body<V, U>
where T: FnMut(VariantData<F>) -> VariantData<U>
{
match self {
Body::Enum(v) => Body::Enum(v),
Body::Struct(f) => Body::Struct(map(f)),
}
}
pub fn take_struct(self) -> Option<VariantData<F>> {
match self {
Body::Enum(_) => None,
Body::Struct(f) => Some(f),
}
}
pub fn take_enum(self) -> Option<Vec<V>> {
match self {
Body::Enum(v) => Some(v),
Body::Struct(_) => None,
}
}
pub fn is_enum(&self) -> bool {
match *self {
Body::Enum(_) => true,
Body::Struct(_) => false,
}
}
pub fn is_struct(&self) -> bool {
!self.is_enum()
}
}
impl<V: FromVariant, F: FromField> Body<V, F> {
pub fn try_from(body: &syn::Body) -> Result<Self> {
match *body {
syn::Body::Enum(ref variants) => {
Ok(Body::Enum(variants.into_iter()
.map(FromVariant::from_variant)
.collect::<Result<_>>()?))
}
syn::Body::Struct(ref data) => Ok(Body::Struct(VariantData::try_from(data)?)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantData<T> {
pub style: Style,
pub fields: Vec<T>,
}
impl<T> VariantData<T> {
pub fn empty_from(vd: &syn::VariantData) -> Self {
VariantData {
style: vd.into(),
fields: Vec::new(),
}
}
pub fn split(self) -> (Style, Vec<T>) {
(self.style, self.fields)
}
pub fn is_newtype(&self) -> bool {
self.style == Style::Tuple && self.fields.len() == 1
}
pub fn is_unit(&self) -> bool {
self.style.is_unit()
}
pub fn is_tuple(&self) -> bool {
self.style.is_tuple()
}
pub fn is_struct(&self) -> bool {
self.style.is_struct()
}
pub fn as_ref<'a>(&'a self) -> VariantData<&'a T> {
VariantData {
style: self.style,
fields: self.fields.iter().collect(),
}
}
pub fn map<F, U>(self, map: F) -> VariantData<U> where F: FnMut(T) -> U {
VariantData {
style: self.style,
fields: self.fields.into_iter().map(map).collect()
}
}
}
impl<F: FromField> VariantData<F> {
pub fn try_from(data: &syn::VariantData) -> Result<Self> {
Ok(VariantData {
style: data.into(),
fields: data.fields()
.into_iter()
.map(FromField::from_field)
.collect::<Result<Vec<F>>>()?,
})
}
}
impl<T> From<Style> for VariantData<T> {
fn from(style: Style) -> Self {
VariantData {
style,
fields: Vec::new(),
}
}
}
impl<T, U: Into<Vec<T>>> From<(Style, U)> for VariantData<T> {
fn from((style, fields): (Style, U)) -> Self {
style.with_fields(fields)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Style {
Tuple,
Struct,
Unit,
}
impl Style {
pub fn is_unit(&self) -> bool {
*self == Style::Unit
}
pub fn is_tuple(&self) -> bool {
*self == Style::Tuple
}
pub fn is_struct(&self) -> bool {
*self == Style::Struct
}
fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> VariantData<T> {
VariantData {
style: self,
fields: fields.into(),
}
}
}
impl From<syn::VariantData> for Style {
fn from(vd: syn::VariantData) -> Self {
(&vd).into()
}
}
impl<'a> From<&'a syn::VariantData> for Style {
fn from(vd: &syn::VariantData) -> Self {
match *vd {
syn::VariantData::Struct(_) => Style::Struct,
syn::VariantData::Tuple(_) => Style::Tuple,
syn::VariantData::Unit => Style::Unit,
}
}
}