use proc_macro2::{Ident, Span, TokenStream};
use quote::quote_spanned;
use syn::Result;
use crate::{
crate_root,
generics::{push_container_predicate, push_debug_predicate, push_policy_predicate},
strategy::Strategy,
types::is_nonzero_type,
};
pub(crate) struct DeriveContext<'a> {
pub(crate) container_path: &'a TokenStream,
pub(crate) container_predicates: &'a mut Vec<syn::WherePredicate>,
pub(crate) policy_predicates: &'a mut Vec<syn::WherePredicate>,
pub(crate) debug_unredacted_predicates: &'a mut Vec<syn::WherePredicate>,
}
fn nonzero_policy_error(span: Span) -> syn::Error {
syn::Error::new(
span,
"NonZero integer fields cannot use #[sensitive(Policy)] because redaction \
may need to produce zero; use a nullable scalar or a policy-aware wrapper",
)
}
pub(crate) fn generate_field_transform(
ctx: &mut DeriveContext<'_>,
ty: &syn::Type,
binding: &Ident,
span: Span,
strategy: &Strategy,
) -> Result<TokenStream> {
let container_path = ctx.container_path;
let mapper = crate::internal_ident("__redactable_mapper");
match strategy {
Strategy::WalkDefault => {
push_container_predicate(ctx.container_predicates, ty);
push_debug_predicate(ctx.debug_unredacted_predicates, ty);
Ok(quote_spanned! { span =>
let #binding = #container_path::redact_with(#binding, #mapper);
})
}
Strategy::NotSensitive => {
push_debug_predicate(ctx.debug_unredacted_predicates, ty);
Ok(TokenStream::new())
}
Strategy::Policy(policy_path) => {
if is_nonzero_type(ty) {
return Err(nonzero_policy_error(span));
}
push_policy_predicate(ctx.policy_predicates, ty, policy_path);
push_debug_predicate(ctx.debug_unredacted_predicates, ty);
let policy = policy_path.clone();
let crate_root = crate_root();
Ok(quote_spanned! { span =>
let #binding = <#ty as #crate_root::__private::PolicyField<#policy>>::apply_field(
#binding,
#mapper,
);
})
}
}
}