Skip to content

Commit

Permalink
make specific variant work
Browse files Browse the repository at this point in the history
  • Loading branch information
realbigsean committed Feb 2, 2024
1 parent 877edbc commit ff4391a
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 3 deletions.
17 changes: 14 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,10 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
panic!("can't configure `only` and `getter` on the same field");
} else if field_opts.meta_only.is_some() && field_opts.getter.is_some() {
panic!("can't configure `meta_only` and `getter` on the same field");
} else if field_opts.only.is_none() && field_opts.partial_getter.is_some() {
} else if field_opts.only.is_none()
&& field_opts.meta_only.is_none()
&& field_opts.partial_getter.is_some()
{
panic!("can't set `partial_getter` options on common field");
} else if field_opts.flatten.is_some() && field_opts.only.is_some() {
panic!("can't set `flatten` and `only` on the same field");
Expand Down Expand Up @@ -407,19 +410,27 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
for (variant_key, struct_name) in variant_combinations.zip(struct_names.iter()) {
let fields = &variant_fields[&variant_key];

// TODO: think about how to handle this with meta
let specific_struct_attributes = opts
.specific_variant_attributes
.as_ref()
.and_then(|sv| sv.get(&variant_key.variant))
.map_or(&[][..], |attrs| &attrs.metas);
let specific_struct_attributes_meta = opts
.specific_variant_attributes
.as_ref()
.and_then(|sv| variant_key.meta_variant.and_then(|mv| sv.get(&mv)))
.map_or(&[][..], |attrs| &attrs.metas);
let spatt = specific_struct_attributes
.iter()
.chain(specific_struct_attributes_meta.iter())
.unique();

let variant_code = quote! {
#(
#[#universal_struct_attributes]
)*
#(
#[#specific_struct_attributes]
#[#spatt]
)*
#visibility struct #struct_name #decl_generics #where_clause {
#(
Expand Down
94 changes: 94 additions & 0 deletions tests/meta_variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,97 @@ fn meta_variant_flatten() {
assert!(message_h.inner_b_read_upper().is_err());
assert_eq!(message_h.inner_b_write_upper().unwrap().w, 3);
}

#[test]
fn meta_variants_map_macro() {
#[superstruct(
meta_variants(Juicy, Sour),
variants(Apple, Orange),
variant_attributes(derive(Debug, PartialEq))
)]
#[derive(Debug, PartialEq)]
pub struct Fruit {
#[superstruct(getter(copy))]
id: u64,
#[superstruct(only(Apple), partial_getter(copy))]
description: &'static str,
#[superstruct(meta_only(Juicy))]
name: &'static str,
}

fn increment_id(id: Fruit) -> Fruit {
map_fruit!(id, |mut inner, cons| {
*inner.id_mut() += 1;
cons(inner)
})
}

fn get_id_via_ref<'a>(fruit_ref: FruitRef<'a>) -> u64 {
map_fruit_ref!(&'a _, fruit_ref, |inner, _| { inner.id() })
}

assert_eq!(
increment_id(Fruit::Juicy(FruitJuicy::Orange(FruitJuicyOrange {
id: 10,
name: "orange"
})))
.id(),
get_id_via_ref(
Fruit::Juicy(FruitJuicy::Orange(FruitJuicyOrange {
id: 11,
name: "orange"
}))
.to_ref()
)
);
}

#[test]
fn meta_variants_exist_specific_attributes() {
#[superstruct(
meta_variants(One, Two),
variants(IsCopy, IsNotCopy),
variant_attributes(derive(Debug, PartialEq, Clone)),
specific_variant_attributes(IsCopy(derive(Copy)))
)]
#[derive(Clone, PartialEq, Debug)]
pub struct Thing {
pub x: u64,
#[superstruct(only(IsNotCopy))]
pub y: String,
}

fn copy<T: Copy>(t: T) -> (T, T) {
(t, t)
}

let x = ThingOneIsCopy { x: 0 };
assert_eq!(copy(x), (x, x));
let x = ThingTwoIsCopy { x: 0 };
assert_eq!(copy(x), (x, x));
}

#[test]
fn meta_variants_have_specific_attributes() {
#[superstruct(
meta_variants(IsCopy, IsNotCopy),
variants(One, Two),
variant_attributes(derive(Debug, PartialEq, Clone)),
specific_variant_attributes(IsCopy(derive(Copy)))
)]
#[derive(Clone, PartialEq, Debug)]
pub struct Ting {
pub x: u64,
#[superstruct(meta_only(IsNotCopy))]
pub y: String,
}

fn copy<T: Copy>(t: T) -> (T, T) {
(t, t)
}

let x = TingIsCopyOne { x: 0 };
assert_eq!(copy(x), (x, x));
let x = TingIsCopyTwo { x: 0 };
assert_eq!(copy(x), (x, x));
}

0 comments on commit ff4391a

Please sign in to comment.