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

mlange-42 / arche-serde / 7613049089

22 Jan 2024 02:56PM CUT coverage: 93.939%. Remained the same
7613049089

Pull #11

github

web-flow
Merge 393180d6e into 4bea2d3c8
Pull Request #11: Add test for components with generic type argument

217 of 231 relevant lines covered (93.94%)

25.84 hits per line

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

100.0
/deserialize.go
1
package archeserde
2

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

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

11
// Deserialize an Arche [ecs.World] from JSON.
12
//
13
// The world must be prepared the following way:
14
//   - The world must not contain any alive or dead entities (i.e. a new or [ecs.World.Reset] world)
15
//   - All required component types must be registered using [ecs.ComponentID]
16
//   - All required resources must be added as dummies using [ecs.AddResource]
17
//
18
// # Query iteration order
19
//
20
// After deserialization, it is not guaranteed that entity iteration order in queries is the same as before.
21
// More precisely, it should at first be the same as before, but will likely deviate over time from what would
22
// happen when continuing the original, serialized run. Multiple worlds deserialized from the same source should,
23
// however, behave exactly the same.
24
func Deserialize(jsonData []byte, world *ecs.World) error {
15✔
25
        deserial := deserializer{}
15✔
26
        if err := json.Unmarshal(jsonData, &deserial); err != nil {
17✔
27
                return err
2✔
28
        }
2✔
29

30
        world.LoadEntities(&deserial.World)
13✔
31

13✔
32
        if err := deserializeComponents(world, &deserial); err != nil {
18✔
33
                return err
5✔
34
        }
5✔
35
        if err := deserializeResources(world, &deserial); err != nil {
11✔
36
                return err
3✔
37
        }
3✔
38

39
        return nil
5✔
40
}
41

42
func deserializeComponents(world *ecs.World, deserial *deserializer) error {
13✔
43
        infos := map[ecs.ID]ecs.CompInfo{}
13✔
44
        ids := map[string]ecs.ID{}
13✔
45
        allComps := ecs.ComponentIDs(world)
13✔
46
        for _, id := range allComps {
56✔
47
                if info, ok := ecs.ComponentInfo(world, id); ok {
86✔
48
                        infos[id] = info
43✔
49
                        ids[info.Type.String()] = id
43✔
50
                }
43✔
51
        }
52

53
        for _, tp := range deserial.Types {
42✔
54
                if _, ok := ids[tp]; !ok {
30✔
55
                        return fmt.Errorf("component type is not registered: %s", tp)
1✔
56
                }
1✔
57
        }
58

59
        if len(deserial.Components) != len(deserial.World.Alive) {
13✔
60
                return fmt.Errorf("found components for %d entities, but world has %d alive entities", len(deserial.Components), len(deserial.World.Alive))
1✔
61
        }
1✔
62

63
        for i, comps := range deserial.Components {
89✔
64
                entity := deserial.World.Entities[deserial.World.Alive[i]]
78✔
65

78✔
66
                mp := map[string]entry{}
78✔
67

78✔
68
                if err := json.Unmarshal(comps.Bytes, &mp); err != nil {
79✔
69
                        return err
1✔
70
                }
1✔
71

72
                target := ecs.Entity{}
77✔
73
                var targetComp ecs.ID
77✔
74
                components := []ecs.Component{}
77✔
75
                for tpName, value := range mp {
168✔
76
                        if tpName == targetTag {
94✔
77
                                if err := json.Unmarshal(value.Bytes, &target); err != nil {
4✔
78
                                        return err
1✔
79
                                }
1✔
80
                                continue
2✔
81
                        }
82

83
                        id := ids[tpName]
88✔
84
                        info := infos[id]
88✔
85

88✔
86
                        if info.IsRelation {
90✔
87
                                targetComp = id
2✔
88
                        }
2✔
89

90
                        component := reflect.New(info.Type).Interface()
88✔
91
                        if err := json.Unmarshal(value.Bytes, &component); err != nil {
89✔
92
                                return err
1✔
93
                        }
1✔
94
                        components = append(components, ecs.Component{
87✔
95
                                ID:   id,
87✔
96
                                Comp: component,
87✔
97
                        })
87✔
98
                }
99
                builder := ecs.NewBuilderWith(world, components...)
75✔
100
                if target.IsZero() {
149✔
101
                        builder.Add(entity)
74✔
102
                } else {
75✔
103
                        builder = builder.WithRelation(targetComp)
1✔
104
                        builder.Add(entity, target)
1✔
105
                }
1✔
106
        }
107
        return nil
8✔
108
}
109

110
func deserializeResources(world *ecs.World, deserial *deserializer) error {
8✔
111
        resTypes := map[ecs.ResID]reflect.Type{}
8✔
112
        resIds := map[string]ecs.ResID{}
8✔
113
        allRes := ecs.ResourceIDs(world)
8✔
114
        for _, id := range allRes {
13✔
115
                if tp, ok := ecs.ResourceType(world, id); ok {
10✔
116
                        resTypes[id] = tp
5✔
117
                        resIds[tp.String()] = id
5✔
118
                }
5✔
119
        }
120

121
        for tpName, res := range deserial.Resources {
14✔
122
                resID, ok := resIds[tpName]
6✔
123
                if !ok {
7✔
124
                        return fmt.Errorf("resource type is not registered: %s", tpName)
1✔
125
                }
1✔
126
                tp := resTypes[resID]
5✔
127

5✔
128
                resLoc := world.Resources().Get(resID)
5✔
129
                if resLoc == nil {
6✔
130
                        return fmt.Errorf("resource type registered but nil: %s", tpName)
1✔
131
                }
1✔
132

133
                ptr := reflect.ValueOf(resLoc).UnsafePointer()
4✔
134
                value := reflect.NewAt(tp, ptr).Interface()
4✔
135

4✔
136
                if err := json.Unmarshal(res.Bytes, &value); err != nil {
5✔
137
                        return err
1✔
138
                }
1✔
139
        }
140
        return nil
5✔
141
}
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