@@ -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+ "\n export 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)]
622694pub 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+
661737export 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
673749export 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