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

mlange-42 / arche-serde / 7487858638

11 Jan 2024 11:05AM CUT coverage: 83.468% (-0.3%) from 83.766%
7487858638

Pull #3

github

web-flow
Merge 7ca67c00c into 8937cb386
Pull Request #3: Serialize entity relations

207 of 248 relevant lines covered (83.47%)

28.39 hits per line

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

87.01
/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
func Serialize(world *ecs.World) ([]byte, error) {
3✔
16
        builder := strings.Builder{}
3✔
17

3✔
18
        builder.WriteString("{\n")
3✔
19

3✔
20
        if err := serializeWorld(world, &builder); err != nil {
3✔
21
                return nil, err
×
22
        }
×
23
        builder.WriteString(",\n")
3✔
24

3✔
25
        serializeTypes(world, &builder)
3✔
26
        builder.WriteString(",\n")
3✔
27

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

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

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

3✔
43
        return []byte(builder.String()), nil
3✔
44
}
45

46
func serializeWorld(world *ecs.World, builder *strings.Builder) error {
3✔
47
        entities := world.GetEntityData()
3✔
48

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

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

3✔
63
        types := map[ecs.ID]reflect.Type{}
3✔
64
        for i := 0; i < ecs.MaskTotalBits; i++ {
771✔
65
                if info, ok := ecs.ComponentInfo(world, ecs.ID(i)); ok {
773✔
66
                        types[ecs.ID(i)] = info.Type
5✔
67
                }
5✔
68
        }
69
        maxComp := len(types) - 1
3✔
70
        counter := 0
3✔
71
        for _, tp := range types {
8✔
72
                builder.WriteString(fmt.Sprintf("  \"%s\"", tp.String()))
5✔
73
                if counter < maxComp {
8✔
74
                        builder.WriteString(",")
3✔
75
                }
3✔
76
                builder.WriteString("\n")
5✔
77
                counter++
5✔
78
        }
79

80
        builder.WriteString("]")
3✔
81
}
82

83
func serializeEntities(world *ecs.World, builder *strings.Builder) error {
3✔
84

3✔
85
        builder.WriteString("\"Entities\" : [\n")
3✔
86

3✔
87
        query := world.Query(ecs.All())
3✔
88
        lastEntity := query.Count() - 1
3✔
89
        counter := 0
3✔
90
        for query.Next() {
8✔
91
                jsonData, err := json.Marshal(query.Entity())
5✔
92
                if err != nil {
5✔
93
                        return err
×
94
                }
×
95
                builder.WriteString(fmt.Sprintf("    %s", jsonData))
5✔
96
                if counter < lastEntity {
8✔
97
                        builder.WriteString(",")
3✔
98
                }
3✔
99
                builder.WriteString("\n")
5✔
100

5✔
101
                counter++
5✔
102
        }
103
        builder.WriteString("]")
3✔
104

3✔
105
        return nil
3✔
106
}
107

108
func serializeComponents(world *ecs.World, builder *strings.Builder) error {
3✔
109

3✔
110
        builder.WriteString("\"Components\" : [\n")
3✔
111

3✔
112
        query := world.Query(ecs.All())
3✔
113
        lastEntity := query.Count() - 1
3✔
114
        counter := 0
3✔
115
        for query.Next() {
8✔
116
                builder.WriteString("  {\n")
5✔
117

5✔
118
                ids := query.Ids()
5✔
119
                last := len(ids) - 1
5✔
120

5✔
121
                for i, id := range ids {
14✔
122
                        info, _ := ecs.ComponentInfo(world, id)
9✔
123

9✔
124
                        if info.IsRelation {
11✔
125
                                target := query.Relation(id)
2✔
126
                                builder.WriteString(fmt.Sprintf("    \"%s\" : {\"ID\": %d, \"Gen\": %d},\n", targetTag, target.ID(), target.Gen()))
2✔
127
                        }
2✔
128

129
                        comp := query.Get(id)
9✔
130
                        value := reflect.NewAt(info.Type, comp).Interface()
9✔
131
                        jsonData, err := json.Marshal(value)
9✔
132
                        if err != nil {
9✔
133
                                return err
×
134
                        }
×
135
                        builder.WriteString(fmt.Sprintf("    \"%s\" : ", info.Type.String()))
9✔
136
                        builder.WriteString(string(jsonData))
9✔
137
                        if i < last {
13✔
138
                                builder.WriteString(",")
4✔
139
                        }
4✔
140
                        builder.WriteString("\n")
9✔
141
                }
142

143
                builder.WriteString("  }")
5✔
144
                if counter < lastEntity {
8✔
145
                        builder.WriteString(",")
3✔
146
                }
3✔
147
                builder.WriteString("\n")
5✔
148

5✔
149
                counter++
5✔
150
        }
151
        builder.WriteString("]")
3✔
152

3✔
153
        return nil
3✔
154
}
155

156
func serializeResources(world *ecs.World, builder *strings.Builder) error {
3✔
157
        builder.WriteString("\"Resources\" : {\n")
3✔
158

3✔
159
        resTypes := map[ecs.ResID]reflect.Type{}
3✔
160
        for i := 0; i < ecs.MaskTotalBits; i++ {
771✔
161
                if tp, ok := ecs.ResourceType(world, ecs.ResID(i)); ok {
769✔
162
                        resTypes[ecs.ResID(i)] = tp
1✔
163
                }
1✔
164
        }
165

166
        last := len(resTypes) - 1
3✔
167
        counter := 0
3✔
168
        for id, tp := range resTypes {
4✔
169
                res := world.Resources().Get(id)
1✔
170
                rValue := reflect.ValueOf(res)
1✔
171
                ptr := rValue.UnsafePointer()
1✔
172

1✔
173
                value := reflect.NewAt(tp, ptr).Interface()
1✔
174
                jsonData, err := json.Marshal(value)
1✔
175
                if err != nil {
1✔
176
                        return err
×
177
                }
×
178

179
                builder.WriteString("    ")
1✔
180
                builder.WriteString(fmt.Sprintf("\"%s\" : ", tp.String()))
1✔
181
                builder.WriteString(string(jsonData))
1✔
182

1✔
183
                if counter < last {
1✔
184
                        builder.WriteString(",")
×
185
                }
×
186
                builder.WriteString("\n")
1✔
187
        }
188

189
        builder.WriteString("}")
3✔
190

3✔
191
        return nil
3✔
192
}
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