Skip to content

Commit 258fca7

Browse files
authored
Add safe attribute helper to SafeDebug (#2613)
* Add safe attribute helper to SafeDebug * Require parenthesis They should've been before, but I realized I wasn't propagating the errors up and had to make significant changes to do so. * Always use inner-most safe attribute Also updated docs. * Fix MSRV test
1 parent b76c836 commit 258fca7

File tree

6 files changed

+341
-74
lines changed

6 files changed

+341
-74
lines changed

sdk/typespec/typespec_client_core/src/fmt.rs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,6 @@
55
66
use std::borrow::Cow;
77

8-
/// Derive to help prevent leaking personally identifiable information (PII) that deriving [`Debug`](std::fmt::Debug) might otherwise.
9-
///
10-
/// `SafeDebug` is not a trait and cannot be implemented, nor should you derive `Debug` explicitly.
11-
/// Only when you derive `SafeDebug` will types help prevent leaking PII because, by default, only the type name is printed.
12-
/// Only when you import `typespec_client_core` with feature `debug` will it derive `Debug` normally.
13-
///
14-
/// # Examples
15-
///
16-
/// ```
17-
/// use typespec_client_core::fmt::SafeDebug;
18-
///
19-
/// #[derive(SafeDebug)]
20-
/// struct MyModel {
21-
/// name: Option<String>,
22-
/// }
23-
///
24-
/// let model = MyModel {
25-
/// name: Some("Kelly Smith".to_string()),
26-
/// };
27-
/// if cfg!(feature = "debug") {
28-
/// assert_eq!(format!("{model:?}"), r#"MyModel { name: Some("Kelly Smith") }"#);
29-
/// } else {
30-
/// assert_eq!(format!("{model:?}"), "MyModel { .. }");
31-
/// }
32-
/// ```
338
#[cfg(feature = "derive")]
349
pub use typespec_macros::SafeDebug;
3510

sdk/typespec/typespec_macros/src/lib.rs

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,66 @@ pub fn derive_model(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9191
/// Only when you derive `SafeDebug` will types help prevent leaking PII because, by default, only the type name is printed.
9292
/// Only when you enable the `debug` feature will it derive `Debug` normally.
9393
///
94+
/// You can attribute types, fields, and variants with `#[safe(true)]` or `#[safe(false)]` to optionally show or hide members.
95+
/// The default is that no members are shown. The inner most `#[safe(..)]` attribute determines whether to show or hide a member.
96+
///
9497
/// # Examples
9598
///
9699
/// ```
97100
/// # use typespec_macros::SafeDebug;
98101
/// #[derive(SafeDebug)]
99-
/// struct MyModel {
100-
/// name: Option<String>,
102+
/// struct Person {
103+
/// name: String,
104+
/// }
105+
///
106+
/// let person = Person {
107+
/// name: "Kelly Smith".to_string(),
108+
/// };
109+
/// if cfg!(feature = "debug") {
110+
/// assert_eq!(format!("{person:?}"), r#"Person { name: "Kelly Smith" }"#);
111+
/// } else {
112+
/// assert_eq!(format!("{person:?}"), "Person { .. }");
113+
/// }
114+
/// ```
115+
///
116+
/// Using the `#[safe(..)]` attribute, you can selectively show or hide members.
117+
/// The default, when not present or inherited, is to always hide members unless the `debug` feature is enabled.
118+
///
119+
/// ```
120+
/// # use typespec_macros::SafeDebug;
121+
/// use std::ops::Range;
122+
///
123+
/// #[derive(SafeDebug)]
124+
/// struct Employee {
125+
/// name: String,
126+
/// #[safe(true)]
127+
/// position: Position,
128+
/// }
129+
///
130+
/// #[derive(SafeDebug)]
131+
/// #[safe(true)]
132+
/// struct Position {
133+
/// id: i32,
134+
/// title: String,
135+
/// #[safe(false)]
136+
/// salary: Range<i32>,
101137
/// }
102138
///
103-
/// let model = MyModel {
104-
/// name: Some("Kelly Smith".to_string()),
139+
/// let employee = Employee {
140+
/// name: "Kelly Smith".to_string(),
141+
/// position: Position {
142+
/// id: 12,
143+
/// title: "Staff Engineer".to_string(),
144+
/// salary: 200_000..250_000,
145+
/// },
105146
/// };
106147
/// if cfg!(feature = "debug") {
107-
/// assert_eq!(format!("{model:?}"), r#"MyModel { name: Some("Kelly Smith") }"#);
148+
/// assert_eq!(format!("{employee:?}"), r#"Employee { name: "Kelly Smith", position: Position { id: 12, title: "Staff Engineer", salary: 200000..250000 } }"#);
108149
/// } else {
109-
/// assert_eq!(format!("{model:?}"), "MyModel { .. }");
150+
/// assert_eq!(format!("{employee:?}"), r#"Employee { position: Position { id: 12, title: "Staff Engineer", .. }, .. }"#);
110151
/// }
111152
/// ```
112-
#[proc_macro_derive(SafeDebug)]
153+
#[proc_macro_derive(SafeDebug, attributes(safe))]
113154
pub fn derive_safe_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
114155
run_derive_macro(input, safe_debug::derive_safe_debug_impl)
115156
}

0 commit comments

Comments
 (0)