dtolnay / inventory

Typed distributed plugin registration
Apache License 2.0
948 stars 43 forks source link

module submit doesn't work when coming from macro #35

Closed mimoo closed 2 years ago

mimoo commented 2 years ago

Hey! I've been setting up the inventory stuff via a macro from another crate:

#[proc_macro]
pub fn init_gen(_item: TokenStream) -> TokenStream {
    r#"
    use ::ocaml::inventory;

    pub struct OcamlFunc {
        pub module: &'static str,
        pub name: &'static str,
        pub args: Vec<&'static str>,
    }

    impl OcamlFunc {
        pub fn new(module: &'static str, name: &'static str, args: Vec<&'static str>) -> Self {
            OcamlFunc { module, name, args }
        }
    }

    pub fn gen_ocaml_bindings() {
        // group by module

        // generate .ml code
        for flag in inventory::iter::<OcamlFunc> {
            println!("module {} = struct external {}: unit -> string = \"{}\" end", flag.module, flag.name, flag.name);
        }
    }

// this works
    inventory::submit! {
        OcamlFunc::new("init", "test init", vec!["t: int"])
    }

    // this doesn't work v
    pub mod inside_mod {
        use super::*;
        inventory::submit! {
            OcamlFunc::new("init2", "test init inside mod", vec!["t: int"])
        }

    }

    inventory::collect!(OcamlFunc);
    "#
    .parse()
    .unwrap()
}

and it seems to work except when I try to submit from inside another module. Here's the code from the proc macro crate, but doing it from inside another module where I call

ocaml::init_gen!();

// this works
inventory::submit! {
    OcamlFunc::new("init3", "test init inside mod", vec!["t: int"])
}

pub mod a {
    use super::*;

// this doesn't work
    inventory::submit! {
        OcamlFunc::new("init4", "test init inside mod", vec!["t: int"])
    }
}
mimoo commented 2 years ago

This is really troubling me. This is an expanded example that works:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
pub struct Flag {
    short: char,
    name: &'static str,
    /* ... */
}

impl Flag {
    pub fn new(short: char, name: &'static str) -> Self { Flag{short, name,} }
}

#[allow(non_upper_case_globals)]
extern fn __init12616011980604515118() {
    inventory::submit({ Flag::new('v', "verbose") });
}
#[used]
#[allow(non_upper_case_globals)]
#[doc(hidden)]
#[link_section = "__DATA,__mod_init_func"]
static __init12616011980604515118___rust_ctor___ctor: unsafe extern "C" fn() =
    {
        unsafe extern "C" fn __init12616011980604515118___rust_ctor___ctor() {
            __init12616011980604515118()
        }
        ;
        __init12616011980604515118___rust_ctor___ctor
    };
mod a {
    use super::Flag;
    #[allow(non_upper_case_globals)]
    extern fn __init3632956075760860679() {
        inventory::submit({ Flag::new('l', "loose") });
    }
    #[used]
    #[allow(non_upper_case_globals)]
    #[doc(hidden)]
    #[link_section = "__DATA,__mod_init_func"]
    static __init3632956075760860679___rust_ctor___ctor:
     unsafe extern "C" fn() =
        {
            unsafe extern "C" fn __init3632956075760860679___rust_ctor___ctor() {
                __init3632956075760860679()
            }
            ;
            __init3632956075760860679___rust_ctor___ctor
        };
}
impl ::inventory::Collect for Flag {
    #[inline]
    fn registry() -> &'static ::inventory::Registry<Self> {
        static REGISTRY: ::inventory::Registry<Flag> =
            ::inventory::Registry::new();
        &REGISTRY
    }
}
fn main() {
    for flag in inventory::iter::<Flag> {
        {
            ::std::io::_print(match match (&flag.short, &flag.name) {
                                        (arg0, arg1) =>
                                        [::core::fmt::ArgumentV1::new(arg0,
                                                                      ::core::fmt::Display::fmt),
                                         ::core::fmt::ArgumentV1::new(arg1,
                                                                      ::core::fmt::Display::fmt)],
                                    } {
                                  ref args => unsafe {
                                      ::core::fmt::Arguments::new_v1(&["-",
                                                                       ", --",
                                                                       "\n"],
                                                                     args)
                                  }
                              });
        };
    }
}

and this is my expanded example that doesn't work:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
use ::ocaml::inventory;
pub struct OcamlFunc {
    pub module: &'static str,
    pub name: &'static str,
    pub args: Vec<&'static str>,
}
impl OcamlFunc {
    pub fn new(module: &'static str, name: &'static str,
               args: Vec<&'static str>) -> Self {
        OcamlFunc{module, name, args,}
    }
}
pub fn gen_ocaml_bindings() {
    for flag in inventory::iter::<OcamlFunc> {

        /*
        #[ocaml::func]
        pub fn hello_world() -> &'static str {
            "hello, world!"
        }

        #[ocaml::func]
        pub fn second_one() -> &'static str {
            "hello, world!"
        }
        */

        /*
        #[ocaml::func]
        pub fn third_one() {}
        */

        {
            ::std::io::_print(match match (&flag.module, &flag.name,
                                           &flag.name) {
                                        (arg0, arg1, arg2) =>
                                        [::core::fmt::ArgumentV1::new(arg0,
                                                                      ::core::fmt::Display::fmt),
                                         ::core::fmt::ArgumentV1::new(arg1,
                                                                      ::core::fmt::Display::fmt),
                                         ::core::fmt::ArgumentV1::new(arg2,
                                                                      ::core::fmt::Display::fmt)],
                                    } {
                                  ref args => unsafe {
                                      ::core::fmt::Arguments::new_v1(&["module ",
                                                                       " = struct external ",
                                                                       ": unit -> string = \"",
                                                                       "\" end\n"],
                                                                     args)
                                  }
                              });
        };
    }
}
#[allow(non_upper_case_globals)]
extern fn __init7240165574856463891() {
    inventory::submit({
                          OcamlFunc::new("init", "test init",
                                         <[_]>::into_vec(box ["t: int"]))
                      });
}
#[used]
#[allow(non_upper_case_globals)]
#[doc(hidden)]
#[link_section = "__DATA,__mod_init_func"]
static __init7240165574856463891___rust_ctor___ctor: unsafe extern "C" fn() =
    {
        unsafe extern "C" fn __init7240165574856463891___rust_ctor___ctor() {
            __init7240165574856463891()
        }
        ;
        __init7240165574856463891___rust_ctor___ctor
    };
pub mod inside_mod {
    use super::*;
    #[allow(non_upper_case_globals)]
    extern fn __init16324153154278459067() {
        inventory::submit({
                              OcamlFunc::new("init2", "test init inside mod",
                                             <[_]>::into_vec(box ["t: int"]))
                          });
    }
    #[used]
    #[allow(non_upper_case_globals)]
    #[doc(hidden)]
    #[link_section = "__DATA,__mod_init_func"]
    static __init16324153154278459067___rust_ctor___ctor:
     unsafe extern "C" fn() =
        {
            unsafe extern "C" fn __init16324153154278459067___rust_ctor___ctor() {
                __init16324153154278459067()
            }
            ;
            __init16324153154278459067___rust_ctor___ctor
        };
}
impl ::inventory::Collect for OcamlFunc {
    #[inline]
    fn registry() -> &'static ::inventory::Registry<Self> {
        static REGISTRY: ::inventory::Registry<OcamlFunc> =
            ::inventory::Registry::new();
        &REGISTRY
    }
}
#[allow(non_upper_case_globals)]
extern fn __init9752370030967368522() {
    inventory::submit({
                          OcamlFunc::new("init3", "test init inside mod",
                                         <[_]>::into_vec(box ["t: int"]))
                      });
}
#[used]
#[allow(non_upper_case_globals)]
#[doc(hidden)]
#[link_section = "__DATA,__mod_init_func"]
static __init9752370030967368522___rust_ctor___ctor: unsafe extern "C" fn() =
    {
        unsafe extern "C" fn __init9752370030967368522___rust_ctor___ctor() {
            __init9752370030967368522()
        }
        ;
        __init9752370030967368522___rust_ctor___ctor
    };
pub mod a {
    use super::*;
    #[allow(non_upper_case_globals)]
    extern fn __init7342976490476293494() {
        inventory::submit({
                              OcamlFunc::new("init4", "test init inside mod",
                                             <[_]>::into_vec(box ["t: int"]))
                          });
    }
    #[used]
    #[allow(non_upper_case_globals)]
    #[doc(hidden)]
    #[link_section = "__DATA,__mod_init_func"]
    static __init7342976490476293494___rust_ctor___ctor:
     unsafe extern "C" fn() =
        {
            unsafe extern "C" fn __init7342976490476293494___rust_ctor___ctor() {
                __init7342976490476293494()
            }
            ;
            __init7342976490476293494___rust_ctor___ctor
        };
}
dtolnay commented 2 years ago

seems to work except when I try to submit from inside another module

I believe this is a duplicate of #9.