generic-array-struct 0.3.3

An attribute proc macro to convert structs with named fields of the same generic type into a single-array-field tuple struct with array-index-based accessor and mutator methods.
Documentation
use quote::quote;

use crate::GenericArrayStructParams;

/// Outputs the token stream to append
pub(crate) fn impl_trymap(params: &GenericArrayStructParams) -> proc_macro2::TokenStream {
    let struct_id = params.struct_ident();

    quote! {
        impl<T> #struct_id <T> {
            #[inline]
            pub fn try_map_opt<B, F>(
                self,
                mut f: F,
            ) -> Option<#struct_id <B>> where F: FnMut(T) -> Option<B> {
                let mut res: #struct_id <core::mem::MaybeUninit<B>>
                    = #struct_id (core::array::from_fn(|_| core::mem::MaybeUninit::uninit()));
                let written = self.0.into_iter().zip(res.0.iter_mut()).try_fold(
                    0usize,
                    |written, (val, rmut)| {
                        rmut.write(f(val).ok_or(written)?);
                        Ok(written + 1)
                    }
                );
                match written {
                    Ok(_) => Some(#struct_id (
                        unsafe {
                            core::mem::transmute_copy::<_, _>(
                                &core::mem::ManuallyDrop::new(res.0)
                            )
                        }
                    )),
                    Err(written) => {
                        res.0.iter_mut().take(written).for_each(
                            |mu| unsafe { mu.assume_init_drop() }
                        );
                        None
                    }
                }
            }

            #[inline]
            pub fn try_map_res<B, E, F>(
                self,
                mut f: F,
            ) -> Result<#struct_id <B>, E> where F: FnMut(T) -> Result<B, E> {
                let mut res: #struct_id <core::mem::MaybeUninit<B>>
                    = #struct_id (core::array::from_fn(|_| core::mem::MaybeUninit::uninit()));
                let written = self.0.into_iter().zip(res.0.iter_mut()).try_fold(
                    0usize,
                    |written, (val, rmut)| {
                        rmut.write(f(val).map_err(|e| (e, written))?);
                        Ok(written + 1)
                    }
                );
                match written {
                    Ok(_) => Ok(#struct_id (
                        unsafe {
                            core::mem::transmute_copy::<_, _>(
                                &core::mem::ManuallyDrop::new(res.0)
                            )
                        }
                    )),
                    Err((e, written)) => {
                        res.0.iter_mut().take(written).for_each(
                            |mu| unsafe { mu.assume_init_drop() }
                        );
                        Err(e)
                    }
                }
            }
        }
    }
}