prost_protovalidate_build/
backend.rs1use proc_macro2::{Ident, TokenStream};
18use quote::quote;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
26#[non_exhaustive]
27pub enum Backend {
28 #[default]
30 Prost,
31 Buffa,
35}
36
37impl Backend {
38 pub(crate) fn msg_field_is_unset(self, field: &TokenStream) -> TokenStream {
40 match self {
41 Self::Prost => quote! { #field.is_none() },
42 Self::Buffa => quote! { #field.is_unset() },
43 }
44 }
45
46 pub(crate) fn msg_field_is_set(self, field: &TokenStream) -> TokenStream {
48 match self {
49 Self::Prost => quote! { #field.is_some() },
50 Self::Buffa => quote! { #field.is_set() },
51 }
52 }
53
54 pub(crate) fn if_msg_field_set(
57 self,
58 field: &TokenStream,
59 bind: &Ident,
60 body: &TokenStream,
61 ) -> TokenStream {
62 match self {
63 Self::Prost => quote! {
64 if let ::core::option::Option::Some(ref #bind) = #field {
65 #body
66 }
67 },
68 Self::Buffa => quote! {
69 if let ::core::option::Option::Some(#bind) = #field.as_option() {
70 #body
71 }
72 },
73 }
74 }
75
76 pub(crate) fn enum_to_i32(self, access: &TokenStream) -> TokenStream {
82 match self {
83 Self::Prost => access.clone(),
84 Self::Buffa => quote! { #access.to_i32() },
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use quote::{format_ident, quote};
92
93 use super::Backend;
94
95 #[test]
96 fn presence_shapes_per_backend() {
97 let field = quote! { self.inner };
98 assert_eq!(
99 Backend::Prost.msg_field_is_unset(&field).to_string(),
100 "self . inner . is_none ()"
101 );
102 assert_eq!(
103 Backend::Buffa.msg_field_is_unset(&field).to_string(),
104 "self . inner . is_unset ()"
105 );
106 assert_eq!(
107 Backend::Prost.msg_field_is_set(&field).to_string(),
108 "self . inner . is_some ()"
109 );
110 assert_eq!(
111 Backend::Buffa.msg_field_is_set(&field).to_string(),
112 "self . inner . is_set ()"
113 );
114 }
115
116 #[test]
117 fn unwrap_binds_by_ref_in_prost_and_via_as_option_in_buffa() {
118 let field = quote! { self.inner };
119 let bind = format_ident!("_nested");
120 let body = quote! { touch(_nested); };
121
122 let prost = Backend::Prost
123 .if_msg_field_set(&field, &bind, &body)
124 .to_string();
125 assert!(
126 prost.contains("Some (ref _nested) = self . inner"),
127 "{prost}"
128 );
129
130 let buffa = Backend::Buffa
131 .if_msg_field_set(&field, &bind, &body)
132 .to_string();
133 assert!(
134 buffa.contains("Some (_nested) = self . inner . as_option ()"),
135 "{buffa}"
136 );
137 }
138
139 #[test]
140 fn enum_access_gets_to_i32_only_in_buffa() {
141 let access = quote! { self.status };
142 assert_eq!(
143 Backend::Prost.enum_to_i32(&access).to_string(),
144 "self . status"
145 );
146 assert_eq!(
147 Backend::Buffa.enum_to_i32(&access).to_string(),
148 "self . status . to_i32 ()"
149 );
150 }
151}