github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/jsoni/stream.go (about)

     1  package jsoni
     2  
     3  import (
     4  	"io"
     5  )
     6  
     7  // Stream is a io.Writer like object, with JSON specific write functions.
     8  // Error is not returned as return value, but stored as Error member on this stream instance.
     9  type Stream struct {
    10  	cfg        *frozenConfig
    11  	out        io.Writer
    12  	buf        []byte
    13  	Error      error
    14  	indention  int
    15  	Attachment interface{} // open for customized encoder
    16  }
    17  
    18  // NewStream create new stream instance.
    19  // cfg can be jsoni.ConfigDefault.
    20  // out can be nil if write to internal buffer.
    21  // bufSize is the initial size for the internal buffer in bytes.
    22  func NewStream(cfg API, out io.Writer, bufSize int) *Stream {
    23  	return &Stream{
    24  		cfg:       cfg.(*frozenConfig),
    25  		out:       out,
    26  		buf:       make([]byte, 0, bufSize),
    27  		Error:     nil,
    28  		indention: 0,
    29  	}
    30  }
    31  
    32  // Pool returns a pool can provide more stream with same configuration
    33  func (s *Stream) Pool() StreamPool { return s.cfg }
    34  
    35  // Reset reuse this stream instance by assign a new writer
    36  func (s *Stream) Reset(out io.Writer) {
    37  	s.out = out
    38  	s.buf = s.buf[:0]
    39  }
    40  
    41  // Available returns how many bytes are unused in the buffer.
    42  func (s *Stream) Available() int { return cap(s.buf) - len(s.buf) }
    43  
    44  // Buffered returns the number of bytes that have been written into the current buffer.
    45  func (s *Stream) Buffered() int { return len(s.buf) }
    46  
    47  // Buffer if writer is nil, use this method to take the result
    48  func (s *Stream) Buffer() []byte { return s.buf }
    49  
    50  // SetBuffer allows appending to the internal buffer directly
    51  func (s *Stream) SetBuffer(buf []byte) { s.buf = buf }
    52  
    53  // Write writes the contents of p into the buffer.
    54  // It returns the number of bytes written.
    55  // If nn < len(p), it also returns an error explaining
    56  // why the write is short.
    57  func (s *Stream) Write(p []byte) (nn int, err error) {
    58  	s.buf = append(s.buf, p...)
    59  	if s.out != nil {
    60  		nn, err = s.out.Write(s.buf)
    61  		s.buf = s.buf[nn:]
    62  		return
    63  	}
    64  	return len(p), nil
    65  }
    66  
    67  // WriteByte writes a single byte.
    68  func (s *Stream) writeByte(c byte)                    { s.buf = append(s.buf, c) }
    69  func (s *Stream) write2Bytes(c1, c2 byte)             { s.buf = append(s.buf, c1, c2) }
    70  func (s *Stream) write3Bytes(c1, c2, c3 byte)         { s.buf = append(s.buf, c1, c2, c3) }
    71  func (s *Stream) write4Bytes(c1, c2, c3, c4 byte)     { s.buf = append(s.buf, c1, c2, c3, c4) }
    72  func (s *Stream) write5Bytes(c1, c2, c3, c4, c5 byte) { s.buf = append(s.buf, c1, c2, c3, c4, c5) }
    73  
    74  // Flush writes any buffered data to the underlying io.Writer.
    75  func (s *Stream) Flush() error {
    76  	if s.out == nil {
    77  		return nil
    78  	}
    79  	if s.Error != nil {
    80  		return s.Error
    81  	}
    82  	_, err := s.out.Write(s.buf)
    83  	if err != nil {
    84  		if s.Error == nil {
    85  			s.Error = err
    86  		}
    87  		return err
    88  	}
    89  	s.buf = s.buf[:0]
    90  	return nil
    91  }
    92  
    93  // WriteRawBytes write string out without quotes, just like []byte
    94  func (s *Stream) WriteRawBytes(a []byte) { s.buf = append(s.buf, a...) }
    95  
    96  // WriteRaw write string out without quotes, just like []byte
    97  func (s *Stream) WriteRaw(a string) { s.buf = append(s.buf, a...) }
    98  
    99  // WriteNil write null to stream
   100  func (s *Stream) WriteNil() { s.write4Bytes('n', 'u', 'l', 'l') }
   101  
   102  // WriteTrue write true to stream
   103  func (s *Stream) WriteTrue() { s.write4Bytes('t', 'r', 'u', 'e') }
   104  
   105  // WriteFalse write false to stream
   106  func (s *Stream) WriteFalse() { s.write5Bytes('f', 'a', 'l', 's', 'e') }
   107  
   108  // WriteBool write true or false into stream
   109  func (s *Stream) WriteBool(val bool) {
   110  	if val {
   111  		s.WriteTrue()
   112  	} else {
   113  		s.WriteFalse()
   114  	}
   115  }
   116  
   117  // WriteObjectStart write { with possible indention
   118  func (s *Stream) WriteObjectStart() {
   119  	s.indention += s.cfg.indentionStep
   120  	s.writeByte('{')
   121  	s.writeIndention(0)
   122  }
   123  
   124  // WriteObjectField write "field": with possible indention
   125  func (s *Stream) WriteObjectField(field string) {
   126  	s.WriteString(field)
   127  	if s.indention > 0 {
   128  		s.write2Bytes(':', ' ')
   129  	} else {
   130  		s.writeByte(':')
   131  	}
   132  }
   133  
   134  // WriteObjectEnd write } with possible indention
   135  func (s *Stream) WriteObjectEnd() {
   136  	s.writeIndention(s.cfg.indentionStep)
   137  	s.indention -= s.cfg.indentionStep
   138  	s.writeByte('}')
   139  }
   140  
   141  // WriteEmptyObject write {}
   142  func (s *Stream) WriteEmptyObject() {
   143  	s.writeByte('{')
   144  	s.writeByte('}')
   145  }
   146  
   147  // WriteMore write , with possible indention
   148  func (s *Stream) WriteMore() {
   149  	s.writeByte(',')
   150  	s.writeIndention(0)
   151  }
   152  
   153  // WriteArrayStart write [ with possible indention
   154  func (s *Stream) WriteArrayStart() {
   155  	s.indention += s.cfg.indentionStep
   156  	s.writeByte('[')
   157  	s.writeIndention(0)
   158  }
   159  
   160  // WriteEmptyArray write []
   161  func (s *Stream) WriteEmptyArray() {
   162  	s.write2Bytes('[', ']')
   163  }
   164  
   165  // WriteArrayEnd write ] with possible indention
   166  func (s *Stream) WriteArrayEnd() {
   167  	s.writeIndention(s.cfg.indentionStep)
   168  	s.indention -= s.cfg.indentionStep
   169  	s.writeByte(']')
   170  }
   171  
   172  func (s *Stream) writeIndention(delta int) {
   173  	if s.indention == 0 {
   174  		return
   175  	}
   176  	s.writeByte('\n')
   177  	toWrite := s.indention - delta
   178  	for i := 0; i < toWrite; i++ {
   179  		s.buf = append(s.buf, ' ')
   180  	}
   181  }