1 pub(crate) mod ctx; 2 pub(crate) mod rustproto_proto; 3 4 use std::fmt; 5 use std::ops::Deref; 6 use std::rc::Rc; 7 8 use protobuf::reflect::EnumDescriptor; 9 use protobuf::reflect::FieldDescriptor; 10 use protobuf::reflect::FileDescriptor; 11 use protobuf::reflect::MessageDescriptor; 12 use protobuf::reflect::OneofDescriptor; 13 14 /// Dynamic callback to customize code generation. 15 pub trait CustomizeCallback: 'static { file(&self, file: &FileDescriptor) -> Customize16 fn file(&self, file: &FileDescriptor) -> Customize { 17 let _ = file; 18 Customize::default() 19 } 20 message(&self, message: &MessageDescriptor) -> Customize21 fn message(&self, message: &MessageDescriptor) -> Customize { 22 let _ = message; 23 Customize::default() 24 } 25 field(&self, field: &FieldDescriptor) -> Customize26 fn field(&self, field: &FieldDescriptor) -> Customize { 27 let _ = field; 28 Customize::default() 29 } 30 special_field(&self, message: &MessageDescriptor, field: &str) -> Customize31 fn special_field(&self, message: &MessageDescriptor, field: &str) -> Customize { 32 let _ = (message, field); 33 Customize::default() 34 } 35 enumeration(&self, enum_type: &EnumDescriptor) -> Customize36 fn enumeration(&self, enum_type: &EnumDescriptor) -> Customize { 37 let _ = enum_type; 38 Customize::default() 39 } 40 oneof(&self, oneof: &OneofDescriptor) -> Customize41 fn oneof(&self, oneof: &OneofDescriptor) -> Customize { 42 let _ = oneof; 43 Customize::default() 44 } 45 } 46 47 pub(crate) struct CustomizeCallbackDefault; 48 impl CustomizeCallback for CustomizeCallbackDefault {} 49 50 #[derive(Clone)] 51 pub(crate) struct CustomizeCallbackHolder(pub(crate) Rc<dyn CustomizeCallback>); 52 53 impl CustomizeCallbackHolder { new(callback: impl CustomizeCallback) -> CustomizeCallbackHolder54 pub(crate) fn new(callback: impl CustomizeCallback) -> CustomizeCallbackHolder { 55 CustomizeCallbackHolder(Rc::new(callback)) 56 } 57 } 58 59 impl Deref for CustomizeCallbackHolder { 60 type Target = dyn CustomizeCallback; 61 deref(&self) -> &Self::Target62 fn deref(&self) -> &Self::Target { 63 &*self.0 64 } 65 } 66 67 impl Default for CustomizeCallbackHolder { default() -> Self68 fn default() -> Self { 69 CustomizeCallbackHolder(Rc::new(CustomizeCallbackDefault)) 70 } 71 } 72 73 impl PartialEq for CustomizeCallbackHolder { eq(&self, other: &Self) -> bool74 fn eq(&self, other: &Self) -> bool { 75 Rc::ptr_eq(&self.0, &other.0) 76 } 77 } 78 79 impl fmt::Debug for CustomizeCallbackHolder { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 81 f.debug_struct("CustomizeCallbackWrapper") 82 .finish_non_exhaustive() 83 } 84 } 85 86 /// Specifies style of generated code. 87 /// Generated files can be customized using this proto 88 /// or using `rustproto.proto` options. 89 #[derive(Default, Debug, Clone, PartialEq)] 90 pub struct Customize { 91 /// Code to insert before the element in the generated file. 92 pub(crate) before: Option<String>, 93 /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated 94 pub(crate) generate_accessors: Option<bool>, 95 /// When false, `get_` is not generated even if `syntax = "proto2"` 96 pub(crate) generate_getter: Option<bool>, 97 /// Use `bytes::Bytes` for `bytes` fields 98 pub(crate) tokio_bytes: Option<bool>, 99 /// Use `bytes::Bytes` for `string` fields 100 pub(crate) tokio_bytes_for_string: Option<bool>, 101 /// Enable lite runtime. 102 pub(crate) lite_runtime: Option<bool>, 103 /// Generate `mod.rs` in the output directory. 104 /// 105 /// This option allows inclusion of generated files from cargo output directory. 106 /// 107 /// This option will likely be on by default in rust-protobuf version 3. 108 pub(crate) gen_mod_rs: Option<bool>, 109 /// Used internally to generate protos bundled in protobuf crate 110 /// like `descriptor.proto` 111 pub(crate) inside_protobuf: Option<bool>, 112 } 113 114 #[derive(Debug, thiserror::Error)] 115 pub(crate) enum CustomizeParseParameterError { 116 #[error("Cannot parse bool option value: {:?}", .0)] 117 CannotParseBool(String), 118 #[error("Unknown option name: {:?}", .0)] 119 UnknownOptionName(String), 120 } 121 122 impl Customize { 123 /// Insert code before the element in the generated file 124 /// (e. g. serde annotations, see 125 /// [example here](https://github.com/stepancheg/rust-protobuf/tree/master/protobuf-examples/customize-serde)). before(mut self, before: &str) -> Self126 pub fn before(mut self, before: &str) -> Self { 127 self.before = Some(before.to_owned()); 128 self 129 } 130 generate_accessors(mut self, generate_accessors: bool) -> Self131 pub fn generate_accessors(mut self, generate_accessors: bool) -> Self { 132 self.generate_accessors = Some(generate_accessors); 133 self 134 } 135 generate_getter(mut self, generate_getter: bool) -> Self136 pub fn generate_getter(mut self, generate_getter: bool) -> Self { 137 self.generate_getter = Some(generate_getter); 138 self 139 } 140 tokio_bytes(mut self, tokio_bytes: bool) -> Self141 pub fn tokio_bytes(mut self, tokio_bytes: bool) -> Self { 142 self.tokio_bytes = Some(tokio_bytes); 143 self 144 } 145 tokio_bytes_for_string(mut self, tokio_bytes_for_string: bool) -> Self146 pub fn tokio_bytes_for_string(mut self, tokio_bytes_for_string: bool) -> Self { 147 self.tokio_bytes_for_string = Some(tokio_bytes_for_string); 148 self 149 } 150 151 /// Generate code for "lite runtime". Generated code contains no code for reflection. 152 /// So the generated code (and more importantly, generated binary size) is smaller, 153 /// but reflection, text format, JSON serialization won't work. 154 /// 155 /// Note when using `protoc` plugin `protoc-gen-rust`, the option name is just `lite`. lite_runtime(mut self, lite_runtime: bool) -> Self156 pub fn lite_runtime(mut self, lite_runtime: bool) -> Self { 157 self.lite_runtime = Some(lite_runtime); 158 self 159 } 160 161 /// Generate `mod.rs` with all the generated modules. 162 /// This option is on by default in rust-protobuf version 3. gen_mod_rs(mut self, gen_mod_rs: bool) -> Self163 pub fn gen_mod_rs(mut self, gen_mod_rs: bool) -> Self { 164 self.gen_mod_rs = Some(gen_mod_rs); 165 self 166 } 167 168 /// Generate code bundled in protobuf crate. Regular users don't need this option. inside_protobuf(mut self, inside_protobuf: bool) -> Self169 pub fn inside_protobuf(mut self, inside_protobuf: bool) -> Self { 170 self.inside_protobuf = Some(inside_protobuf); 171 self 172 } 173 174 /// Update fields of self with fields defined in other customize update_with(&mut self, that: &Customize)175 pub fn update_with(&mut self, that: &Customize) { 176 if let Some(v) = &that.before { 177 self.before = Some(v.clone()); 178 } 179 if let Some(v) = that.generate_accessors { 180 self.generate_accessors = Some(v); 181 } 182 if let Some(v) = that.generate_getter { 183 self.generate_getter = Some(v); 184 } 185 if let Some(v) = that.tokio_bytes { 186 self.tokio_bytes = Some(v); 187 } 188 if let Some(v) = that.tokio_bytes_for_string { 189 self.tokio_bytes_for_string = Some(v); 190 } 191 if let Some(v) = that.lite_runtime { 192 self.lite_runtime = Some(v); 193 } 194 if let Some(v) = that.gen_mod_rs { 195 self.gen_mod_rs = Some(v); 196 } 197 if let Some(v) = that.inside_protobuf { 198 self.inside_protobuf = Some(v); 199 } 200 } 201 202 /// Update unset fields of self with fields from other customize set_defaults_from(&mut self, other: &Customize)203 pub fn set_defaults_from(&mut self, other: &Customize) { 204 let mut tmp = other.clone(); 205 tmp.update_with(self); 206 *self = tmp; 207 } 208 209 /// Parse customize options from a string passed via protoc flag. parse_from_parameter(parameter: &str) -> anyhow::Result<Customize>210 pub fn parse_from_parameter(parameter: &str) -> anyhow::Result<Customize> { 211 fn parse_bool(v: &str) -> anyhow::Result<bool> { 212 v.parse() 213 .map_err(|_| CustomizeParseParameterError::CannotParseBool(v.to_owned()).into()) 214 } 215 216 let mut r = Customize::default(); 217 for nv in parameter.split_whitespace() { 218 let (n, v) = match nv.find('=') { 219 Some(eq) => { 220 let n = &nv[..eq]; 221 let v = &nv[eq + 1..]; 222 (n, v) 223 } 224 None => (nv, "true"), 225 }; 226 227 if n == "generate_accessors" { 228 r.generate_accessors = Some(parse_bool(v)?); 229 } else if n == "generate_getter" { 230 r.generate_getter = Some(parse_bool(v)?); 231 } else if n == "tokio_bytes" { 232 r.tokio_bytes = Some(parse_bool(v)?); 233 } else if n == "tokio_bytes_for_string" { 234 r.tokio_bytes_for_string = Some(parse_bool(v)?); 235 } else if n == "lite_runtime" { 236 r.lite_runtime = Some(parse_bool(v)?); 237 } else if n == "gen_mod_rs" { 238 r.gen_mod_rs = Some(parse_bool(v)?); 239 } else if n == "inside_protobuf" { 240 r.inside_protobuf = Some(parse_bool(v)?); 241 } else if n == "lite" { 242 // Support Java and C++ protoc plugin syntax: 243 // https://github.com/protocolbuffers/protobuf/issues/6489 244 r.lite_runtime = Some(parse_bool(v)?); 245 } else { 246 return Err(CustomizeParseParameterError::UnknownOptionName(n.to_owned()).into()); 247 } 248 } 249 Ok(r) 250 } 251 } 252