optics 0.3.0

A no_std-compatible optics library providing composable lenses, prisms, isomorphisms, and fallible isomorphisms.
Documentation
use crate::test::helpers;
use convert_case::{Case, Casing};
use syn::visit::Visit;
use syn::{ItemFn, ItemMod, ItemStruct, Visibility, visit};

/// Verifies that no API leakage occurs.
#[test]
fn optic_implementations_exported_struct_and_fns() {
    #[derive(Default)]
    struct Check {
        current_module: Vec<String>,
    }

    impl<'ast> Visit<'ast> for Check {
        fn visit_item_mod(&mut self, i: &'ast ItemMod) {
            self.current_module.push(i.ident.to_string());
            visit::visit_item_mod(self, i);
            self.current_module.pop();
        }

        fn visit_item_struct(&mut self, i: &'ast ItemStruct) {
            if let Visibility::Public(_) = i.vis {
                match self
                    .current_module
                    .iter()
                    .map(std::string::String::as_str)
                    .collect::<Vec<_>>()
                    .as_slice()
                {
                    [.., "mapped" | "composed"] => {
                        panic!(
                            "Found public struct in module {}::{}",
                            self.current_module.join("::"),
                            i.ident
                        );
                    }
                    [.., "wrapped"] => {
                        let optic_type = self
                            .current_module
                            .get(self.current_module.len() - 2)
                            .unwrap()
                            .as_str()
                            .to_case(Case::UpperCamel);

                        let expected_exported_type = format!("{optic_type}Impl");

                        assert!(
                            i.ident == expected_exported_type,
                            "Found public struct in module {}::{} that is not a {}Impl",
                            self.current_module.join("::"),
                            i.ident,
                            optic_type
                        );
                    }
                    _ => (),
                }
            }
        }

        fn visit_item_fn(&mut self, i: &'ast ItemFn) {
            if let Visibility::Public(_) = i.vis {
                match self
                    .current_module
                    .iter()
                    .map(std::string::String::as_str)
                    .collect::<Vec<_>>()
                    .as_slice()
                {
                    [.., "mapped" | "composed"] => {
                        assert!(
                            i.sig.ident == "new",
                            "Found public fn in module {}::{} that is not new()",
                            self.current_module.join("::"),
                            i.sig.ident
                        );
                    }

                    [optic_type] => {
                        let expected_exported_type = format!("identity_{optic_type}");

                        assert!(
                            i.sig.ident == expected_exported_type,
                            "Found public fn in module {}::{} that is not {}",
                            self.current_module.join("::"),
                            i.sig.ident,
                            expected_exported_type
                        );
                    }

                    _ => (),
                }
            }
        }
    }

    helpers::CRATE_AST.with(|syn| Check::default().visit_file(syn));
}