11use anyhow:: { anyhow, Context , Result } ;
2+ use prost:: Message ;
23use prost_build:: Config ;
4+ use prost_types:: FileDescriptorSet ;
35use std:: {
46 fs:: { self , File } ,
5- io:: { Read , Write } ,
6- path:: Path ,
7+ io:: { BufReader , Read , Write } ,
8+ path:: { Path , PathBuf } ,
79} ;
810
911use crate :: svcgen:: { AsyncMode , TtrpcServiceGenerator } ;
1012
13+ const FILE_DESCRIPTOR_SET : & str = "fd_set.bin" ;
14+
1115pub struct Codegen < ' a , P : AsRef < Path > > {
1216 out_dir : & ' a P ,
1317 protos : & ' a [ P ] ,
1418 includes : & ' a [ P ] ,
1519 /// Whether to enable serde
1620 serde : bool ,
1721 async_mode : AsyncMode ,
22+ /// Whether to generate service
23+ generate_service : bool ,
1824}
1925
2026impl < ' a , P > Codegen < ' a , P >
@@ -24,27 +30,30 @@ where
2430 pub fn generate ( & self ) -> Result < ( ) > {
2531 self . compile_protos ( ) . context ( "Compile protos" ) ?;
2632 self . write_header ( ) . context ( "Write header" ) ?;
33+ self . clean_up ( ) . context ( "Clean up" ) ?;
2734
2835 Ok ( ( ) )
2936 }
3037
38+ // TODO: Do not write header to the files that already has the header
39+ // TODO: Write header to the files generated by the codegen
3140 fn write_header ( & self ) -> Result < ( ) > {
32- let dir = fs:: read_dir ( self . out_dir . as_ref ( ) ) . context ( "Read out_dir" ) ?;
33-
34- for child in dir {
35- let entry = child. context ( "Unable to get entry" ) ?;
36- let path = entry. path ( ) ;
37- let ext = match path. extension ( ) {
38- Some ( ext) => match ext. to_str ( ) {
39- Some ( ext) => ext,
40- None => "" ,
41- } ,
42- None => "" ,
41+ // Read fd_set.bin
42+ let f = File :: open ( PathBuf :: from ( self . out_dir . as_ref ( ) ) . join ( FILE_DESCRIPTOR_SET ) )
43+ . context ( "Open fd_set.bin" ) ?;
44+ let mut reader = BufReader :: new ( f) ;
45+ let mut buffer = Vec :: new ( ) ;
46+ reader. read_to_end ( & mut buffer) . context ( "Read fd_set.bin" ) ?;
47+
48+ let fd_set = FileDescriptorSet :: decode ( & buffer as & [ u8 ] ) . context ( "Decode fd_set" ) ?;
49+
50+ for fd in fd_set. file . iter ( ) {
51+ let rs_path =
52+ PathBuf :: from ( self . out_dir . as_ref ( ) ) . join ( & format ! ( "{}.rs" , fd. package( ) ) ) ;
53+ let mut f = match File :: open ( & rs_path) {
54+ Ok ( f) => f,
55+ _ => continue ,
4356 } ;
44- if entry. file_name ( ) == "mod.rs" || ext != "rs" {
45- continue ;
46- }
47-
4857 let header = format ! (
4958 r#"// This file is generated by ttrpc-codegen {}. Do not edit
5059// @generated
@@ -55,12 +64,11 @@ where
5564
5665 let mut buf = Vec :: < u8 > :: new ( ) ;
5766 buf. write ( header. as_bytes ( ) ) . context ( "Write header" ) ?;
58- let mut f = File :: open ( & path) . context ( format ! ( "Open rust file {:?}" , path) ) ?;
5967 f. read_to_end ( & mut buf)
60- . context ( format ! ( "Read from rust file {:?}" , path ) ) ?;
61- let mut f = File :: create ( & path ) . context ( format ! ( "Open rust file {:?}" , path ) ) ?;
68+ . context ( format ! ( "Read from rust file {:?}" , rs_path ) ) ?;
69+ let mut f = File :: create ( & rs_path ) . context ( format ! ( "Open rust file {:?}" , rs_path ) ) ?;
6270 f. write_all ( buf. as_slice ( ) )
63- . context ( format ! ( "Write to rust file {:?}" , path ) ) ?;
71+ . context ( format ! ( "Write to rust file {:?}" , rs_path ) ) ?;
6472 }
6573
6674 Ok ( ( ) )
@@ -72,39 +80,47 @@ where
7280 config. service_generator ( Box :: new ( TtrpcServiceGenerator :: new ( self . async_mode ) ) ) ;
7381 config. protoc_arg ( "--experimental_allow_proto3_optional" ) ;
7482 config. compile_well_known_types ( ) ;
75- config. include_file ( "_include.rs" ) ;
76- if self . serde {
77- config. message_attribute ( "." , "#[derive(::serde::Serialize, ::serde::Deserialize)]" ) ;
83+ config. file_descriptor_set_path (
84+ PathBuf :: from ( self . out_dir . as_ref ( ) ) . join ( FILE_DESCRIPTOR_SET ) ,
85+ ) ;
86+ if self . generate_service {
87+ config. include_file ( "_include.rs" ) ;
88+ if self . serde {
89+ config
90+ . message_attribute ( "." , "#[derive(::serde::Serialize, ::serde::Deserialize)]" ) ;
91+ }
7892 }
7993 config
8094 . compile_protos ( self . protos , self . includes )
8195 . context ( "Compile protos by prost" ) ?;
8296 Ok ( ( ) )
8397 }
98+
99+ fn clean_up ( & self ) -> Result < ( ) > {
100+ fs:: remove_file ( PathBuf :: from ( self . out_dir . as_ref ( ) ) . join ( FILE_DESCRIPTOR_SET ) )
101+ . context ( "Remove fd_set.bin" ) ?;
102+ Ok ( ( ) )
103+ }
84104}
85105
86106#[ derive( Default ) ]
87- pub struct CodegenBuilder < ' a , P : AsRef < Path > > {
107+ pub struct CodegenBuilder < ' a , P : AsRef < Path > + Default > {
88108 out_dir : Option < & ' a P > ,
89109 protos : Option < & ' a [ P ] > ,
90110 includes : Option < & ' a [ P ] > ,
91111 /// Whether to enable serde
92112 serde : Option < bool > ,
93113 async_mode : Option < AsyncMode > ,
114+ /// Whether to generate service
115+ generate_service : Option < bool > ,
94116}
95117
96118impl < ' a , P > CodegenBuilder < ' a , P >
97119where
98- P : AsRef < Path > ,
120+ P : AsRef < Path > + Default ,
99121{
100122 pub fn new ( ) -> Self {
101- Self {
102- out_dir : None ,
103- protos : None ,
104- includes : None ,
105- serde : None ,
106- async_mode : None ,
107- }
123+ Default :: default ( )
108124 }
109125
110126 pub fn set_out_dir ( mut self , out_dir : & ' a P ) -> Self {
@@ -132,6 +148,11 @@ where
132148 self
133149 }
134150
151+ pub fn set_generate_service ( mut self , generate_service : bool ) -> Self {
152+ self . generate_service = Some ( generate_service) ;
153+ self
154+ }
155+
135156 pub fn build ( & self ) -> Result < Codegen < ' a , P > > {
136157 let out_dir = match self . out_dir {
137158 Some ( out_dir) => out_dir,
@@ -158,12 +179,18 @@ where
158179 None => AsyncMode :: None ,
159180 } ;
160181
182+ let generate_service = match self . generate_service {
183+ Some ( gen) => gen,
184+ None => false ,
185+ } ;
186+
161187 Ok ( Codegen {
162188 out_dir,
163189 protos,
164190 includes,
165191 serde,
166192 async_mode,
193+ generate_service,
167194 } )
168195 }
169196}
0 commit comments