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

mlange-42 / arche-serde / 7577714645

19 Jan 2024 12:28AM CUT coverage: 84.483% (+0.3%) from 84.141%
7577714645

push

github

web-flow
Fix for opaque Arche 0.10 component and resource IDs (#7)

* Fix for opaque Arche entities and component and resource IDs
* add more interesting package example

196 of 232 relevant lines covered (84.48%)

19.97 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) {
3✔
23
        builder := strings.Builder{}
3✔
24

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

65✔
97
                for i, id := range ids {
134✔
98
                        info, _ := ecs.ComponentInfo(world, id)
69✔
99

69✔
100
                        if info.IsRelation {
71✔
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)
69✔
110
                        value := reflect.NewAt(info.Type, comp).Interface()
69✔
111
                        jsonData, err := json.Marshal(value)
69✔
112
                        if err != nil {
69✔
113
                                return err
×
114
                        }
×
115
                        builder.WriteString(fmt.Sprintf("    \"%s\" : ", info.Type.String()))
69✔
116
                        builder.WriteString(string(jsonData))
69✔
117
                        if i < last {
73✔
118
                                builder.WriteString(",")
4✔
119
                        }
4✔
120
                        builder.WriteString("\n")
69✔
121
                }
122

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

65✔
129
                counter++
65✔
130
        }
131
        builder.WriteString("]")
3✔
132

3✔
133
        return nil
3✔
134
}
135

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

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

147
        last := len(resTypes) - 1
3✔
148
        counter := 0
3✔
149
        for id, tp := range resTypes {
5✔
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("}")
3✔
172

3✔
173
        return nil
3✔
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