// Copyright 2018 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 ( "container/list" "reflect" "google.golang.org/protobuf/internal/encoding/wire" pref "google.golang.org/protobuf/reflect/protoreflect" ) var bytesType = reflect.TypeOf([]byte(nil)) func makeLegacyUnknownFieldsFunc(t reflect.Type) func(p *messageDataType) pref.UnknownFields { fu, ok := t.FieldByName("XXX_unrecognized") if !ok || fu.Type != bytesType { return nil } fieldOffset := offsetOf(fu) return func(p *messageDataType) pref.UnknownFields { if p.p.IsNil() { return emptyUnknownFields{} } rv := p.p.Apply(fieldOffset).AsValueOf(bytesType) return (*legacyUnknownBytes)(rv.Interface().(*[]byte)) } } // legacyUnknownBytes is a wrapper around XXX_unrecognized that implements // the protoreflect.UnknownFields interface. This is challenging since we are // limited to a []byte, so we do not have much flexibility in the choice // of data structure that would have been ideal. type legacyUnknownBytes []byte func (fs *legacyUnknownBytes) Len() int { // Runtime complexity: O(n) b := *fs m := map[pref.FieldNumber]bool{} for len(b) > 0 { num, _, n := wire.ConsumeField(b) m[num] = true b = b[n:] } return len(m) } func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) { // Runtime complexity: O(n) b := *fs for len(b) > 0 { num2, _, n := wire.ConsumeField(b) if num == num2 { raw = append(raw, b[:n]...) } b = b[n:] } return raw } func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) { num2, _, _ := wire.ConsumeTag(raw) if len(raw) > 0 && (!raw.IsValid() || num != num2) { panic("invalid raw fields") } // Remove all current fields of num. // Runtime complexity: O(n) b := *fs out := (*fs)[:0] for len(b) > 0 { num2, _, n := wire.ConsumeField(b) if num != num2 { out = append(out, b[:n]...) } b = b[n:] } *fs = out // Append new fields of num. *fs = append(*fs, raw...) } func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) { type entry struct { num pref.FieldNumber raw pref.RawFields } // Collect up a list of all the raw fields. // We preserve the order such that the latest encountered fields // are presented at the end. // // Runtime complexity: O(n) b := *fs l := list.New() m := map[pref.FieldNumber]*list.Element{} for len(b) > 0 { num, _, n := wire.ConsumeField(b) if e, ok := m[num]; ok { x := e.Value.(*entry) x.raw = append(x.raw, b[:n]...) l.MoveToBack(e) } else { x := &entry{num: num} x.raw = append(x.raw, b[:n]...) m[num] = l.PushBack(x) } b = b[n:] } // Iterate over all the raw fields. // This ranges over a snapshot of the current state such that mutations // while ranging are not observable. // // Runtime complexity: O(n) for e := l.Front(); e != nil; e = e.Next() { x := e.Value.(*entry) if !f(x.num, x.raw) { return } } } func (fs *legacyUnknownBytes) IsSupported() bool { return true }