use proc_macro2::{Ident, TokenStream};
use quote::quote;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Backend {
#[default]
Prost,
Buffa,
}
impl Backend {
pub(crate) fn msg_field_is_unset(self, field: &TokenStream) -> TokenStream {
match self {
Self::Prost => quote! { #field.is_none() },
Self::Buffa => quote! { #field.is_unset() },
}
}
pub(crate) fn msg_field_is_set(self, field: &TokenStream) -> TokenStream {
match self {
Self::Prost => quote! { #field.is_some() },
Self::Buffa => quote! { #field.is_set() },
}
}
pub(crate) fn if_msg_field_set(
self,
field: &TokenStream,
bind: &Ident,
body: &TokenStream,
) -> TokenStream {
match self {
Self::Prost => quote! {
if let ::core::option::Option::Some(ref #bind) = #field {
#body
}
},
Self::Buffa => quote! {
if let ::core::option::Option::Some(#bind) = #field.as_option() {
#body
}
},
}
}
pub(crate) fn enum_to_i32(self, access: &TokenStream) -> TokenStream {
match self {
Self::Prost => access.clone(),
Self::Buffa => quote! { #access.to_i32() },
}
}
}
#[cfg(test)]
mod tests {
use quote::{format_ident, quote};
use super::Backend;
#[test]
fn presence_shapes_per_backend() {
let field = quote! { self.inner };
assert_eq!(
Backend::Prost.msg_field_is_unset(&field).to_string(),
"self . inner . is_none ()"
);
assert_eq!(
Backend::Buffa.msg_field_is_unset(&field).to_string(),
"self . inner . is_unset ()"
);
assert_eq!(
Backend::Prost.msg_field_is_set(&field).to_string(),
"self . inner . is_some ()"
);
assert_eq!(
Backend::Buffa.msg_field_is_set(&field).to_string(),
"self . inner . is_set ()"
);
}
#[test]
fn unwrap_binds_by_ref_in_prost_and_via_as_option_in_buffa() {
let field = quote! { self.inner };
let bind = format_ident!("_nested");
let body = quote! { touch(_nested); };
let prost = Backend::Prost
.if_msg_field_set(&field, &bind, &body)
.to_string();
assert!(
prost.contains("Some (ref _nested) = self . inner"),
"{prost}"
);
let buffa = Backend::Buffa
.if_msg_field_set(&field, &bind, &body)
.to_string();
assert!(
buffa.contains("Some (_nested) = self . inner . as_option ()"),
"{buffa}"
);
}
#[test]
fn enum_access_gets_to_i32_only_in_buffa() {
let access = quote! { self.status };
assert_eq!(
Backend::Prost.enum_to_i32(&access).to_string(),
"self . status"
);
assert_eq!(
Backend::Buffa.enum_to_i32(&access).to_string(),
"self . status . to_i32 ()"
);
}
}