persist is a Go library for immutable, persistent JSON-like data structures.
It provides compact values, scalar-keyed persistent maps, persistent vectors,
and mixed map/vector path updates.
Use it when you want cheap snapshots, undo/redo state, copy-on-write configuration or policy trees, request-local document edits, or concurrent reads with independently derived versions.
go get github.com/asciimoth/persistValue can hold:
- nil
- int64
- float64
- string
- bool
MapVector
Key can hold only scalar key types: nil, int64, float64, string, and bool.
Maps and vectors cannot be map keys.
Zero values are valid: Value{} is nil, Key{} is the nil key, Map{} is an
empty map, and Vector{} is an empty vector.
package main
import (
"fmt"
"github.com/asciimoth/persist"
)
func main() {
profile := persist.NewMap().
Assoc(persist.KString("name"), persist.String("Ada")).
Assoc(persist.KString("visits"), persist.Int(1))
root := persist.MapValue(persist.NewMap().
Assoc(persist.KString("profile"), persist.MapValue(profile)))
next, err := persist.SetIn(
root,
persist.Int(2),
persist.MapKey(persist.KString("profile")),
persist.MapKey(persist.KString("visits")),
)
if err != nil {
panic(err)
}
oldVisits, _ := persist.GetIn(root, persist.MapKey(persist.KString("profile")), persist.MapKey(persist.KString("visits")))
newVisits, _ := persist.GetIn(next, persist.MapKey(persist.KString("profile")), persist.MapKey(persist.KString("visits")))
oldN, _ := oldVisits.Int64()
newN, _ := newVisits.Int64()
fmt.Println(oldN, newN)
}Every update returns a new root and leaves older roots unchanged. Unchanged subtrees are shared internally.
Use persist.FromJSON to decode ordinary JSON into a Value, and use
Value.ToJSON, Map.ToJSON, or Vector.ToJSON to encode it again. Value,
Map, and Vector also implement the standard encoding/json marshal and
unmarshal interfaces.
root, err := persist.FromJSON([]byte(`{"items":[{"score":10}]}`))
if err != nil {
panic(err)
}
data, err := root.ToJSON()JSON objects decode as maps with string keys. Maps that use nil, integer,
float, or bool keys are valid in memory but cannot be encoded as JSON objects.
Integer-looking JSON numbers decode as Int when they fit in int64;
decimal/exponent numbers decode as Float.
Map.AssocandMap.Dissocreturn new maps.Vector.Set,Vector.Append, andVector.Popreturn new vectors.Map.AllandVector.Allreturn standard Go iterators over immediate entries.Map.WalkandVector.Walkreturn standard Go iterators over nested map/vector trees with paths expressed asStepvalues.GetInandSetInoperate on nested map/vector paths.FromJSONandToJSONconvert ordinary JSON documents to and fromValue.NewReadOnlyMapConfig,NewReadOnlyVectorConfig, andNewReadOnlyConfigexpose read-only views over string-keyed map/vector trees that implementgithub.com/asciimoth/configer/configer.Config.Value.Equal,Map.Equal, andVector.Equalperform deep semantic equality checks.Key.Equal,Step.Equal, andKind.Equalcompare keys, path steps, and kinds.Value.Sameis shallow: scalars compare by value, strings by content, and maps/vectors by identity. It is not deep equality.- Map iteration order is unspecified. Vector iteration is by ascending index.
- Float map keys normalize
-0to+0and all NaN payloads to a canonical NaN. Float leaf values preserve exact IEEE-754 bits. StringandKStringretain the supplied string backing storage without copying. UseStringCloneandKStringClonewhen long-lived values should avoid retaining a larger original buffer.
Files in this repository are distributed under the CC0 license.

To the extent possible under law,
ASCIIMoth
has waived all copyright and related or neighboring rights to
persist.