• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / arche-serde / 8032069594

24 Feb 2024 05:19PM CUT coverage: 93.562% (-0.4%) from 93.939%
8032069594

push

github

web-flow
Fix panic on deserializing entities without components (#12)

218 of 233 relevant lines covered (93.56%)

25.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.31
/serialize.go
1
package archeserde
2

3
import (
4
        "encoding/json"
5
        "fmt"
6
        "reflect"
7
        "strings"
8

9
        "github.com/mlange-42/arche/ecs"
10
)
11

12
const targetTag = "arche.relation.Target"
13

14
// Serialize an Arche [ecs.World] to JSON.
15
//
16
// Serializes the following:
17
//   - Entities and the entity pool
18
//   - All components of all entities
19
//   - All resources
20
//
21
// All components and resources must be "JSON-able" with [encoding/json].
22
func Serialize(world *ecs.World) ([]byte, error) {
4✔
23
        builder := strings.Builder{}
4✔
24

4✔
25
        builder.WriteString("{\n")
4✔
26

4✔
27
        if err := serializeWorld(world, &builder); err != nil {
4✔
28
                return nil, err
×
29
        }
×
30
        builder.WriteString(",\n")
4✔
31

4✔
32
        serializeTypes(world, &builder)
4✔
33
        builder.WriteString(",\n")
4✔
34

4✔
35
        if err := serializeComponents(world, &builder); err != nil {
4✔
36
                return nil, err
×
37
        }
×
38
        builder.WriteString(",\n")
4✔
39

4✔
40
        if err := serializeResources(world, &builder); err != nil {
4✔
41
                return nil, err
×
42
        }
×
43
        builder.WriteString("}\n")
4✔
44

4✔
45
        return []byte(builder.String()), nil
4✔
46
}
47

48
func serializeWorld(world *ecs.World, builder *strings.Builder) error {
4✔
49
        entities := world.DumpEntities()
4✔
50

4✔
51
        jsonData, err := json.Marshal(entities)
4✔
52
        if err != nil {
4✔
53
                return err
×
54
        }
×
55
        builder.WriteString(fmt.Sprintf("\"World\" : %s", string(jsonData)))
4✔
56
        return nil
4✔
57
}
58

59
func serializeTypes(world *ecs.World, builder *strings.Builder) {
4✔
60
        builder.WriteString("\"Types\" : [\n")
4✔
61

4✔
62
        types := map[ecs.ID]reflect.Type{}
4✔
63

4✔
64
        allComps := ecs.ComponentIDs(world)
4✔
65
        for _, id := range allComps {
12✔
66
                if info, ok := ecs.ComponentInfo(world, id); ok {
16✔
67
                        types[id] = info.Type
8✔
68
                }
8✔
69
        }
70
        maxComp := len(types) - 1
4✔
71
        counter := 0
4✔
72
        for _, tp := range types {
12✔
73
                builder.WriteString(fmt.Sprintf("  \"%s\"", tp.String()))
8✔
74
                if counter < maxComp {
12✔
75
                        builder.WriteString(",")
4✔
76
                }
4✔
77
                builder.WriteString("\n")
8✔
78
                counter++
8✔
79
        }
80

81
        builder.WriteString("]")
4✔
82
}
83

84
func serializeComponents(world *ecs.World, builder *strings.Builder) error {
4✔
85

4✔
86
        builder.WriteString("\"Components\" : [\n")
4✔
87

4✔
88
        query := world.Query(ecs.All())
4✔
89
        lastEntity := query.Count() - 1
4✔
90
        counter := 0
4✔
91
        for query.Next() {
72✔
92
                builder.WriteString("  {\n")
68✔
93

68✔
94
                ids := query.Ids()
68✔
95
                last := len(ids) - 1
68✔
96

68✔
97
                for i, id := range ids {
141✔
98
                        info, _ := ecs.ComponentInfo(world, id)
73✔
99

73✔
100
                        if info.IsRelation {
75✔
101
                                target := query.Relation(id)
2✔
102
                                eJSON, err := target.MarshalJSON()
2✔
103
                                if err != nil {
2✔
104
                                        return err
×
105
                                }
×
106
                                builder.WriteString(fmt.Sprintf("    \"%s\" : %s,\n", targetTag, eJSON))
2✔
107
                        }
108

109
                        comp := query.Get(id)
73✔
110
                        value := reflect.NewAt(info.Type, comp).Interface()
73✔
111
                        jsonData, err := json.Marshal(value)
73✔
112
                        if err != nil {
73✔
113
                                return err
×
114
                        }
×
115
                        builder.WriteString(fmt.Sprintf("    \"%s\" : ", info.Type.String()))
73✔
116
                        builder.WriteString(string(jsonData))
73✔
117
                        if i < last {
78✔
118
                                builder.WriteString(",")
5✔
119
                        }
5✔
120
                        builder.WriteString("\n")
73✔
121
                }
122

123
                builder.WriteString("  }")
68✔
124
                if counter < lastEntity {
132✔
125
                        builder.WriteString(",")
64✔
126
                }
64✔
127
                builder.WriteString("\n")
68✔
128

68✔
129
                counter++
68✔
130
        }
131
        builder.WriteString("]")
4✔
132

4✔
133
        return nil
4✔
134
}
135

136
func serializeResources(world *ecs.World, builder *strings.Builder) error {
4✔
137
        builder.WriteString("\"Resources\" : {\n")
4✔
138

4✔
139
        resTypes := map[ecs.ResID]reflect.Type{}
4✔
140
        allRes := ecs.ResourceIDs(world)
4✔
141
        for _, id := range allRes {
6✔
142
                if tp, ok := ecs.ResourceType(world, id); ok {
4✔
143
                        resTypes[id] = tp
2✔
144
                }
2✔
145
        }
146

147
        last := len(resTypes) - 1
4✔
148
        counter := 0
4✔
149
        for id, tp := range resTypes {
6✔
150
                res := world.Resources().Get(id)
2✔
151
                rValue := reflect.ValueOf(res)
2✔
152
                ptr := rValue.UnsafePointer()
2✔
153

2✔
154
                value := reflect.NewAt(tp, ptr).Interface()
2✔
155
                jsonData, err := json.Marshal(value)
2✔
156
                if err != nil {
2✔
157
                        return err
×
158
                }
×
159

160
                builder.WriteString("    ")
2✔
161
                builder.WriteString(fmt.Sprintf("\"%s\" : ", tp.String()))
2✔
162
                builder.WriteString(string(jsonData))
2✔
163

2✔
164
                if counter < last {
3✔
165
                        builder.WriteString(",")
1✔
166
                }
1✔
167
                builder.WriteString("\n")
2✔
168
                counter++
2✔
169
        }
170

171
        builder.WriteString("}")
4✔
172

4✔
173
        return nil
4✔
174
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc