[go-marshal] Update API
- All Marshal* and Unmarshal* methods now require buffers to be correctly sized - Only the Copy{In/Out} variants can handle smaller buffers (or address spaces) PiperOrigin-RevId: 322953881
This commit is contained in:
parent
65b5e64802
commit
c59b792f53
|
@ -413,13 +413,13 @@ func (g *Generator) Run() error {
|
|||
for _, t := range g.collectMarshallableTypes(a, fsets[i]) {
|
||||
impl := g.generateOne(t, fsets[i])
|
||||
// Collect Marshallable types referenced by the generated code.
|
||||
for ref, _ := range impl.ms {
|
||||
for ref := range impl.ms {
|
||||
ms[ref] = struct{}{}
|
||||
}
|
||||
impls = append(impls, impl)
|
||||
// Collect imports referenced by the generated code and add them to
|
||||
// the list of imports we need to copy to the generated code.
|
||||
for name, _ := range impl.is {
|
||||
for name := range impl.is {
|
||||
if !g.imports.markUsed(name) {
|
||||
panic(fmt.Sprintf("Generated code for '%s' referenced a non-existent import with local name '%s'. Either go-marshal needs to add an import to the generated file, or a package in an input source file has a package name differ from the final component of its path, which go-marshal doesn't know how to detect; use an import alias to work around this limitation.", impl.typeName(), name))
|
||||
}
|
||||
|
|
|
@ -268,6 +268,10 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
|
|||
g.emit("// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.\n")
|
||||
g.emit("func (%s *%s) MarshalUnsafe(dst []byte) {\n", g.r, g.typeName())
|
||||
g.inIndent(func() {
|
||||
fallback := func() {
|
||||
g.emit("// Type %s doesn't have a packed layout in memory, fallback to MarshalBytes.\n", g.typeName())
|
||||
g.emit("%s.MarshalBytes(dst)\n", g.r)
|
||||
}
|
||||
if thisPacked {
|
||||
g.recordUsedImport("safecopy")
|
||||
g.recordUsedImport("unsafe")
|
||||
|
@ -277,16 +281,13 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
|
|||
g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r)
|
||||
})
|
||||
g.emit("} else {\n")
|
||||
g.inIndent(func() {
|
||||
g.emit("%s.MarshalBytes(dst)\n", g.r)
|
||||
})
|
||||
g.inIndent(fallback)
|
||||
g.emit("}\n")
|
||||
} else {
|
||||
g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r)
|
||||
}
|
||||
} else {
|
||||
g.emit("// Type %s doesn't have a packed layout in memory, fallback to MarshalBytes.\n", g.typeName())
|
||||
g.emit("%s.MarshalBytes(dst)\n", g.r)
|
||||
fallback()
|
||||
}
|
||||
})
|
||||
g.emit("}\n\n")
|
||||
|
@ -294,6 +295,10 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
|
|||
g.emit("// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.\n")
|
||||
g.emit("func (%s *%s) UnmarshalUnsafe(src []byte) {\n", g.r, g.typeName())
|
||||
g.inIndent(func() {
|
||||
fallback := func() {
|
||||
g.emit("// Type %s doesn't have a packed layout in memory, fallback to UnmarshalBytes.\n", g.typeName())
|
||||
g.emit("%s.UnmarshalBytes(src)\n", g.r)
|
||||
}
|
||||
if thisPacked {
|
||||
g.recordUsedImport("safecopy")
|
||||
g.recordUsedImport("unsafe")
|
||||
|
@ -303,16 +308,13 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
|
|||
g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r)
|
||||
})
|
||||
g.emit("} else {\n")
|
||||
g.inIndent(func() {
|
||||
g.emit("%s.UnmarshalBytes(src)\n", g.r)
|
||||
})
|
||||
g.inIndent(fallback)
|
||||
g.emit("}\n")
|
||||
} else {
|
||||
g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r)
|
||||
}
|
||||
} else {
|
||||
g.emit("// Type %s doesn't have a packed layout in memory, fall back to UnmarshalBytes.\n", g.typeName())
|
||||
g.emit("%s.UnmarshalBytes(src)\n", g.r)
|
||||
fallback()
|
||||
}
|
||||
})
|
||||
g.emit("}\n\n")
|
||||
|
@ -463,8 +465,10 @@ func (g *interfaceGenerator) emitMarshallableSliceForStruct(st *ast.StructType,
|
|||
})
|
||||
g.emit("}\n\n")
|
||||
|
||||
g.emit("// Handle any final partial object.\n")
|
||||
g.emit("if length < size*count && length%size != 0 {\n")
|
||||
g.emit("// Handle any final partial object. buf is guaranteed to be long enough for the\n")
|
||||
g.emit("// final element, but may not contain valid data for the entire range. This may\n")
|
||||
g.emit("// result in unmarshalling zero values for some parts of the object.\n")
|
||||
g.emit("if length%size != 0 {\n")
|
||||
g.inIndent(func() {
|
||||
g.emit("idx := limit\n")
|
||||
g.emit("dst[idx].UnmarshalBytes(buf[size*idx:size*(idx+1)])\n")
|
||||
|
|
|
@ -58,18 +58,12 @@ type Marshallable interface {
|
|||
// likely make use of the type of these fields).
|
||||
SizeBytes() int
|
||||
|
||||
// MarshalBytes serializes a copy of a type to dst. dst may be smaller than
|
||||
// SizeBytes(), which results in a part of the struct being marshalled. Note
|
||||
// that this may have unexpected results for non-packed types, as implicit
|
||||
// padding needs to be taken into account when reasoning about how much of
|
||||
// the type is serialized.
|
||||
// MarshalBytes serializes a copy of a type to dst.
|
||||
// Precondition: dst must be at least SizeBytes() in length.
|
||||
MarshalBytes(dst []byte)
|
||||
|
||||
// UnmarshalBytes deserializes a type from src. src may be smaller than
|
||||
// SizeBytes(), which results in a partially deserialized struct. Note that
|
||||
// this may have unexpected results for non-packed types, as implicit
|
||||
// padding needs to be taken into account when reasoning about how much of
|
||||
// the type is deserialized.
|
||||
// UnmarshalBytes deserializes a type from src.
|
||||
// Precondition: src must be at least SizeBytes() in length.
|
||||
UnmarshalBytes(src []byte)
|
||||
|
||||
// Packed returns true if the marshalled size of the type is the same as the
|
||||
|
@ -89,8 +83,8 @@ type Marshallable interface {
|
|||
// representation to the dst buffer. This is only safe to do when the type
|
||||
// has no implicit padding, see Marshallable.Packed. When Packed would
|
||||
// return false, MarshalUnsafe should fall back to the safer but slower
|
||||
// MarshalBytes. dst may be smaller than SizeBytes(), see comment for
|
||||
// MarshalBytes for implications.
|
||||
// MarshalBytes.
|
||||
// Precondition: dst must be at least SizeBytes() in length.
|
||||
MarshalUnsafe(dst []byte)
|
||||
|
||||
// UnmarshalUnsafe deserializes a type by directly copying to the underlying
|
||||
|
@ -99,8 +93,8 @@ type Marshallable interface {
|
|||
// This allows much faster unmarshalling of types which have no implicit
|
||||
// padding, see Marshallable.Packed. When Packed would return false,
|
||||
// UnmarshalUnsafe should fall back to the safer but slower unmarshal
|
||||
// mechanism implemented in UnmarshalBytes. src may be smaller than
|
||||
// SizeBytes(), see comment for UnmarshalBytes for implications.
|
||||
// mechanism implemented in UnmarshalBytes.
|
||||
// Precondition: src must be at least SizeBytes() in length.
|
||||
UnmarshalUnsafe(src []byte)
|
||||
|
||||
// CopyIn deserializes a Marshallable type from a task's memory. This may
|
||||
|
@ -149,14 +143,16 @@ type Marshallable interface {
|
|||
//
|
||||
// Generates four additional functions for marshalling slices of Foos like this:
|
||||
//
|
||||
// // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It's
|
||||
// // more efficient that repeatedly calling calling Foo.MarshalUnsafe over a
|
||||
// // []Foo in a loop.
|
||||
// // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It
|
||||
// // might be more efficient that repeatedly calling Foo.MarshalUnsafe
|
||||
// // over a []Foo in a loop if the type is Packed.
|
||||
// // Preconditions: dst must be at least len(src)*Foo.SizeBytes() in length.
|
||||
// func MarshalUnsafeFooSlice(src []Foo, dst []byte) (int, error) { ... }
|
||||
//
|
||||
// // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It's
|
||||
// // more efficient that repeatedly calling calling Foo.UnmarshalUnsafe over a
|
||||
// // []Foo in a loop.
|
||||
// // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It
|
||||
// // might be more efficient that repeatedly calling Foo.UnmarshalUnsafe
|
||||
// // over a []Foo in a loop if the type is Packed.
|
||||
// // Preconditions: src must be at least len(dst)*Foo.SizeBytes() in length.
|
||||
// func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) (int, error) { ... }
|
||||
//
|
||||
// // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.
|
||||
|
|
Loading…
Reference in New Issue