Skip to content
darxnetPublic

About

Generates CopyFrom and Copy methods for Go structs that reuse the destination's memory instead of allocating

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

gocopy

Go Reference Go Coverage

gocopy generates CopyFrom(src) and Copy() methods that make a struct value an independent copy of another — without allocating what the destination already owns.

Why gocopy?

*dst = *src is a shallow copy: every slice and map in dst now shares memory with src, and the first write to one shows up in the other. The deep copy by hand allocates a fresh slice for every field on every call, and goes stale the day a field is added. gocopy writes the method from the struct definition and reuses dst's memory:

// Code generated by gocopy; DO NOT EDIT.

// CopyFrom makes dst an independent copy of src: one bulk copy, then the
// fields that would share memory get dst's own, reusing its capacity.
func (dst *Request) CopyFrom(src *Request) {
	keepData := dst.Data[:0]
	keepInner := dst.Inner

	*dst = *src
	dst.Data = append(keepData, src.Data...)
	dst.Inner = keepInner
	dst.Inner.CopyFrom(&src.Inner)
}

// Copy returns a new independent copy of src.
func (src *Request) Copy() (dst Request) {
	dst.CopyFrom(src)
	return dst
}

A CopyFrom into a pooled, already-sized dst allocates nothing.

What it does per field

Field Copy
slice append(dst.F[:0], src.F...) — into dst's own array
map entry by entry into dst's own map (clear first; a nil dst map is made, a nil src leaves dst empty)
struct with CopyFrom(*T) dst.F.CopyFrom(&src.F)
pointer to struct with CopyFrom(*T) into dst's own object; a nil dst gets a new one, a nil src gives nil
array of slices / of structs with CopyFrom element by element
everything else (numbers, strings, pointers, interfaces, chans, funcs, plain structs) assigned as it is

Struct tags change the treatment of a field:

Tag Effect
copy:"-" dst keeps its own value
copy:"shallow" assigned as it is, even if it is a slice or a map — on purpose, and visibly

A field holding a sync or sync/atomic type (also inside a nested struct or array, by value) must carry one of the two tags; an array of maps too.

Two modes

Bulk (the default): dst's own slices, maps and nested values are saved, the struct is assigned in one go, the saved fields are put back and filled from src. The type also gets Copy().

Field by field: a struct that holds a lock or an atomic cannot be assigned as a whole (go vet copylocks), so every field is copied on its own, and there is no Copy(): such a value is not meant to be returned.

The mode is chosen per type, and shown in the comment of the generated method.

Installation

go get -tool github.com/darxnet/gocopy/cmd/gocopy

Requires Go 1.24 (go get -tool). No dependencies: the package is loaded with go list -export and go/importer from the standard library.

Usage

Put the directive next to the type and run go generate:

//go:generate go tool gocopy -type=Request,Response
type Request struct {
	Data  []byte
	Inner Inner
	Cache map[string]int `copy:"-"`
	Mu    sync.Mutex     `copy:"-"`
}

This writes request_copy.gen.go and response_copy.gen.go in the same package. -dir points the generator at another package.

The generator is also a library — gocopy.Load and Package.Generate — for tools that want the source without the file.

Rules of the generated CopyFrom

  • src and dst must not be the same value or share slices: dst's arrays are overwritten.
  • A nested type's CopyFrom is found by its method set when the generator runs: generate (or write) the inner type's first.
  • Pointers other than "pointer to a struct with CopyFrom" are shared with src. That is usually right for references to long-lived objects; for an owned object, give its type a CopyFrom.

See also

The sibling modules follow the same rule — nothing allocated on the hot path, the zero value ready to use:

  • goshard — sharded, lock-based concurrent map for high-churn data: stores allocate nothing
  • gosync — generic concurrent map with sync.Map semantics and no interface boxing, for read-mostly data
  • goreset — generates Reset() for pooled structs: back to the zero state, memory kept

License

Apache License 2.0. See LICENSE for details.

About

Generates CopyFrom and Copy methods for Go structs that reuse the destination's memory instead of allocating

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages