1use convert_case::Case;
2use proc_macro2::TokenStream;
3use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
4use syn::{punctuated::Punctuated, spanned::Spanned, Ident, LitStr};
5use syn_prelude::{ToIdent, ToIdentWithCase, ToLitStr, WithPrefix, WithSuffix};
6
7use crate::model::{
8 DeclIndex, EnumValue, Enumeration, Field, FieldType, GetOption, Message, MessageElement,
9 Method, Modifier, NestedTypeIndex, OneOf, Package, ProtobufOption, ProtobufPath, Protocol,
10 Service, Type,
11};
12
13impl ToTokens for Protocol {
14 fn to_tokens(&self, tokens: &mut TokenStream) {
15 self.to_token_stream_with_extra(tokens, TokenStream::new())
16 }
17}
18
19impl Protocol {
20 pub fn to_token_stream_with_extra(&self, tokens: &mut TokenStream, extra: TokenStream) {
21 let decls = self
22 .decls
23 .iter()
24 .map(|index| match index {
25 DeclIndex::Message(idx) => self.messages.get(*idx).map(Message::to_tokens),
26 DeclIndex::Enum(idx) => self.enums.get(*idx).map(Enumeration::to_tokens),
27 DeclIndex::Service(idx) => {
28 self.services.get(*idx).map(|s| s.to_tokens(&self.package))
29 }
30 })
31 .collect::<Vec<_>>();
32 if let Some(Package { package }) = &self.package {
33 tokens.append_all(quote! {
34 pub mod #package {
35 #(#decls)*
36 #extra
37 }
38 })
39 } else {
40 tokens.append_all(quote! {
41 #(#decls)*
42 #extra
43 })
44 }
45 }
46}
47
48impl Message {
49 fn to_tokens(&self) -> TokenStream {
50 let Self {
51 name,
52 struct_name,
53 messages,
54 enums,
55 fields,
56 nested_types,
57 ..
58 } = self;
59
60 let field_tokens = fields.iter().map(|field| match field {
61 MessageElement::Field(field) => field.to_tokens(),
62 MessageElement::OneOf(OneOf {
63 field_name,
64 enum_name: type_name,
65 field_lit,
66 tags,
67 options,
68 ..
69 }) => {
70 let deprecated = options.deprecated();
71 let nested_mod_name = name.to_ident_with_case(Case::Snake);
72 quote! {
73 #deprecated
74 #[prost(oneof=#field_lit, tags=#tags)]
75 pub #field_name: Option<#nested_mod_name::#type_name>
76 }
77 }
78 });
79
80 let nested = if !nested_types.is_empty() {
81 let nested = nested_types
82 .iter()
83 .filter_map(|i| match i {
84 NestedTypeIndex::Message(idx) => {
85 messages.get(*idx).map(|mesage| mesage.to_tokens())
86 }
87 NestedTypeIndex::Enum(idx) => {
88 enums.get(*idx).map(|enumeration| enumeration.to_tokens())
89 }
90 NestedTypeIndex::Oneof(idx) => fields
91 .get(*idx)
92 .map(|f| match f {
93 MessageElement::Field(_) => None,
94 MessageElement::OneOf(oneof) => Some(oneof.to_tokens()),
95 })
96 .flatten(),
97 })
98 .collect::<Vec<_>>();
99
100 let nested_mod_name = name.to_ident_with_case(Case::Snake);
101 Some(quote! {
102 pub mod #nested_mod_name {
103 #(#nested)*
104 }
105 })
106 } else {
107 None
108 };
109
110 let mut derives = vec![quote!(Clone), quote!(PartialEq), quote!(prost::Message)];
111 if cfg!(feature = "derive_serde") {
112 derives.push(quote!(serde::Deserialize));
113 derives.push(quote!(serde::Serialize));
114 };
115
116 quote! {
117 #[allow(clippy::derive_partial_eq_without_eq)]
118 #[derive(#(#derives),*)]
119 pub struct #struct_name {
120 #(#field_tokens),*
121 }
122
123 #nested
124 }
125 }
126}
127
128impl Field {
129 fn to_tokens(&self) -> TokenStream {
130 let Field {
131 field_name,
132 typ,
133 tag: number,
134 options,
135 ..
136 } = self;
137 let deprecated = options.deprecated();
138 let tag = number.to_lit_str();
139
140 let (optional, repeated, field_type) = self.to_type_tokens();
141
142 let mut prost_args = vec![];
143 prost_args.push(typ.to_prost_type());
144 if optional {
145 prost_args.push(quote!(optional));
146 } else if repeated {
147 prost_args.push(quote!(repeated));
148 }
149 prost_args.push(quote!(tag=#tag));
150
151 quote! {
152 #deprecated
153 #[prost(#(#prost_args),*)]
154 pub #field_name: #field_type
155 }
156 }
157
158 fn to_type_tokens(&self) -> (bool, bool, TokenStream) {
159 let Field {
160 modifier,
161 typ,
162 options,
163 enum_field,
164 ..
165 } = self;
166 let field_type = typ.to_tokens(Some(options));
167 let mut optional = false;
168 let mut repeated = false;
169 let typ = if let Some(modifier) = modifier {
170 match modifier {
171 Modifier::Optional => {
172 optional = true;
173 quote!(Option<#field_type>)
174 }
175 Modifier::Repeated => {
176 repeated = true;
177 quote!(::prost::alloc::vec::Vec<#field_type>)
178 }
179 Modifier::Required => field_type,
180 }
181 } else if !enum_field && typ.is_message() {
182 quote!(Option<#field_type>)
183 } else {
184 field_type
185 };
186 (optional, repeated, typ)
187 }
188}
189
190impl Service {
191 fn to_tokens(&self, package: &Option<Package>) -> TokenStream {
192 let Self { name, .. } = self;
193
194 let service_name = if let Some(package) = package.as_ref() {
195 name.to_lit_str().with_prefix(package.package.to_string())
196 } else {
197 name.to_lit_str()
198 };
199
200 let client = self.impl_client(&service_name);
201 let server = self.impl_server(&service_name);
202
203 quote! {
204 #client
205 #server
206 }
207 }
208
209 fn impl_client(&self, service_name: &LitStr) -> TokenStream {
210 let client_mod = self
211 .name
212 .to_ident_with_case(Case::Snake)
213 .with_suffix("_client");
214
215 let client_name = self.code_name.with_suffix("Client");
216 let methods = self
217 .methods
218 .iter()
219 .map(|m| m.impl_client_method(service_name))
220 .collect::<Vec<_>>();
221
222 quote! {
223 pub mod #client_mod {
224 #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
225 use tonic::codegen::*;
226 use tonic::codegen::http::Uri;
227
228 pub struct #client_name<T> {
229 inner: tonic::client::Grpc<T>,
230 }
231
232 impl #client_name<tonic::transport::Channel> {
233 pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
234 where
235 D: TryInto<tonic::transport::Endpoint>,
236 D::Error: Into<StdError>,
237 {
238 let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
239 Ok(Self::new(conn))
240 }
241 }
242
243 impl<T> #client_name<T>
244 where
245 T: tonic::client::GrpcService<tonic::body::BoxBody>,
246 T::Error: Into<StdError>,
247 T::ResponseBody: Body<Data = Bytes> + Send + 'static,
248 <T::ResponseBody as Body>::Error: Into<StdError> + Send,
249 {
250 pub fn new(inner: T) -> Self {
251 let inner = tonic::client::Grpc::new(inner);
252 Self { inner }
253 }
254 pub fn with_origin(inner: T, origin: Uri) -> Self {
255 let inner = tonic::client::Grpc::with_origin(inner, origin);
256 Self { inner }
257 }
258 pub fn with_interceptor<F>(
259 inner: T,
260 interceptor: F,
261 ) -> #client_name<InterceptedService<T, F>>
262 where
263 F: tonic::service::Interceptor,
264 T::ResponseBody: Default,
265 T: tonic::codegen::Service<
266 http::Request<tonic::body::BoxBody>,
267 Response = http::Response<
268 <T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
269 >,
270 >,
271 <T as tonic::codegen::Service<
272 http::Request<tonic::body::BoxBody>,
273 >>::Error: Into<StdError> + Send + Sync,
274 {
275 #client_name::new(InterceptedService::new(inner, interceptor))
276 }
277 #[must_use]
282 pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
283 self.inner = self.inner.send_compressed(encoding);
284 self
285 }
286 #[must_use]
288 pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
289 self.inner = self.inner.accept_compressed(encoding);
290 self
291 }
292 #[must_use]
296 pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
297 self.inner = self.inner.max_decoding_message_size(limit);
298 self
299 }
300 #[must_use]
304 pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
305 self.inner = self.inner.max_encoding_message_size(limit);
306 self
307 }
308
309 #(#methods)*
310 }
311 }
312 }
313 }
314
315 fn impl_server(&self, service_name: &LitStr) -> TokenStream {
316 let Self {
317 name,
318 code_name,
319 methods,
320 ..
321 } = self;
322
323 let server_mod = name.to_ident_with_case(Case::Snake).with_suffix("_server");
324 let trait_methods = methods
325 .iter()
326 .map(|m| m.impl_server_trait_method())
327 .collect::<Vec<_>>();
328
329 let server_name = code_name.with_suffix("Server");
330 let svc_cases = methods
331 .iter()
332 .map(|m| m.impl_server_method_switch(service_name, code_name))
333 .collect::<Vec<_>>();
334
335 quote! {
336 pub mod #server_mod {
337 #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
338 use tonic::codegen::*;
339
340 #[async_trait]
341 pub trait #code_name: Send + Sync + 'static {
342 #(#trait_methods)*
343 }
344
345 #[derive(Debug)]
346 pub struct #server_name<T: #code_name> {
347 inner: _Inner<T>,
348 accept_compression_encodings: EnabledCompressionEncodings,
349 send_compression_encodings: EnabledCompressionEncodings,
350 max_decoding_message_size: Option<usize>,
351 max_encoding_message_size: Option<usize>,
352 }
353
354 struct _Inner<T>(Arc<T>);
355
356 impl<T: #code_name> #server_name<T> {
357 pub fn new(inner: T) -> Self {
358 Self::from_arc(Arc::new(inner))
359 }
360 pub fn from_arc(inner: Arc<T>) -> Self {
361 let inner = _Inner(inner);
362 Self {
363 inner,
364 accept_compression_encodings: Default::default(),
365 send_compression_encodings: Default::default(),
366 max_decoding_message_size: None,
367 max_encoding_message_size: None,
368 }
369 }
370 pub fn with_interceptor<F>(
371 inner: T,
372 interceptor: F,
373 ) -> InterceptedService<Self, F>
374 where
375 F: tonic::service::Interceptor,
376 {
377 InterceptedService::new(Self::new(inner), interceptor)
378 }
379 #[must_use]
381 pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
382 self.accept_compression_encodings.enable(encoding);
383 self
384 }
385 #[must_use]
387 pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
388 self.send_compression_encodings.enable(encoding);
389 self
390 }
391 #[must_use]
395 pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
396 self.max_decoding_message_size = Some(limit);
397 self
398 }
399 #[must_use]
403 pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
404 self.max_encoding_message_size = Some(limit);
405 self
406 }
407 }
408 impl<T, B> tonic::codegen::Service<http::Request<B>> for #server_name<T>
409 where
410 T: #code_name,
411 B: Body + Send + 'static,
412 B::Error: Into<StdError> + Send + 'static,
413 {
414 type Response = http::Response<tonic::body::BoxBody>;
415 type Error = std::convert::Infallible;
416 type Future = BoxFuture<Self::Response, Self::Error>;
417 fn poll_ready(
418 &mut self,
419 _cx: &mut Context<'_>,
420 ) -> Poll<std::result::Result<(), Self::Error>> {
421 Poll::Ready(Ok(()))
422 }
423 fn call(&mut self, req: http::Request<B>) -> Self::Future {
424 let inner = self.inner.clone();
425 match req.uri().path() {
426 #(#svc_cases)*
427 _ => {
428 Box::pin(async move {
429 Ok(
430 http::Response::builder()
431 .status(200)
432 .header("grpc-status", "12")
433 .header("content-type", "application/grpc")
434 .body(empty_body())
435 .unwrap(),
436 )
437 })
438 }
439 }
440 }
441 }
442 impl<T: #code_name> Clone for #server_name<T> {
443 fn clone(&self) -> Self {
444 let inner = self.inner.clone();
445 Self {
446 inner,
447 accept_compression_encodings: self.accept_compression_encodings,
448 send_compression_encodings: self.send_compression_encodings,
449 max_decoding_message_size: self.max_decoding_message_size,
450 max_encoding_message_size: self.max_encoding_message_size,
451 }
452 }
453 }
454 impl<T: #code_name> Clone for _Inner<T> {
455 fn clone(&self) -> Self {
456 Self(Arc::clone(&self.0))
457 }
458 }
459 impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
460 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
461 write!(f, "{:?}", self.0)
462 }
463 }
464 impl<T: #code_name> tonic::server::NamedService for #server_name<T> {
465 const NAME: &'static str = #service_name;
466 }
467 }
468 }
469 }
470}
471
472impl Method {
473 fn impl_client_method(&self, service_name: &LitStr) -> TokenStream {
474 let Self {
475 method_name,
476 input_type,
477 output_type,
478 ..
479 } = self;
480
481 let method_name_lit = method_name
482 .to_ident_with_case(Case::UpperCamel)
483 .to_lit_str();
484 let request_path = method_name_lit.with_prefix(format!("/{}/", service_name.value()));
485
486 quote! {
487 pub async fn #method_name(&mut self, request: impl tonic::IntoRequest<#input_type>) -> std::result::Result<tonic::Response<#output_type>, tonic::Status> {
488 self.inner
489 .ready()
490 .await
491 .map_err(|e| {
492 tonic::Status::new(
493 tonic::Code::Unknown,
494 format!("Service was not ready: {}", e.into()),
495 )
496 })?;
497 let codec = tonic::codec::ProstCodec::default();
498 let path = http::uri::PathAndQuery::from_static(#request_path);
499 let mut req = request.into_request();
500 req.extensions_mut().insert(GrpcMethod::new(#service_name, #method_name_lit));
501 self.inner.unary(req, path, codec).await
502 }
503 }
504 }
505
506 fn impl_server_trait_method(&self) -> TokenStream {
507 let Self {
508 method_name,
509 input_type: Type { ty: input_type, .. },
510 output_type: Type {
511 ty: output_type, ..
512 },
513 ..
514 } = self;
515
516 quote! {
517 async fn #method_name(
518 &self,
519 request: tonic::Request<#input_type>,
520 ) -> std::result::Result<
521 tonic::Response<#output_type>,
522 tonic::Status,
523 >;
524 }
525 }
526
527 fn impl_server_method_switch(
528 &self,
529 service_name: &LitStr,
530 server_trait: &Ident,
531 ) -> TokenStream {
532 let Self {
533 name,
534 method_name,
535 input_type,
536 output_type,
537 ..
538 } = self;
539 let case_lit = service_name
540 .with_prefix("/")
541 .with_suffix("/")
542 .with_suffix(name.to_ident_with_case(Case::UpperCamel).to_string());
543
544 let struct_name = name.to_ident_with_case(Case::Camel).with_suffix("Svc");
545
546 quote! {
547 #case_lit => {
548 #[allow(non_camel_case_types)]
549 struct #struct_name<T: #server_trait>(pub Arc<T>);
550 impl<T: #server_trait> tonic::server::UnaryService<#input_type>
551 for #struct_name<T> {
552 type Response = #output_type;
553 type Future = BoxFuture<
554 tonic::Response<Self::Response>,
555 tonic::Status,
556 >;
557 fn call(
558 &mut self,
559 request: tonic::Request<#input_type>,
560 ) -> Self::Future {
561 let inner = Arc::clone(&self.0);
562 let fut = async move {
563 <T as #server_trait>::#method_name(&inner, request).await
564 };
565 Box::pin(fut)
566 }
567 }
568 let accept_compression_encodings = self.accept_compression_encodings;
569 let send_compression_encodings = self.send_compression_encodings;
570 let max_decoding_message_size = self.max_decoding_message_size;
571 let max_encoding_message_size = self.max_encoding_message_size;
572 let inner = self.inner.clone();
573 let fut = async move {
574 let inner = inner.0;
575 let method = #struct_name(inner);
576 let codec = tonic::codec::ProstCodec::default();
577 let mut grpc = tonic::server::Grpc::new(codec)
578 .apply_compression_config(
579 accept_compression_encodings,
580 send_compression_encodings,
581 )
582 .apply_max_message_size_config(
583 max_decoding_message_size,
584 max_encoding_message_size,
585 );
586 let res = grpc.unary(method, req).await;
587 Ok(res)
588 };
589 Box::pin(fut)
590 }
591 }
592 }
593}
594
595impl Enumeration {
596 fn to_tokens(&self) -> TokenStream {
597 let Self { name, values, .. } = self;
598 let variants = values
599 .iter()
600 .map(
601 |EnumValue {
602 variant_name,
603 tag: number,
604 ..
605 }| {
606 quote! { #variant_name = #number }
607 },
608 )
609 .collect::<Vec<_>>();
610
611 let name = name.to_ident_with_case(Case::UpperCamel);
612
613 let as_str_cases = values
614 .iter()
615 .map(
616 |EnumValue {
617 variant_name,
618 proto_name,
619 ..
620 }| {
621 quote! {Self::#variant_name => #proto_name}
622 },
623 )
624 .collect::<Vec<_>>();
625
626 let from_str_cases = values.iter().map(
627 |EnumValue {
628 variant_name,
629 proto_name,
630 ..
631 }| {
632 quote! { #proto_name => Some(Self::#variant_name) }
633 },
634 );
635
636 let mut derives = vec![
637 quote!(Clone),
638 quote!(Copy),
639 quote!(Debug),
640 quote!(Eq),
641 quote!(PartialEq),
642 quote!(PartialOrd),
643 quote!(Ord),
644 quote!(Hash),
645 quote!(prost::Enumeration),
646 ];
647 if cfg!(feature = "derive_serde") {
648 derives.push(quote!(serde::Deserialize));
649 derives.push(quote!(serde::Serialize));
650 }
651
652 quote! {
653 #[derive(#(#derives),*)]
654 #[repr(i32)]
655 pub enum #name {
656 #(#variants),*
657 }
658
659 impl #name {
660 pub fn as_str_name(&self) -> &'static str {
665 match self {
666 #(#as_str_cases),*
667 }
668 }
669
670 pub fn from_str_name(value: &str) -> Option<Self> {
672 match value {
673 #(#from_str_cases,)*
674 _ => None,
675 }
676 }
677 }
678
679 }
680 }
681}
682
683impl OneOf {
684 fn to_tokens(&self) -> TokenStream {
685 let Self {
686 enum_name, fields, ..
687 } = self;
688 let field_tokens = fields.iter().map(|field| {
689 let Field { name, typ, tag, .. } = field;
690 let prost_type = typ.to_prost_type();
691 let (_, _, typ) = field.to_type_tokens();
692 let name = name.to_ident_with_case(Case::UpperCamel);
693 let tag = tag.to_lit_str();
694 quote! {
695 #[prost(#prost_type, tag = #tag)]
696 #name(#typ)
697 }
698 });
699
700 let mut derives = vec![quote!(Clone), quote!(PartialEq), quote!(prost::Oneof)];
701 if cfg!(feature = "derive_serde") {
702 derives.push(quote!(serde::Deserialize));
703 derives.push(quote!(serde::Serialize));
704 }
705
706 quote! {
707 #[allow(clippy::derive_partial_eq_without_eq)]
708 #[derive(#(#derives),*)]
709 pub enum #enum_name {
710 #(#field_tokens),*
711 }
712 }
713 }
714}
715
716impl ToTokens for ProtobufPath {
717 fn to_tokens(&self, tokens: &mut TokenStream) {
718 let idents = self.segments.iter().collect::<Vec<_>>();
719 tokens.append_all(quote!(#(#idents)::*))
720 }
721}
722
723impl ToTokens for Type {
724 fn to_tokens(&self, tokens: &mut TokenStream) {
725 let Self {
726 ty: complete_path, ..
727 } = self;
728 tokens.append_all(quote!(#complete_path))
729 }
730}
731
732impl FieldType {
733 fn to_tokens(&self, options: Option<&Vec<ProtobufOption>>) -> TokenStream {
734 match self {
735 FieldType::Int32(span) => Ident::new("i32", *span).to_token_stream(),
736 FieldType::Int64(span) => Ident::new("i64", *span).to_token_stream(),
737 FieldType::Uint32(span) => Ident::new("u32", *span).to_token_stream(),
738 FieldType::Uint64(span) => Ident::new("u64", *span).to_token_stream(),
739 FieldType::Sint32(span) => Ident::new("i32", *span).to_token_stream(),
740 FieldType::Sint64(span) => Ident::new("i64", *span).to_token_stream(),
741 FieldType::Bool(span) => Ident::new("bool", *span).to_token_stream(),
742 FieldType::Fixed32(span) => Ident::new("u32", *span).to_token_stream(),
743 FieldType::Sfixed32(span) => Ident::new("i32", *span).to_token_stream(),
744 FieldType::Fixed64(span) => Ident::new("u64", *span).to_token_stream(),
745 FieldType::Sfixed64(span) => Ident::new("i64", *span).to_token_stream(),
746 FieldType::Float(span) => Ident::new("f32", *span).to_token_stream(),
747 FieldType::Double(span) => Ident::new("f64", *span).to_token_stream(),
748 FieldType::String(span) => quote_spanned!(*span => ::prost::alloc::string::String),
749 FieldType::Bytes(span) => quote_spanned!(*span => ::prost::alloc::vec::Vec<u8>),
750 FieldType::MessageOrEnum(ty) => {
751 if ty.target_is_message {
752 ty.ty.to_token_stream()
753 } else {
754 Ident::new("i32", ty.type_path.span()).to_token_stream()
755 }
756 }
757 FieldType::Map(map) => {
758 let key_type = map.key.as_ref().to_tokens(None);
759 let value_type = map.value.as_ref().to_tokens(None);
760
761 if let Some(value) = options
762 .map(|opts| opts.get_string_option("map_type"))
763 .flatten()
764 {
765 let opt = value.value();
766 if opt.eq("hash") || opt.eq("HashMap") {
767 quote_spanned!(value.span() => std::collections::HashMap<#key_type, #value_type>)
768 } else if opt.eq("btree_map") || opt.eq("BTreeMap") {
769 quote_spanned!(value.span() => std::collections::BTreeMap<#key_type, #value_type>)
770 } else {
771 quote_spanned!(value.span() => std::collections::HashMap<#key_type, #value_type>)
773 }
774 } else {
775 quote!(std::collections::HashMap<#key_type, #value_type>)
776 }
777 }
778 FieldType::Group(_group) => todo!(),
779 }
780 }
781
782 fn to_prost_type(&self) -> TokenStream {
783 match self {
784 Self::Int32(span) => ("int32", *span).to_ident().to_token_stream(),
785 Self::Int64(span) => ("int64", *span).to_ident().to_token_stream(),
786 Self::Uint32(span) => ("uint32", *span).to_ident().to_token_stream(),
787 Self::Uint64(span) => ("uint64", *span).to_ident().to_token_stream(),
788 Self::Sint32(span) => ("sint32", *span).to_ident().to_token_stream(),
789 Self::Sint64(span) => ("sint64", *span).to_ident().to_token_stream(),
790 Self::Bool(span) => ("bool", *span).to_ident().to_token_stream(),
791 Self::Fixed64(span) => ("fixed64", *span).to_ident().to_token_stream(),
792 Self::Sfixed64(span) => ("sfixed64", *span).to_ident().to_token_stream(),
793 Self::Double(span) => ("double", *span).to_ident().to_token_stream(),
794 Self::String(span) => ("string", *span).to_ident().to_token_stream(),
795 Self::Bytes(span) => ("bytes", *span).to_ident().to_token_stream(),
796 Self::Fixed32(span) => ("fixed32", *span).to_ident().to_token_stream(),
797 Self::Sfixed32(span) => ("sfixed32", *span).to_ident().to_token_stream(),
798 Self::Float(span) => ("float", *span).to_ident().to_token_stream(),
799 Self::MessageOrEnum(ty) => {
800 if ty.target_is_message {
801 ("message", ty.ty.span()).to_ident().to_token_stream()
802 } else {
803 let enum_type = ty.type_path.local_name().to_lit_str();
804 quote!(enumeration = #enum_type)
805 }
806 }
807 Self::Group(g) => ("group", g.name.span()).to_ident().to_token_stream(),
808 Self::Map(map) => {
809 let key_type = map.key.to_prost_type().to_string();
810 let value_type = map.value.to_prost_type().to_string();
811 let map_type = (
812 format!("{}, {}", key_type.trim(), value_type.trim()),
813 map.key.span(),
814 )
815 .to_lit_str();
816 quote!(map = #map_type)
817 }
818 }
819 }
820}
821
822trait Deprecated: GetOption {
823 fn deprecated(&self) -> Option<TokenStream> {
824 if self
825 .get_bool_option("deprecated")
826 .map(|opt| opt.value())
827 .unwrap_or_default()
828 {
829 Some(quote!(#[deprecated]))
830 } else {
831 None
832 }
833 }
834}
835
836impl Deprecated for Vec<ProtobufOption> {}
837impl<P> Deprecated for Punctuated<ProtobufOption, P> {}