From 287ea0a6e466e5bc620b628ffe39771d4e819970 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 3 Nov 2023 22:21:00 +0100 Subject: [PATCH] Allow deriving `Serialize` and `Deserialize` on generated refinement (#3227) This PR adds support for deriving `Serialize` and `Deserialize` on the refinement type generated by `#[derive(Refineable)]`. Release Notes: - N/A --- .../src/derive_refineable.rs | 44 +++++++++++++++++-- crates/theme2/src/colors.rs | 16 ++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/crates/refineable/derive_refineable/src/derive_refineable.rs b/crates/refineable/derive_refineable/src/derive_refineable.rs index ed233e1b0d..c2d001b287 100644 --- a/crates/refineable/derive_refineable/src/derive_refineable.rs +++ b/crates/refineable/derive_refineable/src/derive_refineable.rs @@ -16,9 +16,33 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream { .. } = parse_macro_input!(input); - let impl_debug_on_refinement = attrs - .iter() - .any(|attr| attr.path.is_ident("refineable") && attr.tokens.to_string().contains("debug")); + let refineable_attr = attrs.iter().find(|attr| attr.path.is_ident("refineable")); + + let mut impl_debug_on_refinement = false; + let mut derive_serialize_on_refinement = false; + let mut derive_deserialize_on_refinement = false; + + if let Some(refineable_attr) = refineable_attr { + if let Ok(syn::Meta::List(meta_list)) = refineable_attr.parse_meta() { + for nested in meta_list.nested { + let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested else { + continue; + }; + + if path.is_ident("debug") { + impl_debug_on_refinement = true; + } + + if path.is_ident("serialize") { + derive_serialize_on_refinement = true; + } + + if path.is_ident("deserialize") { + derive_deserialize_on_refinement = true; + } + } + } + } let refinement_ident = format_ident!("{}Refinement", ident); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); @@ -235,8 +259,22 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream { quote! {} }; + let derive_serialize = if derive_serialize_on_refinement { + quote! { #[derive(serde::Serialize)]} + } else { + quote! {} + }; + + let derive_deserialize = if derive_deserialize_on_refinement { + quote! { #[derive(serde::Deserialize)]} + } else { + quote! {} + }; + let gen = quote! { #[derive(Clone)] + #derive_serialize + #derive_deserialize pub struct #refinement_ident #impl_generics { #( #field_visibilities #field_names: #wrapped_types ),* } diff --git a/crates/theme2/src/colors.rs b/crates/theme2/src/colors.rs index 38ae1325a0..b02a9c14df 100644 --- a/crates/theme2/src/colors.rs +++ b/crates/theme2/src/colors.rs @@ -49,7 +49,7 @@ pub struct GitStatusColors { } #[derive(Refineable, Clone, Debug)] -#[refineable(debug)] +#[refineable(debug, deserialize)] pub struct ThemeColors { pub border: Hsla, pub border_variant: Hsla, @@ -105,6 +105,8 @@ pub struct ThemeStyles { #[cfg(test)] mod tests { + use serde_json::json; + use super::*; #[test] @@ -146,4 +148,16 @@ mod tests { assert_eq!(colors.text, magenta); assert_eq!(colors.background, green); } + + #[test] + fn deserialize_theme_colors_refinement_from_json() { + let colors: ThemeColorsRefinement = serde_json::from_value(json!({ + "background": "#ff00ff", + "text": "#ff0000" + })) + .unwrap(); + + assert_eq!(colors.background, Some(gpui::rgb(0xff00ff))); + assert_eq!(colors.text, Some(gpui::rgb(0xff0000))); + } }