Joe Tsai 4fe9663f4c internal/impl: rename MessageType as MessageInfo
The name MessageType is easily confused with protoreflect.MessageType.
Rename it as MessageInfo, which follows the pattern set by v1,
where the equivalent data structure is called InternalMessageInfo.

Change-Id: I535956e1f7c6e9b07e9585e889d5e93388d0d2ce
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/178478
Reviewed-by: Damien Neil <dneil@google.com>
2019-05-22 14:54:35 +00:00

184 lines
4.6 KiB
Go

// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package impl
import (
"sort"
"sync/atomic"
"google.golang.org/protobuf/internal/errors"
proto "google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
type marshalOptions uint
const (
marshalAllowPartial marshalOptions = 1 << iota
marshalDeterministic
marshalUseCachedSize
)
func newMarshalOptions(opts piface.MarshalOptions) marshalOptions {
var o marshalOptions
if opts.AllowPartial {
o |= marshalAllowPartial
}
if opts.Deterministic {
o |= marshalDeterministic
}
if opts.UseCachedSize {
o |= marshalUseCachedSize
}
return o
}
func (o marshalOptions) Options() proto.MarshalOptions {
return proto.MarshalOptions{
AllowPartial: o.AllowPartial(),
Deterministic: o.Deterministic(),
UseCachedSize: o.UseCachedSize(),
}
}
func (o marshalOptions) AllowPartial() bool { return o&marshalAllowPartial != 0 }
func (o marshalOptions) Deterministic() bool { return o&marshalDeterministic != 0 }
func (o marshalOptions) UseCachedSize() bool { return o&marshalUseCachedSize != 0 }
// size is protoreflect.Methods.Size.
func (mi *MessageInfo) size(msg pref.ProtoMessage) (size int) {
return mi.sizePointer(pointerOfIface(msg), 0)
}
func (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) {
mi.init()
if p.IsNil() {
return 0
}
if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() {
return int(atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()))
}
return mi.sizePointerSlow(p, opts)
}
func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int) {
if mi.extensionOffset.IsValid() {
e := p.Apply(mi.extensionOffset).Extensions()
size += mi.sizeExtensions(e, opts)
}
for _, f := range mi.fieldsOrdered {
fptr := p.Apply(f.offset)
if f.isPointer && fptr.Elem().IsNil() {
continue
}
if f.funcs.size == nil {
continue
}
size += f.funcs.size(fptr, f.tagsize, opts)
}
if mi.unknownOffset.IsValid() {
u := *p.Apply(mi.unknownOffset).Bytes()
size += len(u)
}
if mi.sizecacheOffset.IsValid() {
atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
}
return size
}
// marshalAppend is protoreflect.Methods.MarshalAppend.
func (mi *MessageInfo) marshalAppend(b []byte, msg pref.ProtoMessage, opts piface.MarshalOptions) ([]byte, error) {
return mi.marshalAppendPointer(b, pointerOfIface(msg), newMarshalOptions(opts))
}
func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
mi.init()
if p.IsNil() {
return b, nil
}
var err error
var nerr errors.NonFatal
// The old marshaler encodes extensions at beginning.
if mi.extensionOffset.IsValid() {
e := p.Apply(mi.extensionOffset).Extensions()
// TODO: Special handling for MessageSet?
b, err = mi.appendExtensions(b, e, opts)
if !nerr.Merge(err) {
return b, err
}
}
for _, f := range mi.fieldsOrdered {
fptr := p.Apply(f.offset)
if f.isPointer && fptr.Elem().IsNil() {
continue
}
if f.funcs.marshal == nil {
continue
}
b, err = f.funcs.marshal(b, fptr, f.wiretag, opts)
if !nerr.Merge(err) {
return b, err
}
}
if mi.unknownOffset.IsValid() {
u := *p.Apply(mi.unknownOffset).Bytes()
b = append(b, u...)
}
return b, nerr.E
}
func (mi *MessageInfo) sizeExtensions(ext *legacyExtensionMap, opts marshalOptions) (n int) {
if ext == nil {
return 0
}
for _, e := range *ext {
ei := mi.extensionFieldInfo(e.Desc)
if ei.funcs.size == nil {
continue
}
n += ei.funcs.size(e.value, ei.tagsize, opts)
}
return n
}
func (mi *MessageInfo) appendExtensions(b []byte, ext *legacyExtensionMap, opts marshalOptions) ([]byte, error) {
if ext == nil {
return b, nil
}
switch len(*ext) {
case 0:
return b, nil
case 1:
// Fast-path for one extension: Don't bother sorting the keys.
var err error
for _, e := range *ext {
ei := mi.extensionFieldInfo(e.Desc)
b, err = ei.funcs.marshal(b, e.value, ei.wiretag, opts)
}
return b, err
default:
// Sort the keys to provide a deterministic encoding.
// Not sure this is required, but the old code does it.
keys := make([]int, 0, len(*ext))
for k := range *ext {
keys = append(keys, int(k))
}
sort.Ints(keys)
var err error
var nerr errors.NonFatal
for _, k := range keys {
e := (*ext)[int32(k)]
ei := mi.extensionFieldInfo(e.Desc)
b, err = ei.funcs.marshal(b, e.value, ei.wiretag, opts)
if !nerr.Merge(err) {
return b, err
}
}
return b, nerr.E
}
}