Cyclic graph structures serialization library written in go.
Sometimes you need to serialize a structure that has circular references. This library lets you transform your cyclic graph to a tree and then serialize to json.
package main
import (
"encoding/json"
"fmt"
"github.com/go-extras/tahwil"
)
type Person struct {
Name string
Parent *Person
Children []*Person
}
func main() {
parent := &Person{
Name: "Arthur",
Children: []*Person{
{
Name: "Ford",
},
{
Name: "Trillian",
},
},
}
parent.Children[0].Parent = parent
parent.Children[1].Parent = parent
v, err := tahwil.ToValue(parent)
if err != nil {
panic(err)
}
res, err := json.Marshal(v)
if err != nil {
panic(err)
}
fmt.Println(string(res))
}
The output will be one-line equivalent of the following JSON:
{
"refid": 1,
"kind": "ptr",
"value": {
"refid": 2,
"kind": "struct",
"value": {
"Children": {
"refid": 5,
"kind": "slice",
"value": [
{
"refid": 6,
"kind": "ptr",
"value": {
"refid": 7,
"kind": "struct",
"value": {
"Children": {
"refid": 10,
"kind": "slice",
"value": []
},
"Name": {
"refid": 8,
"kind": "string",
"value": "Ford"
},
"Parent": {
"refid": 9,
"kind": "ref",
"value": 1
}
}
}
},
{
"refid": 11,
"kind": "ptr",
"value": {
"refid": 12,
"kind": "struct",
"value": {
"Children": {
"refid": 15,
"kind": "slice",
"value": []
},
"Name": {
"refid": 13,
"kind": "string",
"value": "Trillian"
},
"Parent": {
"refid": 14,
"kind": "ref",
"value": 1
}
}
}
}
]
},
"Name": {
"refid": 3,
"kind": "string",
"value": "Arthur"
},
"Parent": {
"refid": 4,
"kind": "ptr",
"value": null
}
}
}
}
package main
import (
"encoding/json"
"fmt"
"github.com/go-extras/tahwil"
)
type Person struct {
Name string `json:"name"`
Parent *Person `json:"parent"`
Children []*Person `json:"children"`
}
func prepareData() []byte {
parent := &Person{
Name: "Arthur",
Children: []*Person{
{
Name: "Ford",
},
{
Name: "Trillian",
},
},
}
parent.Children[0].Parent = parent
parent.Children[1].Parent = parent
v, err := tahwil.ToValue(parent)
if err != nil {
panic(err)
}
res, err := json.Marshal(v)
if err != nil {
panic(err)
}
return res
}
func main() {
data := &tahwil.Value{}
res := prepareData()
err := json.Unmarshal(res, data)
if err != nil {
panic(err)
}
person := &Person{}
err = tahwil.FromValue(data, person)
if err != nil {
panic(err)
}
fmt.Printf(`Name: %s
Children:
- %s
-- parent name: %s
- %s
-- parent name: %s
`, person.Name,
person.Children[0].Name,
person.Children[0].Parent.Name,
person.Children[1].Name,
person.Children[1].Parent.Name)
}
This should output:
Name: Arthur
Children:
- Ford
-- parent name: Arthur
- Trillian
-- parent name: Arthur
As you can see, Arthur is displayed here 3 times - first as a main person, and then as a parent of the both children.
We support the following go built-in types (kinds):
- string
- bool
- int
- int8
- int16
- int32
- int64
- uint
- uint8
- uint16
- uint32
- uint64
- float32
- float64
- ptr
- struct
- map
- slice
In addition, tahwil
adds a ref
type, which is used to refer to the cyclic reference and thus avoid endless recursion.
Structs, slices, maps and pointers must pointer to one of the supported types.