owpengram-server/internal/compat/layerwire/walk.go

116 lines
2.5 KiB
Go

package layerwire
import (
"fmt"
"github.com/gotd/td/bin"
)
// skipObject advances b past one boxed object (CRC + body), resolving the
// constructor from the canonical schema.
func (m *schemaModel) skipObject(b *bin.Buffer) error {
id, err := b.PeekID()
if err != nil {
return err
}
cl, ok := m.byCRC[id]
if !ok {
return fmt.Errorf("layerwire: unknown constructor %#08x", id)
}
if err := b.ConsumeID(id); err != nil {
return err
}
return m.skipCtorBody(b, cl)
}
// skipCtorBody advances b past a constructor body (no leading CRC), evaluating
// flag integers so conditional fields are read iff present.
func (m *schemaModel) skipCtorBody(b *bin.Buffer, cl *ctorLayout) error {
var flags map[string]uint32
for i := range cl.fields {
f := &cl.fields[i]
if f.isFlags {
v, err := b.Uint32()
if err != nil {
return fmt.Errorf("%s.%s: %w", cl.name, f.name, err)
}
if flags == nil {
flags = make(map[string]uint32, 2)
}
flags[f.name] = v
continue
}
if f.conditional() && flags[f.flagName]&(1<<uint(f.flagBit)) == 0 {
continue
}
if err := m.skipValue(b, f); err != nil {
return fmt.Errorf("%s.%s: %w", cl.name, f.name, err)
}
}
return nil
}
// skipValue advances b past one (already known-present) field value.
func (m *schemaModel) skipValue(b *bin.Buffer, f *fieldLayout) error {
switch f.kind {
case kindInt:
_, err := b.Int()
return err
case kindLong:
_, err := b.Long()
return err
case kindDouble:
_, err := b.Double()
return err
case kindInt128:
_, err := b.Int128()
return err
case kindInt256:
_, err := b.Int256()
return err
case kindBytes:
_, err := b.Bytes()
return err
case kindString:
_, err := b.String()
return err
case kindBool:
_, err := b.Bool()
return err
case kindTrue:
return nil
case kindVector, kindVectorBare:
if f.kind == kindVector {
id, err := b.Uint32()
if err != nil {
return err
}
if id != vectorTypeID {
return fmt.Errorf("expected vector id, got %#08x", id)
}
}
n, err := b.Int()
if err != nil {
return err
}
if n < 0 {
return fmt.Errorf("negative vector length %d", n)
}
for i := 0; i < n; i++ {
if err := m.skipValue(b, f.elem); err != nil {
return err
}
}
return nil
case kindObject:
return m.skipObject(b)
case kindBareObject:
cl, ok := m.bareByT[f.typeName]
if !ok {
return fmt.Errorf("unknown bare type %q", f.typeName)
}
return m.skipCtorBody(b, cl)
default:
return fmt.Errorf("bad wire kind %d", f.kind)
}
}