Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PLATFORM-860]: Veil memory optimisations and refactoring #60

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions src/private.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::fmt::{Debug, Display, Write};
use std::{
fmt::{Debug, Display, Write},
num::NonZeroU8,
};

pub enum RedactSpecialization {
/// Whether the type we're redacting is an Option<T> or not. Poor man's specialization! This is detected
Expand All @@ -17,20 +20,25 @@ pub enum RedactSpecialization {
Option,
}

#[derive(Clone, Copy)]
pub enum RedactionLength {
/// Redact the entire data.
Full,

/// Redact a portion of the data.
Partial,

/// Whether to redact with a fixed width, ignoring the length of the data.
Fixed(NonZeroU8),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason to keep this as just an u8 instead of u32 or usize?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think anyone is gonna need anything greater than 255 characters :V

}

#[derive(Clone, Copy)]
pub struct RedactFlags {
/// Whether to only partially redact the data.
///
/// Incompatible with `fixed`.
pub partial: bool,
/// How much of the data to redact.
pub redact_length: RedactionLength,

/// What character to use for redacting.
pub redact_char: char,

/// Whether to redact with a fixed width, ignoring the length of the data.
///
/// Incompatible with `partial`.
pub fixed: u8,
}
impl RedactFlags {
/// How many characters must a word be for it to be partially redacted?
Expand Down Expand Up @@ -140,8 +148,8 @@ impl std::fmt::Debug for RedactionFormatter<'_> {
return self.this.passthrough(fmt);
}

if self.flags.fixed > 0 {
return RedactFlags::redact_fixed(fmt, self.flags.fixed as usize, self.flags.redact_char);
if let RedactionLength::Fixed(n) = &self.flags.redact_length {
return RedactFlags::redact_fixed(fmt, n.get() as usize, self.flags.redact_char);
}

let redactable_string = self.this.to_string();
Expand Down Expand Up @@ -169,7 +177,7 @@ impl std::fmt::Debug for RedactionFormatter<'_> {
None => {}
}

if self.flags.partial {
if let RedactionLength::Partial = &self.flags.redact_length {
self.flags.redact_partial(fmt, &redactable_string)
} else {
self.flags.redact_full(fmt, &redactable_string)
Expand Down
80 changes: 49 additions & 31 deletions veil-macros/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,26 +96,42 @@ pub trait ExtractFlags: Sized + Copy + Default {
}
}

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum RedactionLength {
/// Redact the entire data.
Full,

/// Redact a portion of the data.
Partial,

/// Whether to redact with a fixed width, ignoring the length of the data.
Fixed(NonZeroU8),
}
impl quote::ToTokens for RedactionLength {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
RedactionLength::Full => quote! { ::veil::private::RedactionLength::Full }.to_tokens(tokens),
RedactionLength::Partial => quote! { ::veil::private::RedactionLength::Partial }.to_tokens(tokens),
RedactionLength::Fixed(n) => {
let n = n.get();
quote! { ::veil::private::RedactionLength::Fixed(::core::num::NonZeroU8::new(#n).unwrap()) }
.to_tokens(tokens)
}
}
}
}

#[derive(Clone, Copy, PartialEq, Eq)]
pub struct RedactFlags {
/// Whether the field is partially or fully redacted.
///
/// Incompatible with `fixed`.
pub partial: bool,
pub redact_length: RedactionLength,

/// The character to use for redacting. Defaults to `*`.
pub redact_char: char,

/// Whether to redact with a fixed width, ignoring the length of the data.
///
/// Incompatible with `partial`.
pub fixed: Option<NonZeroU8>,
}
impl Default for RedactFlags {
fn default() -> Self {
Self {
partial: false,
fixed: None,
redact_length: RedactionLength::Full,
redact_char: '*',
}
}
Expand All @@ -127,7 +143,13 @@ impl ExtractFlags for RedactFlags {
match meta {
// #[redact(partial)]
syn::Meta::Path(path) if path.is_ident("partial") => {
self.partial = true;
if self.redact_length != RedactionLength::Full {
return TryParseMeta::Err(syn::Error::new_spanned(
path,
"`partial` clashes with an existing redaction length flag",
));
}
self.redact_length = RedactionLength::Partial;
}

// #[redact(with = 'X')]
Expand All @@ -137,9 +159,15 @@ impl ExtractFlags for RedactFlags {
},

// #[redact(fixed = u8)]
syn::Meta::NameValue(kv) if kv.path.is_ident("fixed") => match kv.lit {
syn::Lit::Int(int) => {
self.fixed = Some(
syn::Meta::NameValue(kv) if kv.path.is_ident("fixed") => {
if self.redact_length != RedactionLength::Full {
return TryParseMeta::Err(syn::Error::new_spanned(
kv.path,
"`fixed` clashes with an existing redaction length flag",
));
}
if let syn::Lit::Int(int) = kv.lit {
self.redact_length = RedactionLength::Fixed(
match int.base10_parse::<u8>().and_then(|int| {
NonZeroU8::new(int).ok_or_else(|| {
syn::Error::new_spanned(int, "fixed redacting width must be greater than zero")
Expand All @@ -149,9 +177,10 @@ impl ExtractFlags for RedactFlags {
Err(err) => return TryParseMeta::Err(err),
},
)
} else {
return TryParseMeta::Err(syn::Error::new_spanned(kv.lit, "expected a character literal"));
}
_ => return TryParseMeta::Err(syn::Error::new_spanned(kv.lit, "expected a character literal")),
},
}

_ => return TryParseMeta::Unrecognised(meta),
}
Expand All @@ -161,18 +190,14 @@ impl ExtractFlags for RedactFlags {
impl quote::ToTokens for RedactFlags {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let Self {
partial,
redact_length,
redact_char,
fixed,
..
} = self;

let fixed = fixed.map(|fixed| fixed.get()).unwrap_or(0);

tokens.extend(quote! {
partial: #partial,
redact_char: #redact_char,
fixed: #fixed,
redact_length: #redact_length,
redact_char: #redact_char
});
}
}
Expand Down Expand Up @@ -261,13 +286,6 @@ impl ExtractFlags for FieldFlags {
}
}

if self.redact.partial && self.redact.fixed.is_some() {
return Err(syn::Error::new_spanned(
attr,
"`#[redact(partial)]` and `#[redact(fixed = ...)]` are incompatible",
));
}

Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions veil-tests/src/compile_tests/fail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ fail_tests! {
redact_all_on_field,
redact_all_variant_on_variant,
redact_enum_without_variant,
redact_partial_fixed,
redact_too_many,
redact_unused,
redact_variant_on_field,
Expand All @@ -19,5 +18,6 @@ fail_tests! {
redact_units,
redact_skip,
redact_missing_all,
redact_display_enum_variant
redact_display_enum_variant,
redact_incompatible_flags
}
31 changes: 31 additions & 0 deletions veil-tests/src/compile_tests/fail/redact_incompatible_flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
fn main() {}

#[derive(veil::Redact)]
struct Foo {
#[redact(partial, fixed = 3)]
bar: String
}

#[derive(veil::Redact)]
struct Bar {
#[redact(fixed = 3, partial)]
baz: String
}

#[derive(veil::Redact)]
enum Baz {
#[redact(variant, fixed = 3, partial)]
Foo {
#[redact(fixed = 3, partial)]
bar: String,
}
}

#[derive(veil::Redact)]
enum Qux {
#[redact(variant, partial, fixed = 3)]
Foo {
#[redact(partial, fixed = 3)]
bar: String,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error: `fixed` clashes with an existing redaction length flag
--> src/compile_tests/fail/redact_incompatible_flags.rs:5:23
|
5 | #[redact(partial, fixed = 3)]
| ^^^^^

error: `partial` clashes with an existing redaction length flag
--> src/compile_tests/fail/redact_incompatible_flags.rs:11:25
|
11 | #[redact(fixed = 3, partial)]
| ^^^^^^^

error: `partial` clashes with an existing redaction length flag
--> src/compile_tests/fail/redact_incompatible_flags.rs:17:34
|
17 | #[redact(variant, fixed = 3, partial)]
| ^^^^^^^

error: `fixed` clashes with an existing redaction length flag
--> src/compile_tests/fail/redact_incompatible_flags.rs:26:32
|
26 | #[redact(variant, partial, fixed = 3)]
| ^^^^^
16 changes: 0 additions & 16 deletions veil-tests/src/compile_tests/fail/redact_partial_fixed.rs

This file was deleted.

11 changes: 0 additions & 11 deletions veil-tests/src/compile_tests/fail/redact_partial_fixed.stderr

This file was deleted.