package node import ( "bytes" "encoding/json" "sync" ) // bufferPool provides reusable byte buffers for JSON encoding. // This reduces allocation overhead in hot paths like message serialization. var bufferPool = sync.Pool{ New: func() interface{} { return bytes.NewBuffer(make([]byte, 0, 1024)) }, } // buf := getBuffer() // defer putBuffer(buf) func getBuffer() *bytes.Buffer { buf := bufferPool.Get().(*bytes.Buffer) buf.Reset() return buf } // putBuffer(buf) // always called via defer after getBuffer() func putBuffer(buf *bytes.Buffer) { // Don't pool buffers that grew too large (>64KB) if buf.Cap() <= 65536 { bufferPool.Put(buf) } } // data, err := MarshalJSON(msg) // if err != nil { return nil, err } func MarshalJSON(v interface{}) ([]byte, error) { buf := getBuffer() defer putBuffer(buf) enc := json.NewEncoder(buf) // Don't escape HTML characters (matches json.Marshal behavior for these use cases) enc.SetEscapeHTML(false) if err := enc.Encode(v); err != nil { return nil, err } // json.Encoder.Encode adds a newline; remove it to match json.Marshal data := buf.Bytes() if len(data) > 0 && data[len(data)-1] == '\n' { data = data[:len(data)-1] } // Return a copy since the buffer will be reused result := make([]byte, len(data)) copy(result, data) return result, nil }