Skip to content

Commit 4db0d49

Browse files
committed
Implement bind_class macro under examples/bind-class-test
This implements a `bind_class!()` macro via `macro_rules` that can be used like: ``` bind_class! { "foo.bar.Baz" as JTest2 { api = CustomJTest2API, raw = jthrowable, as = [ string = JString, JObject ], native_trait = CustomJTest2Natives, native_trait_impl = CustomJTest2NativesImpl, native_error_policy = ThrowRuntimeExAndDefault, priv = JTest2Priv, impl = { load_class = |env, load_context, initialize| { load_context.load_class_for_type::<JTest2>(initialize, env) }, init_priv = |env, class, load_context | { println!("Priv init called for JTest2"); Ok(JTest2Priv) } }, constructors = { constructor1 = { sig = (), vis = pub(self) }, constructor2 = { sig = (a: jint) }, }, static_native_methods = { static_native_method1 = { name = "nativeStaticFoo", sig = (arg0: java.lang.String) -> jint }, }, native_methods = { native_method1 = { sig = (arg0: java.lang.String) -> jint }, native_method2 = { sig = (arg0: java.lang.String) -> jint, //fn = my_native_method2_impl, error_policy = LogErrorAndDefault, vis = pub }, }, static_methods = { static_method1 = { name = "createInstance", sig = () -> JString }, }, methods = { method1 = { name = "getValue", sig = () -> ([[jint]]) }, method2 = { sig = (a: jint, b: java.lang.String as JString, c: jboolean) -> JString }, }, static_fields = { static_field1 = { sig = (java.lang.String) }, }, fields = { field1 = { name = "value", sig = jint }, field_name = { sig = JString }, }, } } ``` Apart from some issues with handling the mangling of native methods (which is tricky to manage within a macro_rules macro) this all works but _sheesh_ it was pretty complex to get this working, with lots of backtracking to work within the limitations of macro_rules. Some of the challenges: We can't heavily rely on tt-munching without hitting recursion limits, so this has a verbose workaround for finding properties without recursion. In general the lack of tail call optimisation for tt munching in macro_rules really constrains the syntax that can practically be supported by the macro. The lazy expansion of sub-macros (where you have to ensure that code is valid at each level of expansion) is difficult to manage and leads to awkward auto-complete expansions with rust-analyzer (if you ask it to fill out a blank implementation of the trait for native methods then it will contain various macro calls that are supposed to be hidden. Not being able to decompose metavars back into tokens is awkward to manage, while code is forced to keep everything as token trees as long as possible and only bind into a metavariable during later codegen steps. In the end I think this is too complex to use in practice but I guess I learned a bunch about abusing Rust macro_rules. The thing that kind of broke the camels back is that I wanted to add support for doc attributes, which would have blown up the complexity for accessing properties without recursion. TODO: Re-write as a proc macro instead!
1 parent 3dc5f79 commit 4db0d49

File tree

5 files changed

+4141
-0
lines changed

5 files changed

+4141
-0
lines changed

0 commit comments

Comments
 (0)