Skip to content

Commit e11525e

Browse files
committed
Encoder packet ID generation uses enum names
1 parent 3a5e837 commit e11525e

1 file changed

Lines changed: 125 additions & 26 deletions

File tree

rust/bufferfish/src/compiler.rs

Lines changed: 125 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,46 @@ fn generate_output_string(input: Vec<String>, output: &mut String) -> Result<(),
138138
output.push_str("/* AUTOGENERATED BUFFERFISH FILE, DO NOT EDIT */\n");
139139
output.push_str("import { Bufferfish } from 'bufferfish'\n");
140140

141-
for path in input {
142-
let items = parse_rust_source_file(&path)?;
141+
let mut packet_id_enum_names = Vec::new();
142+
let mut all_structs = Vec::new();
143+
let mut all_enums = Vec::new();
144+
145+
for path in &input {
146+
let items = parse_rust_source_file(path)?;
143147
let (structs, enums) = get_items_implementing_encode(items);
144148

145-
for item in &enums {
146-
generate_typescript_enum_defs(item.clone(), output);
147-
generate_typescript_enum_decoders(item.clone(), output);
148-
generate_typescript_enum_encoders(item.clone(), output);
149+
// Find struct attributes with #[bufferfish(...)] to identify packet ID enums
150+
for item in &structs {
151+
if let Some(packet_id) = get_packet_id(&item.attrs) {
152+
if let Some(enum_name) = extract_enum_name_from_packet_id(&packet_id) {
153+
if !packet_id_enum_names.contains(&enum_name) {
154+
packet_id_enum_names.push(enum_name);
155+
}
156+
}
157+
}
149158
}
150159

151-
for item in &structs {
152-
generate_typescript_struct_defs(item.clone(), output);
153-
generate_typescript_struct_decoders(item.clone(), output);
154-
generate_typescript_struct_encoders(item.clone(), output);
160+
all_structs.extend(structs);
161+
all_enums.extend(enums);
162+
}
163+
164+
for item in &all_enums {
165+
generate_typescript_enum_defs(item.clone(), output);
166+
generate_typescript_enum_decoders(item.clone(), output);
167+
generate_typescript_enum_encoders(item.clone(), output);
168+
169+
let enum_name = item.ident.to_string();
170+
if packet_id_enum_names.contains(&enum_name) {
171+
generate_typescript_packet_id_encoder(item.clone(), output);
155172
}
156173
}
157174

175+
for item in &all_structs {
176+
generate_typescript_struct_defs(item.clone(), output);
177+
generate_typescript_struct_decoders(item.clone(), output);
178+
generate_typescript_struct_encoders(item.clone(), output, &packet_id_enum_names);
179+
}
180+
158181
Ok(())
159182
}
160183

@@ -192,7 +215,6 @@ fn get_packet_id(attrs: &[Attribute]) -> Option<String> {
192215
if attr.path().is_ident("bufferfish") {
193216
if let Meta::List(list) = &attr.meta {
194217
let tokens = list.tokens.to_string();
195-
196218
let cleaned = tokens.trim().replace(" ", "").replace("::", ".");
197219

198220
return Some(cleaned);
@@ -202,8 +224,46 @@ fn get_packet_id(attrs: &[Attribute]) -> Option<String> {
202224
None
203225
}
204226

227+
/// Extract the enum name from a packet ID reference like "EnumName.Variant"
228+
fn extract_enum_name_from_packet_id(id: &str) -> Option<String> {
229+
id.split('.').next().map(|s| s.to_string())
230+
}
231+
205232
/// Generate TypeScript encoders for structs including PacketID if specified
206-
fn generate_typescript_struct_encoders(item: ItemStruct, output: &mut String) {
233+
/// Generate a TypeScript encoder function for a specific packet ID enum
234+
fn generate_typescript_packet_id_encoder(item: ItemEnum, output: &mut String) {
235+
let enum_name = item.ident.to_string();
236+
let repr_type = get_repr_type(&item.attrs).unwrap_or("u8".to_string());
237+
238+
let write_fn = match repr_type.as_str() {
239+
"u8" => "writeUint8",
240+
"u16" => "writeUint16",
241+
"u32" => "writeUint32",
242+
"u64" => "writeUint64",
243+
"u128" => "writeUint128",
244+
"i8" => "writeInt8",
245+
"i16" => "writeInt16",
246+
"i32" => "writeInt32",
247+
"i64" => "writeInt64",
248+
"i128" => "writeInt128",
249+
_ => panic!("Unsupported repr type"),
250+
};
251+
252+
output.push_str(
253+
format!(
254+
"\nexport function encode{enum_name}(bf: Bufferfish, value: {enum_name}): void {{\n",
255+
)
256+
.as_str(),
257+
);
258+
output.push_str(format!(" bf.{write_fn}(value)\n").as_str());
259+
output.push_str("}\n");
260+
}
261+
262+
fn generate_typescript_struct_encoders(
263+
item: ItemStruct,
264+
output: &mut String,
265+
packet_id_enums: &[String],
266+
) {
207267
let struct_name = item.ident.to_string();
208268
let packet_id = get_packet_id(&item.attrs);
209269

@@ -223,10 +283,13 @@ fn generate_typescript_struct_encoders(item: ItemStruct, output: &mut String) {
223283
);
224284

225285
if let Some(id) = &packet_id {
226-
output.push_str(format!(" encodePacketId(bf, {id})\n").as_str());
286+
if let Some(enum_name) = extract_enum_name_from_packet_id(id) {
287+
if packet_id_enums.contains(&enum_name) {
288+
output.push_str(format!(" encode{enum_name}(bf, {id})\n").as_str());
289+
}
290+
}
227291
}
228292

229-
// Write struct fields
230293
for field in &fields_named.named {
231294
if let Some(field_name) = &field.ident {
232295
let field_ts_name = snake_to_camel_case(field_name.to_string());
@@ -260,10 +323,13 @@ fn generate_typescript_struct_encoders(item: ItemStruct, output: &mut String) {
260323
);
261324

262325
if let Some(id) = &packet_id {
263-
output.push_str(format!(" encodePacketId(bf, {id})\n").as_str());
326+
if let Some(enum_name) = extract_enum_name_from_packet_id(id) {
327+
if packet_id_enums.contains(&enum_name) {
328+
output.push_str(format!(" encode{enum_name}(bf, {id})\n").as_str());
329+
}
330+
}
264331
}
265332

266-
// Write tuple fields
267333
for (i, field) in fields_unnamed.unnamed.iter().enumerate() {
268334
output.push_str(
269335
format!(
@@ -285,7 +351,13 @@ fn generate_typescript_struct_encoders(item: ItemStruct, output: &mut String) {
285351
)
286352
.as_str(),
287353
);
288-
output.push_str(format!(" encodePacketId(bf, {id})\n").as_str());
354+
355+
if let Some(enum_name) = extract_enum_name_from_packet_id(&id) {
356+
if packet_id_enums.contains(&enum_name) {
357+
output.push_str(format!(" encode{enum_name}(bf, {id})\n").as_str());
358+
}
359+
}
360+
289361
output.push_str("}\n");
290362
}
291363
}
@@ -511,7 +583,7 @@ fn generate_typescript_struct_decoders(item: ItemStruct, lines: &mut String) {
511583
}
512584
}
513585

514-
lines.push_str(" };\n");
586+
lines.push_str(" }\n");
515587
lines.push_str("}\n");
516588
}
517589
Fields::Unnamed(fields_unnamed) => {
@@ -616,7 +688,7 @@ mod tests {
616688

617689
#[test]
618690
fn test_ts_generation() {
619-
let input = r#"
691+
let test_file = r#"
620692
#[derive(Encode)]
621693
#[repr(u16)]
622694
pub enum PacketId {
@@ -658,6 +730,10 @@ export function encodePacketId(bf: Bufferfish, value: PacketId): void {
658730
bf.writeUint16(value)
659731
}
660732
733+
export function encodePacketId(bf: Bufferfish, value: PacketId): void {
734+
bf.writeUint16(value)
735+
}
736+
661737
export interface JoinPacket {
662738
id: number
663739
username: string
@@ -667,7 +743,7 @@ export function decodeJoinPacket(bf: Bufferfish): JoinPacket {
667743
return {
668744
id: bf.readUint8() as number,
669745
username: bf.readString() as string,
670-
};
746+
}
671747
}
672748
673749
export function encodeJoinPacket(bf: Bufferfish, value: JoinPacket): void {
@@ -696,25 +772,48 @@ export function encodeUnknownPacket(bf: Bufferfish, value: UnknownPacket): void
696772
}
697773
"#;
698774

775+
let items = syn::parse_file(test_file)
776+
.unwrap_or_else(|e| panic!("Failed to parse: {e}"))
777+
.items;
778+
let (structs, enums) = get_items_implementing_encode(items);
779+
699780
let mut output = String::new();
700781
output.push_str("/* AUTOGENERATED BUFFERFISH FILE, DO NOT EDIT */\n");
701782
output.push_str("import { Bufferfish } from 'bufferfish'\n");
702783

703-
let syntax_tree = syn::parse_file(input).unwrap();
704-
let (structs, enums) = get_items_implementing_encode(syntax_tree.items);
784+
let mut packet_id_enum_names = Vec::new();
705785

706-
for item in enums {
786+
for item in &structs {
787+
if let Some(packet_id) = get_packet_id(&item.attrs) {
788+
if let Some(enum_name) = extract_enum_name_from_packet_id(&packet_id) {
789+
if !packet_id_enum_names.contains(&enum_name) {
790+
packet_id_enum_names.push(enum_name);
791+
}
792+
}
793+
}
794+
}
795+
796+
for item in &enums {
707797
generate_typescript_enum_defs(item.clone(), &mut output);
708798
generate_typescript_enum_decoders(item.clone(), &mut output);
709799
generate_typescript_enum_encoders(item.clone(), &mut output);
800+
801+
let enum_name = item.ident.to_string();
802+
if packet_id_enum_names.contains(&enum_name) {
803+
generate_typescript_packet_id_encoder(item.clone(), &mut output);
804+
}
710805
}
711806

712-
for item in structs {
807+
for item in &structs {
713808
generate_typescript_struct_defs(item.clone(), &mut output);
714809
generate_typescript_struct_decoders(item.clone(), &mut output);
715-
generate_typescript_struct_encoders(item.clone(), &mut output);
810+
generate_typescript_struct_encoders(item.clone(), &mut output, &packet_id_enum_names);
716811
}
717812

718-
assert_eq!(output, expected_output);
813+
if output != expected_output {
814+
println!("Expected:\n{expected_output}");
815+
println!("Got:\n{output}");
816+
panic!("Output does not match expected output");
817+
}
719818
}
720819
}

0 commit comments

Comments
 (0)