Skip to content

Commit 3aed515

Browse files
committed
Implement bitwise operators and Default impl for DuplicateFlags mainly.
1 parent 403aa97 commit 3aed515

4 files changed

Lines changed: 70 additions & 2 deletions

File tree

godot-codegen/src/generator/enums.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@ pub fn make_enum_definition_with(
115115
let index_enum_impl = make_enum_index_impl(enum_);
116116
let bitwise_impls = make_enum_bitwise_operators(enum_, enum_bitmask.as_ref());
117117

118+
let special_default_impl = if let Some(override_default) = enum_.override_default.as_ref() {
119+
quote! {
120+
impl Default for #name {
121+
fn default() -> Self {
122+
#override_default
123+
}
124+
}
125+
}
126+
} else {
127+
TokenStream::new()
128+
};
129+
118130
let var_trait_set = if enum_.is_exhaustive {
119131
quote! {
120132
fn var_set(field: &mut Self, value: Self::Via) {
@@ -144,6 +156,7 @@ pub fn make_enum_definition_with(
144156
#engine_trait_impl
145157
#index_enum_impl
146158
#bitwise_impls
159+
#special_default_impl
147160

148161
impl crate::meta::GodotConvert for #name {
149162
type Via = #ord_type;
@@ -485,7 +498,12 @@ fn make_enum_as_str(enum_: &Enum) -> TokenStream {
485498

486499
/// Creates implementations for bitwise operators for the given enum.
487500
///
488-
/// Currently, this is just [`BitOr`](std::ops::BitOr) for bitfields but that could be expanded in the future.
501+
/// Currently, for bitfields this is the following (but could be expanded in the future):
502+
/// - [`BitOr`](std::ops::BitOr)
503+
/// - [`BitOrAssign`](std::ops::BitOrAssign)
504+
/// - [`BitAnd`](std::ops::BitAnd)
505+
/// - [`BitAndAssign`](std::ops::BitAndAssign)
506+
/// - [`Not`](std::ops::Not) (there is not a separate 'BitNot' trait)
489507
fn make_enum_bitwise_operators(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> TokenStream {
490508
let name = &enum_.name;
491509

@@ -507,6 +525,31 @@ fn make_enum_bitwise_operators(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> T
507525
*self = *self | rhs;
508526
}
509527
}
528+
529+
impl std::ops::BitAnd for #name {
530+
type Output = Self;
531+
532+
#[inline]
533+
fn bitand(self, rhs: Self) -> Self::Output {
534+
Self { ord: self.ord & rhs.ord }
535+
}
536+
}
537+
538+
impl std::ops::BitAndAssign for #name {
539+
#[inline]
540+
fn bitand_assign(&mut self, rhs: Self) {
541+
*self = *self & rhs;
542+
}
543+
}
544+
545+
impl std::ops::Not for #name {
546+
type Output = Self;
547+
548+
#[inline]
549+
fn not(self) -> Self::Output {
550+
Self { ord: !self.ord }
551+
}
552+
}
510553
}
511554
} else if let Some(mask_enum) = enum_bitmask {
512555
// Enum that has an accompanying bitfield for masking.

godot-codegen/src/models/domain/enums.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub struct Enum {
2020
pub godot_name: String,
2121
pub surrounding_class: Option<TyName>,
2222
pub is_bitfield: bool,
23+
pub override_default: Option<TokenStream>,
2324
pub is_private: bool,
2425
pub is_exhaustive: bool,
2526
pub enumerators: Vec<Enumerator>,
@@ -33,7 +34,7 @@ impl Enum {
3334
// Debug is implemented manually, using enumerator name. This can be derived once we use proper enums.
3435
let mut derives = vec!["Copy", "Clone", "Eq", "PartialEq", "Hash"];
3536

36-
if self.is_bitfield {
37+
if self.is_bitfield && self.override_default.is_none() {
3738
derives.push("Default");
3839
}
3940

godot-codegen/src/models/domain_mapping.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,8 @@ impl Enum {
766766
.unwrap_or(json_is_bitfield);
767767
let is_private = special_cases::is_enum_private(surrounding_class, &godot_name);
768768
let is_exhaustive = special_cases::is_enum_exhaustive(surrounding_class, &godot_name);
769+
let override_default =
770+
special_cases::does_enum_have_special_default(surrounding_class, &godot_name);
769771

770772
let rust_enum_name = conv::make_enum_name_str(&godot_name);
771773
let rust_enumerator_names = {
@@ -800,6 +802,7 @@ impl Enum {
800802
godot_name,
801803
surrounding_class: surrounding_class.cloned(),
802804
is_bitfield,
805+
override_default,
803806
is_private,
804807
is_exhaustive,
805808
enumerators,

godot-codegen/src/special_cases/special_cases.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,27 @@ pub fn is_enum_bitfield(class_name: Option<&TyName>, enum_name: &str) -> Option<
13611361
}
13621362
}
13631363

1364+
/// For types where a [`Default`](Default) is helpful, but the default value should
1365+
/// be something other than what would be returned by a `#[derive(Default)]` implementation.
1366+
///
1367+
/// An example of this is `DuplicateFlags`, where the default flags to `duplicate` are non-zero,
1368+
/// so if one wants to use "all flags except one" in `duplicate_ex`, the most natural way to do
1369+
/// so would be to pass `DuplicateFlags::default() & !DuplicateFlags::USE_INSTATANTIATION` to `flags`.
1370+
///
1371+
/// * `Some(TokenStream)` -> function body which will be psted into the `Default::default` implementation.
1372+
/// * `None` -> no special default, i.e. if a Default is generated it will be with an automatic derive.
1373+
#[rustfmt::skip]
1374+
pub fn does_enum_have_special_default(class_name: Option<&TyName>, enum_name: &str) -> Option<TokenStream> {
1375+
let class_name = class_name.map(|c| c.godot_ty.as_str());
1376+
match (class_name, enum_name) {
1377+
(Some("Node"), "DuplicateFlags") => Some(quote! {
1378+
Self::SIGNALS | Self::GROUPS | Self::SCRIPTS | Self::USE_INSTANTIATION
1379+
}),
1380+
1381+
_ => None
1382+
}
1383+
}
1384+
13641385
/// Whether an enum can be combined with another enum (return value) for bitmasking purposes.
13651386
///
13661387
/// If multiple masks are ever necessary, this can be extended to return a slice instead of Option.

0 commit comments

Comments
 (0)