enum_delegate_lib 0.2.0

Internal macro implementations for enum_delegate - use to implement your own macros
Documentation
use proc_macro2::Ident;
use syn::spanned::Spanned;
use syn::{Fields, ItemEnum, Type, Variant};

use crate::error::InvalidInput;

/// A "parsed" version of an enum that has been checked to have a single field in each variant.
///
/// It is also guaranteed to have at least one variant
pub(crate) struct SingleFieldEnum {
    /// Always has at least 1 variant
    variants: Vec<SingleFieldVariant>,
}

impl SingleFieldEnum {
    /// Get the first variant
    ///
    /// Never fails, as all [`SingleFieldEnum`]s have at least 1 variant
    pub fn first_variant(&self) -> &SingleFieldVariant {
        &self.variants[0]
    }

    /// A slice of all variants
    pub fn variants(&self) -> &[SingleFieldVariant] {
        &self.variants
    }
}

/// An enum variant that has been checked to have a single field
pub(crate) struct SingleFieldVariant {
    pub name: Ident,
    pub type_: Type,
}

/// Parse a `SingleFieldEnum` from the specified `ItemEnum`
///
/// This function validates that the provided enum is in a form accepted by this library, and formats it in a struct that is easy to use by the rest of the codebase
pub(crate) fn parse_enum_variants(enum_: &ItemEnum) -> Result<SingleFieldEnum, InvalidInput> {
    let variants: Result<Vec<_>, _> = enum_
        .variants
        .iter()
        .map(|variant| {
            Ok(SingleFieldVariant {
                name: variant.ident.clone(),
                type_: get_variant_only_field_type(variant)?.clone(),
            })
        })
        .collect();
    let variants = variants?;

    if variants.is_empty() {
        return Err(InvalidInput::NoVariants(enum_.span()));
    }

    Ok(SingleFieldEnum { variants })
}

/// Given a variant,
///
/// - Make sure that it is a single-field tuple variant (error otherwise)
/// - Return the type of its only field
fn get_variant_only_field_type(variant: &Variant) -> Result<&Type, InvalidInput> {
    match &variant.fields {
        Fields::Unnamed(f) if f.unnamed.len() == 1 => Ok(&f.unnamed[0].ty),
        _ => Err(InvalidInput::InvalidVariant(variant.span())),
    }
}