1
1
use anyhow:: { anyhow, Context , Result } ;
2
+ use prost:: Message ;
2
3
use prost_build:: Config ;
4
+ use prost_types:: FileDescriptorSet ;
3
5
use std:: {
4
6
fs:: { self , File } ,
5
- io:: { Read , Write } ,
6
- path:: Path ,
7
+ io:: { BufReader , Read , Write } ,
8
+ path:: { Path , PathBuf } ,
7
9
} ;
8
10
9
11
use crate :: svcgen:: { AsyncMode , TtrpcServiceGenerator } ;
10
12
13
+ const FILE_DESCRIPTOR_SET : & str = "fd_set.bin" ;
14
+
11
15
pub struct Codegen < ' a , P : AsRef < Path > > {
12
16
out_dir : & ' a P ,
13
17
protos : & ' a [ P ] ,
14
18
includes : & ' a [ P ] ,
15
19
/// Whether to enable serde
16
20
serde : bool ,
17
21
async_mode : AsyncMode ,
22
+ /// Whether to generate service
23
+ generate_service : bool ,
18
24
}
19
25
20
26
impl < ' a , P > Codegen < ' a , P >
@@ -24,27 +30,30 @@ where
24
30
pub fn generate ( & self ) -> Result < ( ) > {
25
31
self . compile_protos ( ) . context ( "Compile protos" ) ?;
26
32
self . write_header ( ) . context ( "Write header" ) ?;
33
+ self . clean_up ( ) . context ( "Clean up" ) ?;
27
34
28
35
Ok ( ( ) )
29
36
}
30
37
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
31
40
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 ,
43
56
} ;
44
- if entry. file_name ( ) == "mod.rs" || ext != "rs" {
45
- continue ;
46
- }
47
-
48
57
let header = format ! (
49
58
r#"// This file is generated by ttrpc-codegen {}. Do not edit
50
59
// @generated
@@ -55,12 +64,11 @@ where
55
64
56
65
let mut buf = Vec :: < u8 > :: new ( ) ;
57
66
buf. write ( header. as_bytes ( ) ) . context ( "Write header" ) ?;
58
- let mut f = File :: open ( & path) . context ( format ! ( "Open rust file {:?}" , path) ) ?;
59
67
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 ) ) ?;
62
70
f. write_all ( buf. as_slice ( ) )
63
- . context ( format ! ( "Write to rust file {:?}" , path ) ) ?;
71
+ . context ( format ! ( "Write to rust file {:?}" , rs_path ) ) ?;
64
72
}
65
73
66
74
Ok ( ( ) )
@@ -72,39 +80,47 @@ where
72
80
config. service_generator ( Box :: new ( TtrpcServiceGenerator :: new ( self . async_mode ) ) ) ;
73
81
config. protoc_arg ( "--experimental_allow_proto3_optional" ) ;
74
82
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
+ }
78
92
}
79
93
config
80
94
. compile_protos ( self . protos , self . includes )
81
95
. context ( "Compile protos by prost" ) ?;
82
96
Ok ( ( ) )
83
97
}
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
+ }
84
104
}
85
105
86
106
#[ derive( Default ) ]
87
- pub struct CodegenBuilder < ' a , P : AsRef < Path > > {
107
+ pub struct CodegenBuilder < ' a , P : AsRef < Path > + Default > {
88
108
out_dir : Option < & ' a P > ,
89
109
protos : Option < & ' a [ P ] > ,
90
110
includes : Option < & ' a [ P ] > ,
91
111
/// Whether to enable serde
92
112
serde : Option < bool > ,
93
113
async_mode : Option < AsyncMode > ,
114
+ /// Whether to generate service
115
+ generate_service : Option < bool > ,
94
116
}
95
117
96
118
impl < ' a , P > CodegenBuilder < ' a , P >
97
119
where
98
- P : AsRef < Path > ,
120
+ P : AsRef < Path > + Default ,
99
121
{
100
122
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 ( )
108
124
}
109
125
110
126
pub fn set_out_dir ( mut self , out_dir : & ' a P ) -> Self {
@@ -132,6 +148,11 @@ where
132
148
self
133
149
}
134
150
151
+ pub fn set_generate_service ( mut self , generate_service : bool ) -> Self {
152
+ self . generate_service = Some ( generate_service) ;
153
+ self
154
+ }
155
+
135
156
pub fn build ( & self ) -> Result < Codegen < ' a , P > > {
136
157
let out_dir = match self . out_dir {
137
158
Some ( out_dir) => out_dir,
@@ -158,12 +179,18 @@ where
158
179
None => AsyncMode :: None ,
159
180
} ;
160
181
182
+ let generate_service = match self . generate_service {
183
+ Some ( gen) => gen,
184
+ None => false ,
185
+ } ;
186
+
161
187
Ok ( Codegen {
162
188
out_dir,
163
189
protos,
164
190
includes,
165
191
serde,
166
192
async_mode,
193
+ generate_service,
167
194
} )
168
195
}
169
196
}
0 commit comments