github.com/spi-ca/misc@v1.0.1/types/json.go (about)

     1  package types
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/json"
     6  	"github.com/pkg/errors"
     7  	"github.com/spi-ca/misc"
     8  	"github.com/spi-ca/misc/strutil"
     9  )
    10  
    11  // JSON is an alias for json.RawMessage, which is
    12  // a []byte underneath.
    13  // JSON implements Marshal and Unmarshal.
    14  type JSON json.RawMessage
    15  
    16  // String output your JSON.
    17  func (j JSON) String() string {
    18  	return strutil.B2S(j)
    19  }
    20  
    21  // Unmarshal your JSON variable into dest.
    22  func (j JSON) Unmarshal(dest any) error {
    23  	iter := misc.JSONCodec.BorrowIterator(j)
    24  	defer misc.JSONCodec.ReturnIterator(iter)
    25  	iter.ReadVal(dest)
    26  	return iter.Error
    27  }
    28  
    29  // Marshal obj into your JSON variable.
    30  func (j *JSON) Marshal(obj any) (err error) {
    31  	stream := misc.JSONCodec.BorrowStream(nil)
    32  	defer misc.JSONCodec.ReturnStream(stream)
    33  
    34  	stream.WriteVal(obj)
    35  	defer stream.Flush()
    36  	if err = stream.Error; err != nil {
    37  		return
    38  	}
    39  	buf := make(JSON, stream.Buffered())
    40  	copy(buf, stream.Buffer())
    41  	*j = buf
    42  	return
    43  }
    44  
    45  // UnmarshalJSON sets *j to a copy of data.
    46  func (j *JSON) UnmarshalJSON(data []byte) error {
    47  	if j == nil {
    48  		return errors.New("json: unmarshal json on nil pointer to json")
    49  	}
    50  
    51  	*j = append((*j)[0:0], data...)
    52  	return nil
    53  }
    54  
    55  // MarshalJSON returns j as the JSON encoding of j.
    56  func (j JSON) MarshalJSON() ([]byte, error) {
    57  	return j, nil
    58  }
    59  
    60  // Value returns j as a value.
    61  // Unmarshal into RawMessage for validation.
    62  func (j JSON) Value() (driver.Value, error) {
    63  	var r json.RawMessage
    64  	if err := j.Unmarshal(&r); err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	return []byte(r), nil
    69  }
    70  
    71  // Scan stores the src in *j.
    72  func (j *JSON) Scan(src any) error {
    73  	var source []byte
    74  
    75  	switch src.(type) {
    76  	case string:
    77  		source = []byte(src.(string))
    78  	case []byte:
    79  		source = src.([]byte)
    80  	default:
    81  		return errors.New("incompatible type for json")
    82  	}
    83  
    84  	*j = JSON(append((*j)[0:0], source...))
    85  
    86  	return nil
    87  }