1 unstable release
0.1.0 | Jan 6, 2021 |
---|
#2959 in Rust patterns
24KB
422 lines
annotation-rs
Compile-time annotation parser for rust
Features
Annotation
annotation-rs provides a derive macro Annotation
to create annotation structure by struct, StructStruct
, TupleStruct
and NoFieldStruct
are all supported.
use annotation_rs::Annotation;
#[derive(Annotation)]
struct NoField;
#[derive(Annotation)]
struct Tuple(i32, String);
#[derive(Annotation)]
struct Struct {
int: i32,
float: f64,
bool: bool,
}
Types
- String:
String
in Rust. - Bool:
bool
in Rust. - Integer: any integer types in Rust.
- Float: any float types in Rust.
- Object: other annotation structure.
- Enum: defined enum, remember to use
enum_value=true
option. - Vec: Vec of T(T can`t be Object, Vec or HashMap).
- HashMap<String, T>: HashMap of T mapping by
String
Skey. If you want to make a field optional, useOption<T>
on the field type.
use annotation_rs::{AnnotationEnumValue, Annotation};
#[derive(Annotation)]
struct Bar;
#[derive(AnnotationEnumValue)]
enum SomeEnum {
A,
B
}
#[derive(Annotation)]
struct Foo {
pub string: String,
pub bool: bool,
pub int: i32, // or other integer types like u32 ...
pub float: f32, // or other float types like f64
pub object: Bar, // any defined object
#[field(enum_value=true)]
pub enum_field: SomeEnum, // have to add enum_value option
pub list: Vec<i32>, // nested type of vec can`t be Object, Vec or HashMap
pub map: std::collections::HashMap<String, SomeEnum>,
pub optional: Option<i32> // optional field
}
Options
alias
Generated reader will parse the field with the given name instead of its field name in Rust.#[derive(Annotation)] struct Foo { #[field(alias = "i32")] pub int32: i32, }
default
Set the default value for this field. If the value is not present when parsing, the default value will be set to the field, even the field is optional.Object
,Vec
orHashMap
fields can`t have default value.#[derive(Annotation)] struct Foo { #[field(default = 1024)] pub int32: i32 }
enum_value
useenum_value=true
on Enum type field.
Enum
Use derive AnnotationEnumValue
on Enum to create a Enum value type.
use annotation_rs::AnnotationEnumValue;
#[derive(AnnotationEnumValue)]
enum SomeEnum {
A,
B
}
And then, the enum can be used as a field type.
variant_value
attribute
Customize a string corresponding value to variant(default is the snake case of variant name in Rust).
use annotation_rs::AnnotationEnumValue;
#[derive(AnnotationEnumValue)]
enum SomeEnum {
#[variant_value("aaa")] // default is 'a'
A,
B
}
Parse annotations with syn
andquote
annotation_rs::AnnotationStructures<T>
can be used in parse_macro_input!
let annotations = syn::parse_macro_inpit!(input as annotation_rs::AnnotationStructures<Foo>);
If you want to parse annotation from syn::Meta
, use annotation_rs::AnnotationStructure::from_meta()
.
And annotation structure with value can be convert to token automatically. But the visibility of each field must be public.
use proc_macro::TokenStream;
#[derive(Annotation)]
struct Foo {
#[field(default = 1024)]
pub int32: i32
}
fn derive_fn(input: TokenStream) -> TokenStream {
let annotations = syn::parse_macro_input!(input as annotation_rs::AnnotationStructures<Foo>);
let attrs = annotations.attrs;
TokenStream::from(quote::quote! {
fn get_attrs() -> Vec<Foo> {
vec![#(#attrs),*]
}
})
}
Generate derive macro
If you want to use builtin reader generator, enable annotation_reader
feature.
Macro generate_reader
is used to generate a derive macro.
use annotation_rs::generate_reader;
generated_reader!(
MyDerive,
[StructAttribute1, StructAttribute2],
[FieldAttribute1, FieldAttribute2]
);
The macro will generate a public derive, it can be use to read annotations of struct
,enum
or union
, and record the metadata by generate impl
block.
Read annotations
Use the generated derive macro on a struct, and you can use the macro has_annotation
and get_annotation
to process annotations of the struct.
The feature require nightly rustc because proc_macro_hygiene
is required.
#![feature(proc_macro_hygiene)]
use annotation_rs::{get_annotation, has_annotation};
#[derive(MyDerive)]
#[StructAttribute1("some parameters")]
struct Foo {
#[FieldAttribute1("some parameters")]
field: i32
}
fn some_fn() {
assert!(has_annotation!(Foo, StructAttribute1));
assert!(has_annotation!(Foo::field, FieldAttribute1));
let struct_attr1: Option<StructAttribute1> = get_annotation!(Foo, StructAttribute1);
let field_attr1: Option<StructAttribute1> = get_annotation!(Foo::field, StructAttribute1);
}
Dependencies
~2MB
~42K SLoC