@@ -215,11 +215,13 @@ func encodeKeyValuePair(w io.Writer, key string, value any, suffix []byte) (err
215215}
216216
217217func 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 )
223225 if err != nil {
224226 return err
225227 }
@@ -228,3 +230,48 @@ func encodeValue(w io.Writer, value any, suffix []byte) error {
228230 }
229231 return err
230232}
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