Skip to content

Commit 294e187

Browse files
committed
attempt 2
1 parent 47bf175 commit 294e187

File tree

3 files changed

+174
-172
lines changed

3 files changed

+174
-172
lines changed

godot-codegen/src/generator/central_files.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
use crate::context::Context;
99
use crate::conv;
10-
use crate::generator::gdext_build_struct;
10+
use crate::generator::{enums, gdext_build_struct};
1111
use crate::models::domain::{Enumerator, ExtensionApi};
1212
use crate::util::ident;
1313
use proc_macro2::{Ident, Literal, TokenStream};
@@ -265,7 +265,7 @@ fn make_global_enums(api: &ExtensionApi) -> Vec<TokenStream> {
265265
continue;
266266
}
267267

268-
let def = enum_.to_definition();
268+
let def = enums::make_enum_definition(enum_);
269269
global_enum_defs.push(def);
270270
}
271271

godot-codegen/src/generator/enums.rs

Lines changed: 153 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -9,212 +9,202 @@
99
//!
1010
//! See also models/domain/enums.rs for other enum-related methods.
1111
12-
use crate::{
13-
models::domain::{self, Enum},
14-
util::ident,
15-
};
16-
use proc_macro2::{Ident, TokenStream};
12+
use crate::models::domain::{Enum, Enumerator};
13+
use proc_macro2::TokenStream;
1714
use quote::{quote, ToTokens};
1815

19-
pub fn make_enums(enums: &[domain::Enum]) -> TokenStream {
20-
let definitions = enums.iter().map(Enum::to_definition);
16+
pub fn make_enums(enums: &[Enum]) -> TokenStream {
17+
let definitions = enums.iter().map(make_enum_definition);
2118

2219
quote! {
2320
#( #definitions )*
2421
}
2522
}
2623

27-
/// Codegen methods.
28-
impl domain::Enum {
29-
/// Creates a definition of this enum.
30-
///
31-
/// This will also implement all relevant traits and generate appropriate constants for each enumerator.
32-
pub fn to_definition(&self) -> TokenStream {
33-
// Things needed for the type definition
34-
let derives = self.derives();
35-
let enum_doc = self.enum_doc();
36-
let name = &self.name;
37-
38-
// Values
39-
let enumerators = self
40-
.enumerators
41-
.iter()
42-
.map(|enumerator| enumerator.to_definition(name.clone().into_token_stream()));
43-
44-
// Trait implementations
45-
let engine_trait_impl = self.to_engine_trait_impl();
46-
let index_enum_impl = self.to_index_impl();
47-
let bitwise_impls = self.bitwise_operators();
48-
49-
// Various types
50-
let ord_type = self.ord_type();
51-
let engine_trait = self.engine_trait();
24+
/// Creates a definition for the given enum.
25+
///
26+
/// This will also implement all relevant traits and generate appropriate constants for each enumerator.
27+
pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
28+
// Things needed for the type definition
29+
let derives = enum_.derives();
30+
let derives = if !derives.is_empty() {
31+
quote! { #[derive( #( #derives )* )]}
32+
} else {
33+
TokenStream::new()
34+
};
35+
let enum_doc = make_enum_doc(enum_);
36+
let name = &enum_.name;
37+
38+
// Values
39+
let enumerators = enum_
40+
.enumerators
41+
.iter()
42+
.map(|enumerator| make_enumerator_definition(enumerator, name.to_token_stream()));
43+
44+
// Trait implementations
45+
let engine_trait_impl = make_enum_engine_trait_impl(enum_);
46+
let index_enum_impl = make_enum_index_impl(enum_);
47+
let bitwise_impls = make_enum_bitwise_operators(enum_);
48+
49+
// Various types
50+
let ord_type = enum_.ord_type();
51+
let engine_trait = enum_.engine_trait();
5252

53-
quote! {
54-
#[repr(transparent)]
55-
#[derive(#( #derives ),*)]
56-
#( #[doc = #enum_doc] )*
57-
pub struct #name {
58-
ord: #ord_type
59-
}
53+
quote! {
54+
#[repr(transparent)]
55+
#derives
56+
#( #[doc = #enum_doc] )*
57+
pub struct #name {
58+
ord: #ord_type
59+
}
6060

61-
impl #name {
62-
#( #enumerators )*
63-
}
61+
impl #name {
62+
#( #enumerators )*
63+
}
6464

65-
#engine_trait_impl
66-
#index_enum_impl
67-
#bitwise_impls
65+
#engine_trait_impl
66+
#index_enum_impl
67+
#bitwise_impls
6868

69-
impl crate::builtin::meta::GodotConvert for #name {
70-
type Via = #ord_type;
71-
}
69+
impl crate::builtin::meta::GodotConvert for #name {
70+
type Via = #ord_type;
71+
}
7272

73-
impl crate::builtin::meta::ToGodot for #name {
74-
fn to_godot(&self) -> Self::Via {
75-
<Self as #engine_trait>::ord(*self)
76-
}
73+
impl crate::builtin::meta::ToGodot for #name {
74+
fn to_godot(&self) -> Self::Via {
75+
<Self as #engine_trait>::ord(*self)
7776
}
77+
}
7878

79-
impl crate::builtin::meta::FromGodot for #name {
80-
fn try_from_godot(via: Self::Via) -> std::result::Result<Self, crate::builtin::meta::ConvertError> {
81-
<Self as #engine_trait>::try_from_ord(via)
82-
.ok_or_else(|| crate::builtin::meta::FromGodotError::InvalidEnum.into_error(via))
83-
}
79+
impl crate::builtin::meta::FromGodot for #name {
80+
fn try_from_godot(via: Self::Via) -> std::result::Result<Self, crate::builtin::meta::ConvertError> {
81+
<Self as #engine_trait>::try_from_ord(via)
82+
.ok_or_else(|| crate::builtin::meta::FromGodotError::InvalidEnum.into_error(via))
8483
}
8584
}
8685
}
86+
}
8787

88-
/// Creates an implementation of `IndexEnum` for this enum.
89-
///
90-
/// Returns `None` if `self` isn't an indexable enum.
91-
fn to_index_impl(&self) -> Option<TokenStream> {
92-
let enum_max = self.count_index_enum()?;
93-
let name = &self.name;
88+
/// Creates an implementation of `IndexEnum` for the given enum.
89+
///
90+
/// Returns `None` if `enum_` isn't an indexable enum.
91+
fn make_enum_index_impl(enum_: &Enum) -> Option<TokenStream> {
92+
let enum_max = enum_.find_index_enum_max()?;
93+
let name = &enum_.name;
9494

95-
Some(quote! {
96-
impl crate::obj::IndexEnum for #name {
97-
const ENUMERATOR_COUNT: usize = #enum_max;
98-
}
99-
})
100-
}
95+
Some(quote! {
96+
impl crate::obj::IndexEnum for #name {
97+
const ENUMERATOR_COUNT: usize = #enum_max;
98+
}
99+
})
100+
}
101101

102-
/// Creates an implementation of the engine trait for this enum.
103-
///
104-
/// This will implement the trait returned by [`Enum::engine_trait`].
105-
fn to_engine_trait_impl(&self) -> TokenStream {
106-
let name = &self.name;
107-
let engine_trait = self.engine_trait();
108-
109-
if self.is_bitfield {
110-
quote! {
111-
impl #engine_trait for #name {
112-
fn try_from_ord(ord: u64) -> Option<Self> {
113-
Some(Self { ord })
114-
}
102+
/// Creates an implementation of the engine trait for the given enum.
103+
///
104+
/// This will implement the trait returned by [`Enum::engine_trait`].
105+
fn make_enum_engine_trait_impl(enum_: &Enum) -> TokenStream {
106+
let name = &enum_.name;
107+
let engine_trait = enum_.engine_trait();
115108

116-
fn ord(self) -> u64 {
117-
self.ord
118-
}
109+
if enum_.is_bitfield {
110+
quote! {
111+
// We may want to add this in the future.
112+
//
113+
// impl #enum_name {
114+
// pub const UNSET: Self = Self { ord: 0 };
115+
// }
116+
117+
impl #engine_trait for #name {
118+
fn try_from_ord(ord: u64) -> Option<Self> {
119+
Some(Self { ord })
120+
}
121+
122+
fn ord(self) -> u64 {
123+
self.ord
119124
}
120125
}
121-
} else {
122-
let unique_ords = self.unique_ords().expect("self is an enum");
123-
124-
quote! {
125-
impl #engine_trait for #name {
126-
fn try_from_ord(ord: i32) -> Option<Self> {
127-
match ord {
128-
#( ord @ #unique_ords )|* => Some(Self { ord }),
129-
_ => None,
130-
}
131-
}
126+
}
127+
} else {
128+
let unique_ords = enum_.unique_ords().expect("self is an enum");
132129

133-
fn ord(self) -> i32 {
134-
self.ord
130+
quote! {
131+
impl #engine_trait for #name {
132+
fn try_from_ord(ord: i32) -> Option<Self> {
133+
match ord {
134+
#( ord @ #unique_ords )|* => Some(Self { ord }),
135+
_ => None,
135136
}
136137
}
138+
139+
fn ord(self) -> i32 {
140+
self.ord
141+
}
137142
}
138143
}
139144
}
145+
}
140146

141-
/// Creates implementations for any bitwise operators.
142-
///
143-
/// Currently this is just [`BitOr`](std::ops::BitOr) for bitfields but that could be expanded in the future.
144-
fn bitwise_operators(&self) -> TokenStream {
145-
let name = &self.name;
147+
/// Creates implementations for bitwise operators for the given enum.
148+
///
149+
/// Currently this is just [`BitOr`](std::ops::BitOr) for bitfields but that could be expanded in the future.
150+
fn make_enum_bitwise_operators(enum_: &Enum) -> TokenStream {
151+
let name = &enum_.name;
146152

147-
if self.is_bitfield {
148-
quote! {
149-
impl std::ops::BitOr for #name {
150-
type Output = Self;
153+
if enum_.is_bitfield {
154+
quote! {
155+
impl std::ops::BitOr for #name {
156+
type Output = Self;
151157

152-
fn bitor(self, rhs: Self) -> Self::Output {
153-
Self { ord: self.ord | rhs.ord }
154-
}
158+
fn bitor(self, rhs: Self) -> Self::Output {
159+
Self { ord: self.ord | rhs.ord }
155160
}
156161
}
157-
} else {
158-
TokenStream::new()
159162
}
163+
} else {
164+
TokenStream::new()
160165
}
161-
162-
/// Which derives should be implemented for this enum.
163-
fn derives(&self) -> Vec<Ident> {
164-
let mut derives = vec!["Copy", "Clone", "Eq", "PartialEq", "Hash", "Debug"];
165-
166-
if self.is_bitfield {
167-
derives.push("Default");
168-
}
169-
170-
derives.into_iter().map(ident).collect()
166+
}
167+
/// Returns the documentation for the given enum.
168+
///
169+
/// Each string is one line of documentation, usually this needs to be wrapped in a `#[doc = ..]`.
170+
fn make_enum_doc(enum_: &Enum) -> Vec<String> {
171+
let mut docs = Vec::new();
172+
173+
if enum_.name != enum_.godot_name {
174+
docs.push(format!("Godot enum name: `{}`.", enum_.godot_name))
171175
}
172176

173-
/// Returns the documentation for this enum.
174-
///
175-
/// Each string is one line of documentation, usually this needs to be wrapped in a `#[doc = ..]`.
176-
fn enum_doc(&self) -> Vec<String> {
177-
let mut docs = Vec::new();
178-
179-
if self.name != self.godot_name {
180-
docs.push(format!("Godot enum name: `{}`.", self.godot_name))
181-
}
182-
183-
docs
184-
}
177+
docs
185178
}
186179

187-
/// Codegen methods.
188-
impl domain::Enumerator {
189-
/// Creates a `const` definition for self of the type `enum_type`.
190-
///
191-
/// That is, it'll be a definition like
192-
/// ```ignore
193-
/// pub const NAME: enum_type = ..;
194-
/// ```
195-
fn to_definition(&self, enum_type: TokenStream) -> TokenStream {
196-
let Self {
197-
name,
198-
godot_name,
199-
value,
200-
} = self;
201-
202-
let docs = if &name.to_string() != godot_name {
203-
let doc = format!("Godot enumerator name: `{godot_name}`");
204-
205-
quote! {
206-
#[doc(alias = #godot_name)]
207-
#[doc = #doc]
208-
}
209-
} else {
210-
TokenStream::new()
211-
};
180+
/// Creates a `const` definition for `enumerator` of the type `enum_type`.
181+
///
182+
/// That is, it'll be a definition like
183+
/// ```ignore
184+
/// pub const NAME: enum_type = ..;
185+
/// ```
186+
fn make_enumerator_definition(enumerator: &Enumerator, enum_type: TokenStream) -> TokenStream {
187+
let Enumerator {
188+
name,
189+
godot_name,
190+
value,
191+
} = enumerator;
192+
193+
let docs = if &name.to_string() != godot_name {
194+
let doc = format!("Godot enumerator name: `{godot_name}`");
212195

213196
quote! {
214-
#docs
215-
pub const #name: #enum_type = #enum_type {
216-
ord: #value
217-
};
197+
#[doc(alias = #godot_name)]
198+
#[doc = #doc]
218199
}
200+
} else {
201+
TokenStream::new()
202+
};
203+
204+
quote! {
205+
#docs
206+
pub const #name: #enum_type = #enum_type {
207+
ord: #value
208+
};
219209
}
220210
}

0 commit comments

Comments
 (0)