servo_config_macro/
lib.rs1use proc_macro2::TokenStream;
6use quote::quote;
7use syn::{Data, Fields};
8use synstructure::decl_derive;
9
10decl_derive!([ServoPreferences] => servo_preferences_derive);
11
12fn servo_preferences_derive(input: synstructure::Structure) -> TokenStream {
16 let ast = input.ast();
17
18 let Data::Struct(ref data) = ast.data else {
19 unimplemented!();
20 };
21 let Fields::Named(ref named_fields) = data.fields else {
22 unimplemented!()
23 };
24
25 let mut exists_match_cases = quote!();
26 for field in named_fields.named.iter() {
27 let name = field.ident.as_ref().unwrap();
28 exists_match_cases.extend(quote!(stringify!(#name) => true,))
29 }
30
31 let mut get_match_cases = quote!();
32 for field in named_fields.named.iter() {
33 let name = field.ident.as_ref().unwrap();
34 get_match_cases.extend(quote!(stringify!(#name) => self.#name.clone().into(),))
35 }
36
37 let mut set_match_cases = quote!();
38 for field in named_fields.named.iter() {
39 let name = field.ident.as_ref().unwrap();
40 set_match_cases.extend(quote!(stringify!(#name) => self.#name = value.try_into().unwrap(),))
41 }
42
43 let mut type_of_match_cases = quote!();
44 for field in named_fields.named.iter() {
45 let name = field.ident.as_ref().unwrap();
46 let ty = &field.ty;
47 type_of_match_cases.extend(quote!(stringify!(#name) => std::any::type_name::<#ty>(),))
48 }
49
50 let mut comparisons = quote!();
51 for field in named_fields.named.iter() {
52 let name = field.ident.as_ref().unwrap();
53 comparisons.extend(quote!(if self.#name != other.#name { changes.push((stringify!(#name), self.#name.clone().into(),)) }))
54 }
55
56 let mut all_fields = quote!();
57 for field in named_fields.named.iter() {
58 let name = field.ident.as_ref().unwrap();
59 all_fields.extend(quote!(stringify!(#name),));
60 }
61
62 let structure_name = &ast.ident;
63 quote! {
64 impl #structure_name {
65 pub fn exists(name: &str) -> bool {
66 match name {
67 #exists_match_cases
68 _ => { false }
69 }
70 }
71
72 pub fn get_value(&self, name: &str) -> PrefValue {
73 match name {
74 #get_match_cases
75 _ => { panic!("Unknown preference: {:?}", name); }
76 }
77 }
78
79 pub fn set_value(&mut self, name: &str, value: PrefValue) {
80 match name {
81 #set_match_cases
82 _ => { panic!("Unknown preference: {:?}", name); }
83 }
84 }
85
86 pub fn type_of(name: &str) -> &'static str {
87 match name {
88 #type_of_match_cases
89 _ => { panic!("Unknown preference: {:?}", name); }
90 }
91 }
92
93 pub fn diff(&self, other: &Self) -> Vec<(&'static str, PrefValue)> {
94 let mut changes = vec![];
95 #comparisons
96 changes
97 }
98
99 pub fn all_fields() -> Vec<&'static str> {
100 vec![
101 #all_fields
102 ]
103 }
104 }
105 }
106}