@@ -215,11 +215,13 @@ func encodeKeyValuePair(w io.Writer, key string, value any, suffix []byte) (err
215
215
}
216
216
217
217
func encodeValue (w io.Writer , value any , suffix []byte ) error {
218
- data , err := json .Marshal (value )
219
- if err != nil {
220
- return err
221
- }
222
- _ , err = w .Write (data )
218
+ // Use an Encoder to avoid the extra []byte allocated by Marshal. Encode, unlike Marshal,
219
+ // appends a trailing newline to separate consecutive encodings of JSON values that aren't
220
+ // self-delimiting, like numbers. Strip the newline to avoid the assumption that every
221
+ // json.Unmarshaler implementation will accept trailing whitespace.
222
+ enc := json .NewEncoder (& trailingLinefeedSuppressor {delegate : w })
223
+ enc .SetIndent ("" , "" )
224
+ err := enc .Encode (value )
223
225
if err != nil {
224
226
return err
225
227
}
@@ -228,3 +230,48 @@ func encodeValue(w io.Writer, value any, suffix []byte) error {
228
230
}
229
231
return err
230
232
}
233
+
234
+ // trailingLinefeedSuppressor is an io.Writer that wraps another io.Writer, suppressing a single
235
+ // trailing linefeed if it is the last byte written by the latest call to Write.
236
+ type trailingLinefeedSuppressor struct {
237
+ lf bool
238
+ delegate io.Writer
239
+ }
240
+
241
+ func (w * trailingLinefeedSuppressor ) Write (p []byte ) (int , error ) {
242
+ if len (p ) == 0 {
243
+ // Avoid flushing a buffered linefeeds on an empty write.
244
+ return 0 , nil
245
+ }
246
+
247
+ if w .lf {
248
+ // The previous write had a trailing linefeed that was buffered. That wasn't the
249
+ // last Write call, so flush the buffered linefeed before continuing.
250
+ n , err := w .delegate .Write ([]byte {'\n' })
251
+ if n > 0 {
252
+ w .lf = false
253
+ }
254
+ if err != nil {
255
+ return 0 , err
256
+ }
257
+ }
258
+
259
+ if p [len (p )- 1 ] != '\n' {
260
+ return w .delegate .Write (p )
261
+ }
262
+
263
+ p = p [:len (p )- 1 ]
264
+
265
+ if len (p ) == 0 { // []byte{'\n'}
266
+ w .lf = true
267
+ return 1 , nil
268
+ }
269
+
270
+ n , err := w .delegate .Write (p )
271
+ if n == len (p ) {
272
+ // Everything up to the trailing linefeed has been flushed. Eat the linefeed.
273
+ w .lf = true
274
+ n ++
275
+ }
276
+ return n , err
277
+ }
0 commit comments