// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//! Records, unlike the previous "records" crate, simply make all struct fields public
//! To get other functionality, use additional attributes

use proc_macro::TokenStream;
use quote::ToTokens;

fn pub_visibility() -> syn::Visibility {
    syn::Visibility::Public(syn::VisPublic {
        pub_token: <syn::Token![pub]>::default(),
    })
}

fn make_all_pub<'a>(fields: impl IntoIterator<Item = &'a mut syn::Field>) {
    for field in fields {
        if matches!(field.vis, syn::Visibility::Inherited)
            && !field
                .ident
                .as_ref()
                .filter(|it| it.to_string().starts_with("_"))
                .is_some()
        {
            field.vis = pub_visibility();
        }
    }
}

pub fn record(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let mut strct = syn::parse_macro_input!(item as syn::ItemStruct);

    match strct.fields {
        syn::Fields::Named(ref mut fields) => make_all_pub(fields.named.iter_mut()),
        syn::Fields::Unnamed(ref mut fields) => make_all_pub(fields.unnamed.iter_mut()),
        _ => panic!("Tried to make unit struct {} into a record!", strct.ident),
    };

    strct.to_token_stream().into()
}
