enum-tools 0.5.5

Automatically derive functions and trait implementations for enums
Documentation
use crate::feature::iter::{extend_common, FeatureIter};
use crate::generator::names::Names;
use crate::generator::Derive;
use proc_macro2::{Span, TokenStream};
use proc_macro_error::abort;
use quote::{quote, ToTokens};
use syn::LitInt;

impl FeatureIter {
    pub(crate) fn check_range(&self, derive: &Derive) {
        if derive.mode.is_with_holes() {
            abort!(
                self.span,
                "mode range is only valid when the enum is gapless"
            );
        }
    }

    pub(crate) fn iter_range(&self, derive: &Derive, names: &Names) -> (TokenStream, TokenStream) {
        let Derive {
            repr,
            vis_enum,
            max_key,
            min_key,
            ..
        } = derive;
        let start = LitInt::new(&format!("{min_key}{repr}"), Span::call_site());
        let end = LitInt::new(&format!("{max_key}{repr}"), Span::call_site());

        let Derive {
            repr, ident_enum, ..
        } = derive;
        let Names {
            ident_iter_fn,
            ident_iter_struct,
            ..
        } = names;
        let vis = self.vis.as_ref().unwrap_or(vis_enum);

        let doc_inner = format!(" An Iterator over the items of {ident_enum}, in value order.");
        let doc_outer = format!(" An Iterator over the items of {ident_enum}.");

        let inner = quote! {
            #[doc=#doc_inner]
            #[inline]
            #vis fn #ident_iter_fn() -> #ident_iter_struct {
                use ::core::iter::Iterator;
                #ident_iter_struct {
                    // Safety: the number is known to be a valid enum
                    inner: (#start..=#end).map(|x| unsafe { ::core::mem::transmute(x) }),
                }
            }
        };

        let mut outer = quote! {
            #[doc=#doc_outer]
            #vis struct #ident_iter_struct {
                inner: ::core::iter::Map<::core::ops::RangeInclusive<#repr>, fn(#repr) -> #ident_enum>
            }
        };

        extend_common(
            &mut outer,
            ident_enum.to_token_stream(),
            ident_iter_struct,
            true,
        );

        (inner, outer)
    }
}