@@ -91,6 +91,46 @@ 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
+ /// ```
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
+ /// ```
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
+ pub fn fragments ( & ' t self ) -> Vec < Fragment < ' t > > {
131
+ defmt_parser:: parse ( self . format , ParserMode :: ForwardsCompatible ) . unwrap ( )
132
+ }
133
+
94
134
pub fn level ( & self ) -> Option < Level > {
95
135
self . level
96
136
}
@@ -100,119 +140,120 @@ impl<'t> Frame<'t> {
100
140
}
101
141
102
142
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`
143
+ let params = defmt_parser:: parse ( format, ParserMode :: ForwardsCompatible ) . unwrap ( ) ;
144
+ let mut buf = String :: new ( ) ;
145
+ for param in params {
146
+ self . format_fragment ( param, & mut buf, args, parent_hint)
147
+ . unwrap ( ) ; // cannot fail, we only write to a `String`
148
+ }
149
+ buf
104
150
}
105
151
106
- fn format_args_real (
152
+ fn format_fragment (
107
153
& self ,
108
- format : & str ,
154
+ param : Fragment < ' _ > ,
155
+ buf : & mut String ,
109
156
args : & [ Arg ] ,
110
157
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
- }
158
+ ) -> Result < ( ) , fmt:: Error > {
159
+ match param {
160
+ Fragment :: Literal ( lit) => {
161
+ buf. push_str ( & lit) ;
162
+ }
163
+ Fragment :: Parameter ( param) => {
164
+ let hint = param. hint . as_ref ( ) . or ( parent_hint) ;
165
+
166
+ match & args[ param. index ] {
167
+ Arg :: Bool ( x) => write ! ( buf, "{x}" ) ?,
168
+ Arg :: F32 ( x) => write ! ( buf, "{}" , ryu:: Buffer :: new( ) . format( * x) ) ?,
169
+ Arg :: F64 ( x) => write ! ( buf, "{}" , ryu:: Buffer :: new( ) . format( * x) ) ?,
170
+ Arg :: Uxx ( x) => {
171
+ match param. ty {
172
+ Type :: BitField ( range) => {
173
+ let left_zeroes = mem:: size_of :: < u128 > ( ) * 8 - range. end as usize ;
174
+ let right_zeroes = left_zeroes + range. start as usize ;
175
+ // isolate the desired bitfields
176
+ let bitfields = ( * x << left_zeroes) >> right_zeroes;
177
+
178
+ if let Some ( DisplayHint :: Ascii ) = hint {
179
+ let bstr = bitfields
180
+ . to_be_bytes ( )
181
+ . iter ( )
182
+ . skip ( right_zeroes / 8 )
183
+ . copied ( )
184
+ . collect :: < Vec < u8 > > ( ) ;
185
+ self . format_bytes ( & bstr, hint, buf) ?
186
+ } else {
187
+ self . format_u128 ( bitfields, hint, buf) ?;
146
188
}
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
189
}
190
+ _ => match hint {
191
+ Some ( DisplayHint :: ISO8601 ( precision) ) => {
192
+ self . format_iso8601 ( * x as u64 , precision, buf) ?
193
+ }
194
+ Some ( DisplayHint :: Debug ) => {
195
+ self . format_u128 ( * x, parent_hint, buf) ?
196
+ }
197
+ _ => self . format_u128 ( * x, hint, buf) ?,
198
+ } ,
157
199
}
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
- }
200
+ }
201
+ Arg :: Ixx ( x) => self . format_i128 ( * x, param. ty , hint, buf) ?,
202
+ Arg :: Str ( x) | Arg :: Preformatted ( x) => self . format_str ( x, hint, buf) ?,
203
+ Arg :: IStr ( x) => self . format_str ( x, hint, buf) ?,
204
+ Arg :: Format { format, args } => match parent_hint {
205
+ Some ( DisplayHint :: Ascii ) => {
206
+ buf. push_str ( & self . format_args ( format, args, parent_hint) ) ;
171
207
}
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 ( ", " ) ?;
208
+ _ => buf. push_str ( & self . format_args ( format, args, hint) ) ,
209
+ } ,
210
+ Arg :: FormatSequence { args } => {
211
+ for arg in args {
212
+ buf. push_str ( & self . format_args ( "{=?}" , & [ arg. clone ( ) ] , hint) )
213
+ }
214
+ }
215
+ Arg :: FormatSlice { elements } => {
216
+ match hint {
217
+ // Filter Ascii Hints, which contains u8 byte slices
218
+ Some ( DisplayHint :: Ascii )
219
+ if elements. iter ( ) . filter ( |e| e. format == "{=u8}" ) . count ( ) != 0 =>
220
+ {
221
+ let vals = elements
222
+ . iter ( )
223
+ . map ( |e| match e. args . as_slice ( ) {
224
+ [ Arg :: Uxx ( v) ] => {
225
+ u8:: try_from ( * v) . expect ( "the value must be in u8 range" )
197
226
}
198
- is_first = false ;
199
- buf. write_str ( & self . format_args (
200
- element. format ,
201
- & element. args ,
202
- hint,
203
- ) ) ?;
227
+ _ => panic ! ( "FormatSlice should only contain one argument" ) ,
228
+ } )
229
+ . collect :: < Vec < u8 > > ( ) ;
230
+ self . format_bytes ( & vals, hint, buf) ?
231
+ }
232
+ _ => {
233
+ buf. write_str ( "[" ) ?;
234
+ let mut is_first = true ;
235
+ for element in elements {
236
+ if !is_first {
237
+ buf. write_str ( ", " ) ?;
204
238
}
205
- buf. write_str ( "]" ) ?;
239
+ is_first = false ;
240
+ buf. write_str ( & self . format_args (
241
+ element. format ,
242
+ & element. args ,
243
+ hint,
244
+ ) ) ?;
206
245
}
246
+ buf. write_str ( "]" ) ?;
207
247
}
208
248
}
209
- Arg :: Slice ( x) => self . format_bytes ( x, hint, & mut buf) ?,
210
- Arg :: Char ( c) => write ! ( buf, "{c}" ) ?,
211
249
}
250
+ Arg :: Slice ( x) => self . format_bytes ( x, hint, buf) ?,
251
+ Arg :: Char ( c) => write ! ( buf, "{c}" ) ?,
212
252
}
213
253
}
214
254
}
215
- Ok ( buf)
255
+
256
+ Ok ( ( ) )
216
257
}
217
258
218
259
fn format_u128 (
@@ -531,6 +572,23 @@ impl fmt::Display for DisplayMessage<'_> {
531
572
}
532
573
}
533
574
575
+ pub struct DisplayFragments < ' t > {
576
+ frame : & ' t Frame < ' t > ,
577
+ iter : std:: vec:: IntoIter < Fragment < ' t > > ,
578
+ }
579
+
580
+ impl Iterator for DisplayFragments < ' _ > {
581
+ type Item = String ;
582
+
583
+ fn next ( & mut self ) -> Option < Self :: Item > {
584
+ let mut buf = String :: new ( ) ;
585
+ self . frame
586
+ . format_fragment ( self . iter . next ( ) ?, & mut buf, & self . frame . args , None )
587
+ . ok ( ) ?;
588
+ Some ( buf)
589
+ }
590
+ }
591
+
534
592
/// Prints a `Frame` when formatted via `fmt::Display`, including all included metadata (level,
535
593
/// timestamp, ...).
536
594
pub struct DisplayFrame < ' t > {
0 commit comments