1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
//! This is a companion crate to [`jnix`] that provides some procedural macros for interfacing JNI //! with Rust. See the [`jnix` crate documentation][doc] for more information //! //! [`jnix`]: https://crates.io/crates/jnix //! [doc]: https://docs.rs/jnix/ #![deny(missing_docs)] extern crate proc_macro; mod attributes; mod fields; mod generics; mod parsed_type; mod variants; use crate::{ attributes::JnixAttributes, fields::ParsedFields, generics::{ParsedGenerics, TypeParameters}, parsed_type::ParsedType, variants::ParsedVariants, }; use proc_macro::TokenStream; use syn::{parse_macro_input, DeriveInput}; /// Derives `IntoJava` for a type. /// /// The name of the target Java class must be known for code generation. Either it can specified /// explicitly using an attribute, like so: `#[jnix(class_name = "my.package.MyClass"]`, or it can /// be derived from the Rust type name as long as the containing Java package is specified using an /// attribute, like so: `#[jnix(package = "my.package")]`. /// /// # Structs /// /// The generated `IntoJava` implementation for a struct will convert the field values into their /// respective Java types. Then, the target Java class is constructed by calling a constructor with /// the converted field values as parameters. Note that the field order is used as the constructor /// parameter order. /// /// Fields can be "preconverted" to a different Rust type, so that the resulting type is then used /// to convert to the Java type. To do so, use the `#[jnix(map = "|value| ...")]` attribute with a /// conversion closure. /// /// Fields can be skipped using the `#[jnix(skip)]` attribute, so that they aren't used in the /// conversion process, and therefore not used as a parameter for the constructor. The /// `#[jnix(skip_all)]` attribute can be used on the struct to skip all fields. /// /// The target class of a specific field can be set manually with the /// `#[jnix(target_class = "...")]` attribute. However, be aware that the target class must have /// the expected constructor with the parameter list based on the field order of the Rust type. /// /// # Enums /// /// The generated `IntoJava` implementation for a enum that only has unit variants (i.e., no tuple /// or struct variants) returns a static field value from the specified Java target class. The /// name used for the static field in the Java class is the same as the Rust variant name. This /// allows the Rust enum to be mapped to a Java enum. /// /// When an enum has at least one tuple or struct variant, the generated `IntoJava` implementation /// will assume that that there is a class hierarchy to represent the type. The target Java class /// is used as the super class, and is the Java type returned from the conversion. The class is /// assumed to have one inner class for each variant, and the conversion actually instantiates an /// object for the respective variant type, using the same rules for the fields as the rules for /// struct fields. #[proc_macro_derive(IntoJava, attributes(jnix))] pub fn derive_into_java(input: TokenStream) -> TokenStream { let parsed_type = ParsedType::new(parse_macro_input!(input as DeriveInput)); TokenStream::from(parsed_type.generate_into_java()) }