Commit 37dd2d99 authored by Eric Myhre's avatar Eric Myhre

Check for sideffects from invalid manipulations.

Interestingly, the codegen'd map ends up doing this in a different way
than the generic map: since it *is* actually wrapping and delegating to
another assembler to handle the child value, it has to make sure *that*
is invalidated; otherwise the fact we hand calls to the child assembler
right away before doing our 'flush' would be problematic.

Splitting the 'flush' in half would also work, of course.  At present
it seems like six of one and half a dozen of the other.  We can subject
this to microbenchmarking later if it seems relevant.
parent 22687e04
...@@ -386,8 +386,7 @@ func (ma *_Map_K_T__Assembler) AssembleDirectly(k string) (ipld.NodeAssembler, e ...@@ -386,8 +386,7 @@ func (ma *_Map_K_T__Assembler) AssembleDirectly(k string) (ipld.NodeAssembler, e
l := len(ma.w.t) l := len(ma.w.t)
ma.w.t = append(ma.w.t, _Map_K_T__entry{k: K{k}}) ma.w.t = append(ma.w.t, _Map_K_T__entry{k: K{k}})
ma.w.m[K{k}] = &ma.w.t[l].v ma.w.m[K{k}] = &ma.w.t[l].v
// Init the value assembler with a pointer to its target and to whole 'ma' and yield it. // Init the value assembler with a pointer to its target and yield it.
ma.va.ma = ma
ma.va.ca.w = &ma.w.t[l].v ma.va.ca.w = &ma.w.t[l].v
return &ma.va, nil return &ma.va, nil
} }
...@@ -412,8 +411,7 @@ func (ma *_Map_K_T__Assembler) AssembleValue() ipld.NodeAssembler { ...@@ -412,8 +411,7 @@ func (ma *_Map_K_T__Assembler) AssembleValue() ipld.NodeAssembler {
panic("misuse") panic("misuse")
} }
ma.state = maState_midValue ma.state = maState_midValue
// Init the value assembler with a pointer to its targetand to whole 'ma' and yield it. // Init the value assembler with a pointer to its target and yield it.
ma.va.ma = ma
ma.va.ca.w = &ma.w.t[len(ma.w.t)-1].v ma.va.ca.w = &ma.w.t[len(ma.w.t)-1].v
return &ma.va return &ma.va
} }
...@@ -500,9 +498,10 @@ func (mva *_Map_K_T__ValueAssembler) flush() { ...@@ -500,9 +498,10 @@ func (mva *_Map_K_T__ValueAssembler) flush() {
// A) the appropriate time to do that would've been *before* assignments; // A) the appropriate time to do that would've been *before* assignments;
// A.2) accordingly, we did so before exposing this value assembler at all; and // A.2) accordingly, we did so before exposing this value assembler at all; and
// B) if we were in a wrong state because someone holds onto this too long, // B) if we were in a wrong state because someone holds onto this too long,
// the invalidation we're about to do on `mva.ma` will make . // the invalidation we're about to do on `mva.ca.w` will make it impossible
// for them to make changes in appropriately.
mva.ma.state = maState_initial mva.ma.state = maState_initial
mva.ma = nil // invalidate self to prevent further incorrect use. mva.ca.w = nil
} }
func (_Map_K_T__ValueAssembler) Style() ipld.NodeStyle { panic("later") } func (_Map_K_T__ValueAssembler) Style() ipld.NodeStyle { panic("later") }
......
...@@ -174,6 +174,16 @@ func CheckMapStrInt(t *testing.T, ns ipld.NodeStyle) { ...@@ -174,6 +174,16 @@ func CheckMapStrInt(t *testing.T, ns ipld.NodeStyle) {
va.AssignInt(2) va.AssignInt(2)
t.Fatal("must not be reached") t.Fatal("must not be reached")
}() }()
// ... and neither of these should've had visible effects!
wish.Wish(t, ma.Finish(), wish.ShouldEqual, nil)
n := nb.Build()
wish.Wish(t, n.Length(), wish.ShouldEqual, 1)
v, err := n.LookupString("whee")
wish.Wish(t, err, wish.ShouldEqual, nil)
v2, err := v.AsInt()
wish.Wish(t, err, wish.ShouldEqual, nil)
wish.Wish(t, v2, wish.ShouldEqual, 1)
}) })
t.Run("builder reset works", func(t *testing.T) { t.Run("builder reset works", func(t *testing.T) {
// TODO // TODO
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment