[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]) {
|
for _, t := range g.collectMarshallableTypes(a, fsets[i]) {
|
||||||
impl := g.generateOne(t, fsets[i])
|
impl := g.generateOne(t, fsets[i])
|
||||||
// Collect Marshallable types referenced by the generated code.
|
// Collect Marshallable types referenced by the generated code.
|
||||||
for ref, _ := range impl.ms {
|
for ref := range impl.ms {
|
||||||
ms[ref] = struct{}{}
|
ms[ref] = struct{}{}
|
||||||
}
|
}
|
||||||
impls = append(impls, impl)
|
impls = append(impls, impl)
|
||||||
// Collect imports referenced by the generated code and add them to
|
// Collect imports referenced by the generated code and add them to
|
||||||
// the list of imports we need to copy to the generated code.
|
// 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) {
|
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))
|
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("// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.\n")
|
||||||
g.emit("func (%s *%s) MarshalUnsafe(dst []byte) {\n", g.r, g.typeName())
|
g.emit("func (%s *%s) MarshalUnsafe(dst []byte) {\n", g.r, g.typeName())
|
||||||
g.inIndent(func() {
|
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 {
|
if thisPacked {
|
||||||
g.recordUsedImport("safecopy")
|
g.recordUsedImport("safecopy")
|
||||||
g.recordUsedImport("unsafe")
|
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("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r)
|
||||||
})
|
})
|
||||||
g.emit("} else {\n")
|
g.emit("} else {\n")
|
||||||
g.inIndent(func() {
|
g.inIndent(fallback)
|
||||||
g.emit("%s.MarshalBytes(dst)\n", g.r)
|
|
||||||
})
|
|
||||||
g.emit("}\n")
|
g.emit("}\n")
|
||||||
} else {
|
} else {
|
||||||
g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r)
|
g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.emit("// Type %s doesn't have a packed layout in memory, fallback to MarshalBytes.\n", g.typeName())
|
fallback()
|
||||||
g.emit("%s.MarshalBytes(dst)\n", g.r)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
g.emit("}\n\n")
|
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("// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.\n")
|
||||||
g.emit("func (%s *%s) UnmarshalUnsafe(src []byte) {\n", g.r, g.typeName())
|
g.emit("func (%s *%s) UnmarshalUnsafe(src []byte) {\n", g.r, g.typeName())
|
||||||
g.inIndent(func() {
|
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 {
|
if thisPacked {
|
||||||
g.recordUsedImport("safecopy")
|
g.recordUsedImport("safecopy")
|
||||||
g.recordUsedImport("unsafe")
|
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("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r)
|
||||||
})
|
})
|
||||||
g.emit("} else {\n")
|
g.emit("} else {\n")
|
||||||
g.inIndent(func() {
|
g.inIndent(fallback)
|
||||||
g.emit("%s.UnmarshalBytes(src)\n", g.r)
|
|
||||||
})
|
|
||||||
g.emit("}\n")
|
g.emit("}\n")
|
||||||
} else {
|
} else {
|
||||||
g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r)
|
g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.emit("// Type %s doesn't have a packed layout in memory, fall back to UnmarshalBytes.\n", g.typeName())
|
fallback()
|
||||||
g.emit("%s.UnmarshalBytes(src)\n", g.r)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
g.emit("}\n\n")
|
g.emit("}\n\n")
|
||||||
|
@ -463,8 +465,10 @@ func (g *interfaceGenerator) emitMarshallableSliceForStruct(st *ast.StructType,
|
||||||
})
|
})
|
||||||
g.emit("}\n\n")
|
g.emit("}\n\n")
|
||||||
|
|
||||||
g.emit("// Handle any final partial object.\n")
|
g.emit("// Handle any final partial object. buf is guaranteed to be long enough for the\n")
|
||||||
g.emit("if length < size*count && length%size != 0 {\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.inIndent(func() {
|
||||||
g.emit("idx := limit\n")
|
g.emit("idx := limit\n")
|
||||||
g.emit("dst[idx].UnmarshalBytes(buf[size*idx:size*(idx+1)])\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).
|
// likely make use of the type of these fields).
|
||||||
SizeBytes() int
|
SizeBytes() int
|
||||||
|
|
||||||
// MarshalBytes serializes a copy of a type to dst. dst may be smaller than
|
// MarshalBytes serializes a copy of a type to dst.
|
||||||
// SizeBytes(), which results in a part of the struct being marshalled. Note
|
// Precondition: dst must be at least SizeBytes() in length.
|
||||||
// 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(dst []byte)
|
MarshalBytes(dst []byte)
|
||||||
|
|
||||||
// UnmarshalBytes deserializes a type from src. src may be smaller than
|
// UnmarshalBytes deserializes a type from src.
|
||||||
// SizeBytes(), which results in a partially deserialized struct. Note that
|
// Precondition: src must be at least SizeBytes() in length.
|
||||||
// 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(src []byte)
|
UnmarshalBytes(src []byte)
|
||||||
|
|
||||||
// Packed returns true if the marshalled size of the type is the same as the
|
// 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
|
// representation to the dst buffer. This is only safe to do when the type
|
||||||
// has no implicit padding, see Marshallable.Packed. When Packed would
|
// has no implicit padding, see Marshallable.Packed. When Packed would
|
||||||
// return false, MarshalUnsafe should fall back to the safer but slower
|
// return false, MarshalUnsafe should fall back to the safer but slower
|
||||||
// MarshalBytes. dst may be smaller than SizeBytes(), see comment for
|
// MarshalBytes.
|
||||||
// MarshalBytes for implications.
|
// Precondition: dst must be at least SizeBytes() in length.
|
||||||
MarshalUnsafe(dst []byte)
|
MarshalUnsafe(dst []byte)
|
||||||
|
|
||||||
// UnmarshalUnsafe deserializes a type by directly copying to the underlying
|
// 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
|
// This allows much faster unmarshalling of types which have no implicit
|
||||||
// padding, see Marshallable.Packed. When Packed would return false,
|
// padding, see Marshallable.Packed. When Packed would return false,
|
||||||
// UnmarshalUnsafe should fall back to the safer but slower unmarshal
|
// UnmarshalUnsafe should fall back to the safer but slower unmarshal
|
||||||
// mechanism implemented in UnmarshalBytes. src may be smaller than
|
// mechanism implemented in UnmarshalBytes.
|
||||||
// SizeBytes(), see comment for UnmarshalBytes for implications.
|
// Precondition: src must be at least SizeBytes() in length.
|
||||||
UnmarshalUnsafe(src []byte)
|
UnmarshalUnsafe(src []byte)
|
||||||
|
|
||||||
// CopyIn deserializes a Marshallable type from a task's memory. This may
|
// 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:
|
// Generates four additional functions for marshalling slices of Foos like this:
|
||||||
//
|
//
|
||||||
// // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It's
|
// // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It
|
||||||
// // more efficient that repeatedly calling calling Foo.MarshalUnsafe over a
|
// // might be more efficient that repeatedly calling Foo.MarshalUnsafe
|
||||||
// // []Foo in a loop.
|
// // 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) { ... }
|
// func MarshalUnsafeFooSlice(src []Foo, dst []byte) (int, error) { ... }
|
||||||
//
|
//
|
||||||
// // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It's
|
// // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It
|
||||||
// // more efficient that repeatedly calling calling Foo.UnmarshalUnsafe over a
|
// // might be more efficient that repeatedly calling Foo.UnmarshalUnsafe
|
||||||
// // []Foo in a loop.
|
// // 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) { ... }
|
// func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) (int, error) { ... }
|
||||||
//
|
//
|
||||||
// // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.
|
// // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.
|
||||||
|
|
Loading…
Reference in New Issue