capnproto / go-capnp

Cap'n Proto library and code generator for Go

Home Page:https://capnproto.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Improve Message.Reset API

lthibault opened this issue · comments

It's not immediately obvious how to use Message.Reset to reuse a message from application code. At a glance, I would expect to have to do the following:

  1. foo.Message().Reset(capnp.SingleSegment(nil))
  2. foo, _ = NewRootFoo(foo.Segment()), or some such

The "or some such" in item 2 says it all: it is not immediately clear where the proper segment can be obtained.

An alternative suggested by @zenhack would be to use NewMessage(), though this will allocate an additional message. Perhaps this can be mitigated with some clever use of sync.Pool?

Adding this to the 3.0 milestone, so we remember to consider it before locking ourselves in to the current API.

Relatedly, I would expect the following to work, but it produces a panic:

type pointerStore struct {
	arena capnp.Arena
	msg   *capnp.Message
}

func (ps *pointerStore) Store(ptr capnp.Ptr) error {
	if ps.msg == nil {
		ps.msg = &capnp.Message{}
	}

	ps.arena = capnp.SingleSegment(nil)
	ps.msg.Reset(ps.arena)

	return ps.msg.SetRoot(ptr)
}

Another thought: is it possible to have Message.Reset() call Arena.Reset() instead of having to call the latter separately, as we do in transport.go?

release := func() {
	if alreadyReleased {
		return
	}
	alreadyReleased = true

	msg.Reset(nil)
	arena.Release()  // fold this into msg.Reset ?
}

Per discussion on matrix, we're going to call this one good; we'd both misunderstood what the API was for, and the docs have been clarified.