jsoniterpb

package module
v0.0.0-...-ef03955 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2024 License: MIT Imports: 27 Imported by: 0

README

jsoniterpb

Replacement of Protojson over Jsoniter Extension

Features
  • Handle any type of object, not just proto.Message, to get a consistent format even with nested uses
  • All features of protojson: ProtobufWellKnownType/Oneof/JsonName/64IntToStr/SortMapKeysByRealValue/CheckUT8/...
  • Support more fuzzy decode methods
  • Better performance
Compatibility test

cd ./internal/protojson && go run ./gen.go, it will download the latest tests file from protocolbuffers/protobuf-go and make it available to jsoniterpb

Warns

Some differences with protojson

  • Only proto3 is supported, proto2 is not supported
  • protojson marshal nil proto.Message as zero value if it is root. but jsoniterpb will marshal it to null
  • View internal/protojson/tests/jsoniterpb_decode_test.go
    • Support more fuzzy decode methods => Search FuzzyDecode
    • Most error messages are not the same => Search ErrMsgNotSame
    • Some error check are not supported => Search NotSupport
Usage

Since the current extensibility of json-iterator/go is not enough to complete this project, it needs to be replaced with another version.

// go.mod 
// go get github.com/molon/jsoniter@jsoniterpb
replace github.com/json-iterator/go => github.com/molon/jsoniter v0.0.0-20230529062209-e42e40bd8588
// protojson.MarshalOptions{} equals
cfg := jsoniter.Config{SortMapKeys: true, DisallowUnknownFields: true}.Froze()
cfg.RegisterExtension(&jsoniterpb.ProtoExtension{})

// protojson.MarshalOptions{EmitUnpopulated: true} equals
cfg := jsoniter.Config{SortMapKeys: true, DisallowUnknownFields: true}.Froze()
cfg.RegisterExtension(&jsoniterpb.ProtoExtension{EmitUnpopulated: true})

// protojson.UnmarshalOptions{DiscardUnknown: true} equals
cfg := jsoniter.Config{SortMapKeys: true, DisallowUnknownFields: false}.Froze()
cfg.RegisterExtension(&jsoniterpb.ProtoExtension{})
Benchmark
goos: darwin
goarch: arm64
pkg: github.com/molon/jsoniterpb
BenchmarkWrite
BenchmarkWrite/protojson
BenchmarkWrite/protojson-8         	    4590	    252336 ns/op	  120711 B/op	    2360 allocs/op
BenchmarkWrite/jsoniter
BenchmarkWrite/jsoniter-8          	    6589	    188076 ns/op	   88383 B/op	    2313 allocs/op
BenchmarkWrite/jsoniter-fast
BenchmarkWrite/jsoniter-fast-8     	   10000	    119375 ns/op	   47925 B/op	    1146 allocs/op
goos: darwin
goarch: arm64
pkg: github.com/molon/jsoniterpb
BenchmarkRead
BenchmarkRead/protojson
BenchmarkRead/protojson-8         	    3328	    371155 ns/op	  113408 B/op	    4021 allocs/op
BenchmarkRead/jsoniter
BenchmarkRead/jsoniter-8          	    5720	    204019 ns/op	   87803 B/op	    2790 allocs/op
BenchmarkRead/jsoniter-nofuzzydecode
BenchmarkRead/jsoniter-nofuzzydecode-8         	    6697	    177609 ns/op	   75491 B/op	    2185 allocs/op

Documentation

Index

Constants

View Source
const (
	Value_message_fullname           protoreflect.FullName = "google.protobuf.Value"
	Value_NumberValue_field_fullname protoreflect.FullName = "google.protobuf.Value.number_value"
)
View Source
const (
	Duration_message_fullname protoreflect.FullName = "google.protobuf.Duration"
)
View Source
const (
	FieldMask_Paths_field_fullname protoreflect.FullName = "google.protobuf.FieldMask.paths"
)
View Source
const (
	NullValue_enum_fullname = "google.protobuf.NullValue"
)
View Source
const (
	Timestamp_message_fullname protoreflect.FullName = "google.protobuf.Timestamp"
)

Variables

View Source
var (
	Any_message_fullname protoreflect.FullName = "google.protobuf.Any"
)
View Source
var ProtoCodecs = map[reflect2.Type]*ProtoCodec{}

https://github.com/protocolbuffers/protobuf-go/blob/master/encoding/protojson/well_known_types.go

View Source
var WktProtoCodecs = map[reflect2.Type]*ProtoCodec{
	reflect2.TypeOfPtr((*anypb.Any)(nil)).Elem(): wktAnyCodec,

	reflect2.TypeOfPtr((*timestamppb.Timestamp)(nil)).Elem(): wktTimestampCodec,
	reflect2.TypeOfPtr((*durationpb.Duration)(nil)).Elem():   wktDurationCodec,

	reflect2.TypeOfPtr((*wrapperspb.BoolValue)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.BoolValue)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.BoolValue)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.Int32Value)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.Int32Value)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.Int32Value)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.Int64Value)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.Int64Value)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.Int64Value)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.UInt32Value)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.UInt32Value)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.UInt32Value)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.UInt64Value)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.UInt64Value)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.UInt64Value)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.FloatValue)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.FloatValue)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.FloatValue)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.DoubleValue)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.DoubleValue)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.DoubleValue)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.StringValue)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.StringValue)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.StringValue)(ptr).Value))
		}),
	reflect2.TypeOfPtr((*wrapperspb.BytesValue)(nil)).Elem(): (&ProtoCodec{}).
		SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
			stream.WriteVal(((*wrapperspb.BytesValue)(ptr)).GetValue())
		}).
		SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
			iter.ReadVal(&((*wrapperspb.BytesValue)(ptr).Value))
		}),

	reflect2.TypeOfPtr((*structpb.Struct)(nil)).Elem():    wktStructCodec,
	reflect2.TypeOfPtr((*structpb.Struct)(nil)):           wktStructCodec,
	reflect2.TypeOfPtr((*structpb.ListValue)(nil)).Elem(): wktListValueCodec,
	reflect2.TypeOfPtr((*structpb.ListValue)(nil)):        wktListValueCodec,
	reflect2.TypeOfPtr((*structpb.Value)(nil)).Elem():     wktValueCodec,
	reflect2.TypeOfPtr((*structpb.Value)(nil)):            wktValueCodec,

	reflect2.TypeOfPtr((*fieldmaskpb.FieldMask)(nil)).Elem(): wktFieldmaskCodec,
}

Functions

func IsWellKnownType

func IsWellKnownType(typ reflect2.Type) bool

func JSONCamelCase

func JSONCamelCase(s string) string

JSONCamelCase converts a snake_case identifier to a camelCase identifier, according to the protobuf JSON specification.

func JSONSnakeCase

func JSONSnakeCase(s string) string

JSONSnakeCase converts a camelCase identifier to a snake_case identifier, according to the protobuf JSON specification.

func QuoteValidUTF8String

func QuoteValidUTF8String(s string) ([]byte, error)

func QuoteValidUTF8StringWithHTMLEscaped

func QuoteValidUTF8StringWithHTMLEscaped(s string) ([]byte, error)

func WrapElemDecoder

func WrapElemDecoder(typ reflect2.Type, dec jsoniter.ValDecoder, ifNil func(ptr unsafe.Pointer)) jsoniter.ValDecoder

func WrapElemEncoder

func WrapElemEncoder(typ reflect2.Type, enc jsoniter.ValEncoder, ifNil func(stream *jsoniter.Stream)) jsoniter.ValEncoder

Types

type OptionalDecoder

type OptionalDecoder struct {
	ValueType    reflect2.Type
	ValueDecoder jsoniter.ValDecoder
	IfNil        func(ptr unsafe.Pointer)
}

func (*OptionalDecoder) Decode

func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator)

type OptionalEncoder

type OptionalEncoder struct {
	ValueEncoder jsoniter.ValEncoder
	IfNil        func(stream *jsoniter.Stream)
}

func (*OptionalEncoder) Encode

func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream)

func (*OptionalEncoder) IsEmpty

func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool

type ProtoCodec

type ProtoCodec struct {
	EncoderCreator func(e *ProtoExtension, typ reflect2.Type) jsoniter.ValEncoder
	DecoderCreator func(e *ProtoExtension, typ reflect2.Type) jsoniter.ValDecoder
}

func (*ProtoCodec) SetElemDecodeFunc

func (codec *ProtoCodec) SetElemDecodeFunc(decodeFunc func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator)) *ProtoCodec

func (*ProtoCodec) SetElemEncodeFunc

func (codec *ProtoCodec) SetElemEncodeFunc(encodeFunc func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream)) *ProtoCodec

type ProtoExtension

type ProtoExtension struct {
	jsoniter.DummyExtension

	EmitUnpopulated bool
	UseEnumNumbers  bool
	UseProtoNames   bool
	Resolver        interface {
		protoregistry.MessageTypeResolver
		// TIPS: does not support it now
		protoregistry.ExtensionTypeResolver
	}

	Encode64BitAsInteger bool
	SortMapKeysAsString  bool
	PermitInvalidUTF8    bool
	DisableFuzzyDecode   bool
}

func (*ProtoExtension) CreateDecoder

func (e *ProtoExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder

func (*ProtoExtension) CreateEncoder

func (e *ProtoExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder

func (*ProtoExtension) DecorateDecoder

func (e *ProtoExtension) DecorateDecoder(typ reflect2.Type, decoder jsoniter.ValDecoder) jsoniter.ValDecoder

func (*ProtoExtension) DecorateEncoder

func (e *ProtoExtension) DecorateEncoder(typ reflect2.Type, encoder jsoniter.ValEncoder) jsoniter.ValEncoder

func (*ProtoExtension) GetResolver

func (*ProtoExtension) UpdateArrayEncoderConstructor

func (e *ProtoExtension) UpdateArrayEncoderConstructor(v *jsoniter.ArrayEncoderConstructor)

func (*ProtoExtension) UpdateMapEncoderConstructor

func (e *ProtoExtension) UpdateMapEncoderConstructor(v *jsoniter.MapEncoderConstructor)

func (*ProtoExtension) UpdateSliceEncoderConstructor

func (e *ProtoExtension) UpdateSliceEncoderConstructor(v *jsoniter.SliceEncoderConstructor)

func (*ProtoExtension) UpdateStructDescriptor

func (e *ProtoExtension) UpdateStructDescriptor(desc *jsoniter.StructDescriptor)

Handle EmitUnpopulated and UseProtoNames

func (*ProtoExtension) UpdateStructDescriptorConstructor

func (e *ProtoExtension) UpdateStructDescriptorConstructor(c *jsoniter.StructDescriptorConstructor)

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL