Documentation
¶
Index ¶
Constants ¶
const DefaultBufferSize = 1 << 20 // 1 MiB
DefaultBufferSize is the fixed window of memory the writer holds before flushing downstream.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Marshaler ¶
type Marshaler struct {
// contains filtered or unexported fields
}
func NewMarshaler ¶
func NewMarshaler(opts ...MarshalerOption) *Marshaler
func (*Marshaler) MarshalStream ¶
MarshalStream writes v as a JSON object to w with streaming semantics for channel fields.
v must be a struct or pointer to struct. Each exported field is emitted in declaration order using its `json:"..."` tag name (falling back to the field name). Fields whose kind is chan (with receive direction) are streamed as a JSON array — MarshalStream receives from the channel until it closes and emits each value as an array element. All other fields go through json.Marshal.
Example:
type Response struct {
Status string `json:"status"`
Rows <-chan Row `json:"rows"`
Total int `json:"total"`
}
ch := make(chan Row)
go func() { defer close(ch); ch <- Row{ID: 1}; ch <- Row{ID: 2} }()
err := jsonstreaming.NewMarshaler().MarshalStream(ctx, w, Response{Status: "ok", Rows: ch, Total: 2})
// {"status":"ok","rows":[{"id":1},{"id":2}],"total":2}
The `,omitempty` tag option is honored using reflect.Value.IsZero. A nil channel emits an empty array.
type MarshalerOption ¶
type MarshalerOption func(*Marshaler)
func WithMarshalerBufferSize ¶
func WithMarshalerBufferSize(n int) MarshalerOption
type StreamReader ¶
type StreamReader struct {
// contains filtered or unexported fields
}
StreamReader pulls elements from a JSON array one at a time.
Usage:
r, err := jsonstreaming.NewStreamReader(src)
if err != nil { return err }
defer r.Close()
var row Row
for r.Next() {
if err := r.Decode(&row); err != nil { return err }
// use row; reuse the same pointer to keep allocations bounded
}
if err := r.Err(); err != nil { return err }
The reader materializes at most one element at a time. The decoder's internal buffer grows only to the size of the largest single element.
func NewStreamReader ¶
func NewStreamReader(r io.Reader) (*StreamReader, error)
NewStreamReader wraps r and consumes the opening bracket of a JSON array. It returns an error if the top-level value is not an array.
func (*StreamReader) Close ¶
func (sr *StreamReader) Close() error
Close does not close the underlying io.Reader; callers are responsible for that. It is provided so the iterator satisfies a Closer-style contract.
func (*StreamReader) Decode ¶
func (sr *StreamReader) Decode(v any) error
Decode reads the current element into v. v should be a pointer. Reusing the same pointer across iterations keeps allocations bounded per element.
func (*StreamReader) Err ¶
func (sr *StreamReader) Err() error
Err reports the first error encountered during iteration, if any.
func (*StreamReader) Index ¶
func (sr *StreamReader) Index() int
Index reports how many elements have been decoded so far.
func (*StreamReader) Next ¶
func (sr *StreamReader) Next() bool
Next advances to the next element. It returns false at end of array or on error; check Err to distinguish. Next must be called before the first Decode.
type StreamWriter ¶
type StreamWriter struct {
// contains filtered or unexported fields
}
StreamWriter serializes a JSON array to an io.Writer one element at a time.
func NewStreamWriter ¶
func NewStreamWriter(w io.Writer, opts ...WriterOption) (*StreamWriter, error)
NewStreamWriter wraps w and writes the opening bracket of a JSON array. The internal buffer size defaults to DefaultBufferSize; override with WithBufferSize.
func (*StreamWriter) Abort ¶
func (sw *StreamWriter) Abort(marker string) error
Abort terminates the stream by appending marker verbatim after the last written element (no closing bracket, no separator) and flushing the buffer downstream. Intended for the "producer cancelled mid-stream" case: the caller decides on a marker (e.g. "Timeout") and downstream consumers see a truncated array with a recognizable sentinel.
After Abort the writer is closed; subsequent SetRow calls return an error and Flush is a no-op. Abort itself is idempotent.
Example, after two rows:
sw.Abort("Timeout") // output: [{...},{...}Timeout
func (*StreamWriter) Count ¶
func (sw *StreamWriter) Count() int
Count reports how many elements have been written.
func (*StreamWriter) Flush ¶
func (sw *StreamWriter) Flush() error
Flush writes the closing bracket and flushes the buffer downstream. It is safe (and idempotent) to call Flush multiple times; subsequent calls are no-ops after the first success.
func (*StreamWriter) SetRow ¶
func (sw *StreamWriter) SetRow(v any) error
SetRow encodes v as the next element of the array.
v may be any type accepted by json.Marshal. Reusing the same pointer across calls keeps allocations bounded to the largest single element.
type WriterOption ¶
type WriterOption func(*writerConfig)
WriterOption configures a StreamWriter.
func WithBufferSize ¶
func WithBufferSize(n int) WriterOption
WithBufferSize overrides the flush buffer size.
func WithFields ¶
func WithFields(names ...string) WriterOption
WithFields projects each SetRow value to only the named top-level JSON fields; every other field is dropped. Names must match the JSON key (i.e. the struct tag, or the field name if untagged).
Given a row {"id":1,"name":"a","secret":"x"} and WithFields("id","name"):
{"id":1,"name":"a"}
Selection is applied via goccy/go-json's FieldQuery. When set, SetRow uses json.MarshalContext under the hood, which allocates a bounded []byte per row — trading the writer's zero-alloc guarantee for projection.
