Skip to content

Added the ability to use #[default] and added Default in the derive trait #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,25 @@ fn concat<T>(mut v1: Vec<T>, mut v2: Vec<T>) -> Vec<T> {
v1
}

fn check_for_default(triples: &mut Vec<(TokenStream, Ident, TokenTree)>) {
let mut default_position: Option<usize> = None;
for (attributes, _variant_name, variant_value) in triples.into_iter() {
if attributes.to_string().contains("default") {
if default_position.is_some() {
// error!("Multiple variants marked as default");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to get rid of this if statement? I'm not 100% sure, but I would assume that derive(Default) itself will trigger an error if it sees multiple defaults.

Also it looks like we don't actually need to do anything with the default variant, so you probably don't need the default_position variable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, um, it kinda triggers a error

Copy link
Owner

@math4tots math4tots Nov 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Looks like someone opened a pr to fix the error message here in response to the issue you opened.

Still, I suppose I'd prefer it if we propagated the error, because even after that pr lands, I'm assuming it might take a little while for that fix to be in a release.

Also, I just realized, as you probably noticed, we can't just use the error! macro here because your function doesn't return a TokenStream. I think the "correct" thing to do here would be to return Result<(), String> from check_for_default and check for an error when you call it, then call error! from there.

}
default_position = Some(variant_value.to_string().parse::<usize>().unwrap());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could do a return here instead. And if you do, you won't need to do if !default_position.is_some() below.

}
}
if !default_position.is_some() {
// No default specified, so we'll just use the first variant
triples[0].0.extend(vec![
punct_token('#'),
bracket_token(vec![ident_token("default")]).into(),
]);
}
}

#[proc_macro]
pub fn primitive_enum(tokens: TokenStream) -> TokenStream {
let mut iter = tokens.into_iter();
Expand Down Expand Up @@ -302,6 +321,7 @@ pub fn primitive_enum(tokens: TokenStream) -> TokenStream {
offset += 1;
triples.push((variant_attributes, variant_name, value));
}
check_for_default(&mut triples); // make sure there's a default, if the user didn't specify one
triples
};

Expand All @@ -322,7 +342,6 @@ pub fn primitive_enum(tokens: TokenStream) -> TokenStream {
ident_token("repr"),
paren_token(repr_type.clone()),
]));

// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
out.push(punct_token('#'));
out.push(bracket_token(vec![
Expand All @@ -339,8 +358,11 @@ pub fn primitive_enum(tokens: TokenStream) -> TokenStream {
ident_token("Eq"),
punct_token(','),
ident_token("Hash"),
punct_token(','),
ident_token("Default"),
]),
]));

out.push(ident_token("pub"));
out.push(ident_token("enum"));
out.push(TokenTree::Ident(enum_identifier.clone()));
Expand Down
18 changes: 18 additions & 0 deletions tests/sample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,22 @@ mod tests {
assert_eq!(MarkerType::from_name("Markerboxes"), Some(MarkerType::Markerboxes));
assert_eq!(MarkerType::from_name("Markerpitlane"), Some(MarkerType::Markerpitlane));
}

primitive_enum! { MarkerType2 u32 ;
A, // 0
B, // 1
C, // 2
D, // 3
E, // 4
#[default]
F, // 5
G, // 6
}

#[test]
fn test_enum_default() {
assert_eq!(MarkerType2::default(), MarkerType2::F);
assert_eq!(MarkerType2::from(0), Some(MarkerType2::A));
assert_eq!(MyEnum::default(), MyEnum::A);
}
}