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)) }, } // buffer := getBuffer() // defer putBuffer(buffer) func getBuffer() *bytes.Buffer { buffer := bufferPool.Get().(*bytes.Buffer) buffer.Reset() return buffer } // putBuffer(buffer) // always called via defer after getBuffer() func putBuffer(buffer *bytes.Buffer) { // Don't pool buffers that grew too large (>64KB) if buffer.Cap() <= 65536 { bufferPool.Put(buffer) } } // data, err := MarshalJSON(msg) // if err != nil { return nil, err } func MarshalJSON(v interface{}) ([]byte, error) { buffer := getBuffer() defer putBuffer(buffer) encoder := json.NewEncoder(buffer) // Don't escape HTML characters (matches json.Marshal behavior for these use cases) encoder.SetEscapeHTML(false) if err := encoder.Encode(v); err != nil { return nil, err } // json.Encoder.Encode adds a newline; remove it to match json.Marshal data := buffer.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 }