use proc_macro2::TokenStream;
use quote::{
format_ident,
quote_spanned,
};
use syn::{
Field,
Ident,
Path,
spanned::Spanned,
};
use crate::{
field_mode::FieldMode,
immutable_trait_name::ImmutableTraitName,
};
pub(crate) fn immutable(
type_name: &Ident,
field: &Field,
field_name: &str,
mode: &FieldMode,
runtime: &Path,
) -> TokenStream {
let helper =
helper_name(type_name, field, field_name, mode.immutable_trait_name());
match mode {
FieldMode::Plain | FieldMode::Skip => TokenStream::new(),
FieldMode::Level(sensitivity) => {
let level = sensitivity.runtime_tokens(runtime);
quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[allow(clippy::ptr_arg)]
#[inline(always)]
fn #helper<'a, __QubitRedactField>(
value: &'a __QubitRedactField,
policy: &'a #runtime::RedactionPolicy,
) -> #runtime::RedactedValue<'a>
where
__QubitRedactField: #runtime::RedactValue + ?Sized,
{
#runtime::RedactValue::redact_value(
value,
#level,
policy.masking(),
)
}
}
}
FieldMode::Nested => quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[inline(always)]
fn #helper<'a, __QubitRedactField>(
value: &'a __QubitRedactField,
policy: &#runtime::RedactionPolicy,
) -> #runtime::Redacted<'a, __QubitRedactField>
where
__QubitRedactField: #runtime::Redact,
{
#runtime::Redact::redacted_with(value, policy)
}
},
FieldMode::Map => quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[inline(always)]
fn #helper<
'a,
__QubitRedactField,
__QubitRedactKey: ?Sized,
__QubitRedactValue: ?Sized,
>(
value: &'a __QubitRedactField,
policy: &#runtime::RedactionPolicy,
) -> #runtime::RedactedMap<
'a,
__QubitRedactField,
__QubitRedactKey,
__QubitRedactValue,
>
where
__QubitRedactField:
#runtime::RedactMapValue<
__QubitRedactKey,
__QubitRedactValue,
> + ?Sized,
{
#runtime::RedactedMap::new(value, policy.clone())
}
},
FieldMode::Json => quote_spanned! {field.span()=>
#runtime::__qubit_redact_json! {
#[allow(non_snake_case)]
#[allow(clippy::ptr_arg)]
#[inline(always)]
fn #helper<'a>(
value: &'a ::std::string::String,
policy: &'a #runtime::RedactionPolicy,
) -> #runtime::RedactedJsonText<'a, 'a> {
#runtime::RedactedJsonText::new(value, policy)
}
}
},
}
}
pub(crate) fn mutable(
type_name: &Ident,
field: &Field,
field_name: &str,
mode: &FieldMode,
runtime: &Path,
) -> TokenStream {
let helper =
helper_name(type_name, field, field_name, mode.mutable_trait_name());
match mode {
FieldMode::Plain | FieldMode::Skip => TokenStream::new(),
FieldMode::Level(sensitivity) => {
let level = sensitivity.runtime_tokens(runtime);
quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[inline(always)]
fn #helper<__QubitRedactField>(
value: &mut __QubitRedactField,
policy: &#runtime::RedactionPolicy,
)
where
__QubitRedactField: #runtime::RedactValueMut + ?Sized,
{
#runtime::RedactValueMut::redact_value_in_place(
value,
#level,
policy.masking(),
);
}
}
}
FieldMode::Nested => quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[inline(always)]
fn #helper<__QubitRedactField>(
value: &mut __QubitRedactField,
policy: &#runtime::RedactionPolicy,
)
where
__QubitRedactField: #runtime::RedactMut + ?Sized,
{
#runtime::RedactMut::redact_in_place_with(value, policy);
}
},
FieldMode::Map => quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[inline(always)]
fn #helper<
__QubitRedactField,
__QubitRedactKey: ?Sized,
__QubitRedactValue: ?Sized,
>(
value: &mut __QubitRedactField,
policy: &#runtime::RedactionPolicy,
)
where
__QubitRedactField:
#runtime::RedactMapValueMut<
__QubitRedactKey,
__QubitRedactValue,
> + ?Sized,
{
#runtime::RedactMapValueMut::redact_map_in_place(value, policy);
}
},
FieldMode::Json => quote_spanned! {field.span()=>
#runtime::__qubit_redact_json! {
#[allow(non_snake_case)]
#[inline(always)]
fn #helper(
value: &mut ::std::string::String,
policy: &#runtime::RedactionPolicy,
) {
#runtime::redact_json_text_in_place(value, policy);
}
}
},
}
}
pub(crate) fn serialization(
type_name: &Ident,
field: &Field,
field_name: &str,
mode: &FieldMode,
runtime: &Path,
) -> TokenStream {
let helper = helper_name(
type_name,
field,
field_name,
mode.serialization_trait_name(),
);
match mode {
FieldMode::Nested => quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[inline(always)]
fn #helper<'a, __QubitRedactField>(
value: &'a __QubitRedactField,
policy: &'a #runtime::RedactionPolicy,
) -> #runtime::__private::RedactedSerialize<'a, __QubitRedactField>
where
__QubitRedactField:
#runtime::__private::RedactSerialize + ?Sized,
{
#runtime::__private::RedactedSerialize::new(value, policy)
}
},
FieldMode::Map => quote_spanned! {field.span()=>
#[allow(non_snake_case)]
#[inline(always)]
fn #helper<
'a,
__QubitRedactField,
__QubitRedactKey: ?Sized,
__QubitRedactValue: ?Sized,
>(
value: &'a __QubitRedactField,
policy: &'a #runtime::RedactionPolicy,
) -> #runtime::RedactedMap<
'a,
__QubitRedactField,
__QubitRedactKey,
__QubitRedactValue,
>
where
__QubitRedactField:
#runtime::__private::RedactMapSerialize<
__QubitRedactKey,
__QubitRedactValue,
> + ?Sized,
{
#runtime::RedactedMap::new(value, policy.clone())
}
},
FieldMode::Json => quote_spanned! {field.span()=>
#runtime::__qubit_redact_json! {
#[allow(non_snake_case)]
#[allow(clippy::ptr_arg)]
#[inline(always)]
fn #helper<'a>(
value: &'a ::std::string::String,
policy: &'a #runtime::RedactionPolicy,
) -> #runtime::RedactedJsonText<'a, 'a> {
#runtime::RedactedJsonText::new(value, policy)
}
}
},
FieldMode::Plain | FieldMode::Level(_) | FieldMode::Skip => {
TokenStream::new()
}
}
}
pub(crate) fn helper_name(
type_name: &Ident,
field: &Field,
field_name: &str,
required_trait: &str,
) -> Ident {
let type_fragment = type_name.to_string().replace("r#", "");
let field_fragment = field_name.replace("r#", "");
format_ident!(
"__qubit_redact_{}_{}_requires_{}",
type_fragment,
field_fragment,
required_trait,
span = field.span(),
)
}