@@ -91,6 +91,52 @@ impl<'t> Frame<'t> {
91
91
DisplayMessage { frame : self }
92
92
}
93
93
94
+ /// Returns an iterator over the fragments of the message contained in this log frame.
95
+ ///
96
+ /// Collecting this into a String will yield the same result as [`Self::display_message`], but
97
+ /// this iterator will yield interpolated fragments on their own. For example, the log:
98
+ ///
99
+ /// ```ignore
100
+ /// defmt::info!("foo = {}, bar = {}", 1, 2);
101
+ /// ```
102
+ ///
103
+ /// Will yield the following strings:
104
+ ///
105
+ /// ```ignore
106
+ /// vec!["foo = ", "1", ", bar = ", "2"]
107
+ /// ```
108
+ ///
109
+ /// Note that nested fragments will not yield separately:
110
+ ///
111
+ /// ```ignore
112
+ /// defmt::info!("foo = {}", Foo { bar: 1 });
113
+ /// ```
114
+ ///
115
+ /// Will yield:
116
+ ///
117
+ /// ```ignore
118
+ /// vec!["foo = ", "Foo { bar: 1 }"]
119
+ /// ```
120
+ ///
121
+ /// This iterator yields the same fragments as [`Self::fragments`], so you can zip them
122
+ /// together to get both representations.
123
+ pub fn display_fragments ( & ' t self ) -> DisplayFragments < ' t > {
124
+ DisplayFragments {
125
+ frame : self ,
126
+ iter : self . fragments ( ) . into_iter ( ) ,
127
+ }
128
+ }
129
+
130
+ /// Returns the fragments of the message contained in this log frame.
131
+ ///
132
+ /// Each fragment represents a part of the log message. See [`Fragment`] for more details.
133
+ ///
134
+ /// This iterator yields the same fragments as [`Self::display_fragments`], so you can zip them
135
+ /// together to get both representations.
136
+ pub fn fragments ( & ' t self ) -> Vec < Fragment < ' t > > {
137
+ defmt_parser:: parse ( self . format , ParserMode :: ForwardsCompatible ) . unwrap ( )
138
+ }
139
+
94
140
pub fn level ( & self ) -> Option < Level > {
95
141
self . level
96
142
}
@@ -100,119 +146,120 @@ impl<'t> Frame<'t> {
100
146
}
101
147
102
148
fn format_args ( & self , format : & str , args : & [ Arg ] , parent_hint : Option < & DisplayHint > ) -> String {
103
- self . format_args_real ( format, args, parent_hint) . unwrap ( ) // cannot fail, we only write to a `String`
149
+ let params = defmt_parser:: parse ( format, ParserMode :: ForwardsCompatible ) . unwrap ( ) ;
150
+ let mut buf = String :: new ( ) ;
151
+ for param in params {
152
+ self . format_fragment ( param, & mut buf, args, parent_hint)
153
+ . unwrap ( ) ; // cannot fail, we only write to a `String`
154
+ }
155
+ buf
104
156
}
105
157
106
- fn format_args_real (
158
+ fn format_fragment (
107
159
& self ,
108
- format : & str ,
160
+ param : Fragment < ' _ > ,
161
+ buf : & mut String ,
109
162
args : & [ Arg ] ,
110
163
parent_hint : Option < & DisplayHint > ,
111
- ) -> Result < String , fmt:: Error > {
112
- let params = defmt_parser:: parse ( format, ParserMode :: ForwardsCompatible ) . unwrap ( ) ;
113
- let mut buf = String :: new ( ) ;
114
- for param in params {
115
- match param {
116
- Fragment :: Literal ( lit) => {
117
- buf. push_str ( & lit) ;
118
- }
119
- Fragment :: Parameter ( param) => {
120
- let hint = param. hint . as_ref ( ) . or ( parent_hint) ;
121
-
122
- match & args[ param. index ] {
123
- Arg :: Bool ( x) => write ! ( buf, "{x}" ) ?,
124
- Arg :: F32 ( x) => write ! ( buf, "{}" , ryu:: Buffer :: new( ) . format( * x) ) ?,
125
- Arg :: F64 ( x) => write ! ( buf, "{}" , ryu:: Buffer :: new( ) . format( * x) ) ?,
126
- Arg :: Uxx ( x) => {
127
- match param. ty {
128
- Type :: BitField ( range) => {
129
- let left_zeroes =
130
- mem:: size_of :: < u128 > ( ) * 8 - range. end as usize ;
131
- let right_zeroes = left_zeroes + range. start as usize ;
132
- // isolate the desired bitfields
133
- let bitfields = ( * x << left_zeroes) >> right_zeroes;
134
-
135
- if let Some ( DisplayHint :: Ascii ) = hint {
136
- let bstr = bitfields
137
- . to_be_bytes ( )
138
- . iter ( )
139
- . skip ( right_zeroes / 8 )
140
- . copied ( )
141
- . collect :: < Vec < u8 > > ( ) ;
142
- self . format_bytes ( & bstr, hint, & mut buf) ?
143
- } else {
144
- self . format_u128 ( bitfields, hint, & mut buf) ?;
145
- }
164
+ ) -> Result < ( ) , fmt:: Error > {
165
+ match param {
166
+ Fragment :: Literal ( lit) => {
167
+ buf. push_str ( & lit) ;
168
+ }
169
+ Fragment :: Parameter ( param) => {
170
+ let hint = param. hint . as_ref ( ) . or ( parent_hint) ;
171
+
172
+ match & args[ param. index ] {
173
+ Arg :: Bool ( x) => write ! ( buf, "{x}" ) ?,
174
+ Arg :: F32 ( x) => write ! ( buf, "{}" , ryu:: Buffer :: new( ) . format( * x) ) ?,
175
+ Arg :: F64 ( x) => write ! ( buf, "{}" , ryu:: Buffer :: new( ) . format( * x) ) ?,
176
+ Arg :: Uxx ( x) => {
177
+ match param. ty {
178
+ Type :: BitField ( range) => {
179
+ let left_zeroes = mem:: size_of :: < u128 > ( ) * 8 - range. end as usize ;
180
+ let right_zeroes = left_zeroes + range. start as usize ;
181
+ // isolate the desired bitfields
182
+ let bitfields = ( * x << left_zeroes) >> right_zeroes;
183
+
184
+ if let Some ( DisplayHint :: Ascii ) = hint {
185
+ let bstr = bitfields
186
+ . to_be_bytes ( )
187
+ . iter ( )
188
+ . skip ( right_zeroes / 8 )
189
+ . copied ( )
190
+ . collect :: < Vec < u8 > > ( ) ;
191
+ self . format_bytes ( & bstr, hint, buf) ?
192
+ } else {
193
+ self . format_u128 ( bitfields, hint, buf) ?;
146
194
}
147
- _ => match hint {
148
- Some ( DisplayHint :: ISO8601 ( precision) ) => {
149
- self . format_iso8601 ( * x as u64 , precision, & mut buf) ?
150
- }
151
- Some ( DisplayHint :: Debug ) => {
152
- self . format_u128 ( * x, parent_hint, & mut buf) ?
153
- }
154
- _ => self . format_u128 ( * x, hint, & mut buf) ?,
155
- } ,
156
195
}
196
+ _ => match hint {
197
+ Some ( DisplayHint :: ISO8601 ( precision) ) => {
198
+ self . format_iso8601 ( * x as u64 , precision, buf) ?
199
+ }
200
+ Some ( DisplayHint :: Debug ) => {
201
+ self . format_u128 ( * x, parent_hint, buf) ?
202
+ }
203
+ _ => self . format_u128 ( * x, hint, buf) ?,
204
+ } ,
157
205
}
158
- Arg :: Ixx ( x) => self . format_i128 ( * x, param. ty , hint, & mut buf) ?,
159
- Arg :: Str ( x) | Arg :: Preformatted ( x) => self . format_str ( x, hint, & mut buf) ?,
160
- Arg :: IStr ( x) => self . format_str ( x, hint, & mut buf) ?,
161
- Arg :: Format { format, args } => match parent_hint {
162
- Some ( DisplayHint :: Ascii ) => {
163
- buf. push_str ( & self . format_args ( format, args, parent_hint) ) ;
164
- }
165
- _ => buf. push_str ( & self . format_args ( format, args, hint) ) ,
166
- } ,
167
- Arg :: FormatSequence { args } => {
168
- for arg in args {
169
- buf. push_str ( & self . format_args ( "{=?}" , & [ arg. clone ( ) ] , hint) )
170
- }
206
+ }
207
+ Arg :: Ixx ( x) => self . format_i128 ( * x, param. ty , hint, buf) ?,
208
+ Arg :: Str ( x) | Arg :: Preformatted ( x) => self . format_str ( x, hint, buf) ?,
209
+ Arg :: IStr ( x) => self . format_str ( x, hint, buf) ?,
210
+ Arg :: Format { format, args } => match parent_hint {
211
+ Some ( DisplayHint :: Ascii ) => {
212
+ buf. push_str ( & self . format_args ( format, args, parent_hint) ) ;
171
213
}
172
- Arg :: FormatSlice { elements } => {
173
- match hint {
174
- // Filter Ascii Hints, which contains u8 byte slices
175
- Some ( DisplayHint :: Ascii )
176
- if elements. iter ( ) . filter ( |e| e. format == "{=u8}" ) . count ( )
177
- != 0 =>
178
- {
179
- let vals = elements
180
- . iter ( )
181
- . map ( |e| match e. args . as_slice ( ) {
182
- [ Arg :: Uxx ( v) ] => u8:: try_from ( * v)
183
- . expect ( "the value must be in u8 range" ) ,
184
- _ => panic ! (
185
- "FormatSlice should only contain one argument"
186
- ) ,
187
- } )
188
- . collect :: < Vec < u8 > > ( ) ;
189
- self . format_bytes ( & vals, hint, & mut buf) ?
190
- }
191
- _ => {
192
- buf. write_str ( "[" ) ?;
193
- let mut is_first = true ;
194
- for element in elements {
195
- if !is_first {
196
- buf. write_str ( ", " ) ?;
214
+ _ => buf. push_str ( & self . format_args ( format, args, hint) ) ,
215
+ } ,
216
+ Arg :: FormatSequence { args } => {
217
+ for arg in args {
218
+ buf. push_str ( & self . format_args ( "{=?}" , & [ arg. clone ( ) ] , hint) )
219
+ }
220
+ }
221
+ Arg :: FormatSlice { elements } => {
222
+ match hint {
223
+ // Filter Ascii Hints, which contains u8 byte slices
224
+ Some ( DisplayHint :: Ascii )
225
+ if elements. iter ( ) . filter ( |e| e. format == "{=u8}" ) . count ( ) != 0 =>
226
+ {
227
+ let vals = elements
228
+ . iter ( )
229
+ . map ( |e| match e. args . as_slice ( ) {
230
+ [ Arg :: Uxx ( v) ] => {
231
+ u8:: try_from ( * v) . expect ( "the value must be in u8 range" )
197
232
}
198
- is_first = false ;
199
- buf. write_str ( & self . format_args (
200
- element. format ,
201
- & element. args ,
202
- hint,
203
- ) ) ?;
233
+ _ => panic ! ( "FormatSlice should only contain one argument" ) ,
234
+ } )
235
+ . collect :: < Vec < u8 > > ( ) ;
236
+ self . format_bytes ( & vals, hint, buf) ?
237
+ }
238
+ _ => {
239
+ buf. write_str ( "[" ) ?;
240
+ let mut is_first = true ;
241
+ for element in elements {
242
+ if !is_first {
243
+ buf. write_str ( ", " ) ?;
204
244
}
205
- buf. write_str ( "]" ) ?;
245
+ is_first = false ;
246
+ buf. write_str ( & self . format_args (
247
+ element. format ,
248
+ & element. args ,
249
+ hint,
250
+ ) ) ?;
206
251
}
252
+ buf. write_str ( "]" ) ?;
207
253
}
208
254
}
209
- Arg :: Slice ( x) => self . format_bytes ( x, hint, & mut buf) ?,
210
- Arg :: Char ( c) => write ! ( buf, "{c}" ) ?,
211
255
}
256
+ Arg :: Slice ( x) => self . format_bytes ( x, hint, buf) ?,
257
+ Arg :: Char ( c) => write ! ( buf, "{c}" ) ?,
212
258
}
213
259
}
214
260
}
215
- Ok ( buf)
261
+
262
+ Ok ( ( ) )
216
263
}
217
264
218
265
fn format_u128 (
@@ -531,6 +578,23 @@ impl fmt::Display for DisplayMessage<'_> {
531
578
}
532
579
}
533
580
581
+ pub struct DisplayFragments < ' t > {
582
+ frame : & ' t Frame < ' t > ,
583
+ iter : std:: vec:: IntoIter < Fragment < ' t > > ,
584
+ }
585
+
586
+ impl Iterator for DisplayFragments < ' _ > {
587
+ type Item = String ;
588
+
589
+ fn next ( & mut self ) -> Option < Self :: Item > {
590
+ let mut buf = String :: new ( ) ;
591
+ self . frame
592
+ . format_fragment ( self . iter . next ( ) ?, & mut buf, & self . frame . args , None )
593
+ . ok ( ) ?;
594
+ Some ( buf)
595
+ }
596
+ }
597
+
534
598
/// Prints a `Frame` when formatted via `fmt::Display`, including all included metadata (level,
535
599
/// timestamp, ...).
536
600
pub struct DisplayFrame < ' t > {
0 commit comments