Skip to content

Commit b5e6de6

Browse files
#1744 Meta collections refactor
1 parent 7ea3288 commit b5e6de6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+7979
-3749
lines changed

distr/flecs.c

Lines changed: 1667 additions & 1476 deletions
Large diffs are not rendered by default.

distr/flecs.h

Lines changed: 259 additions & 202 deletions
Large diffs are not rendered by default.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.bake_cache
2+
.DS_Store
3+
.vscode
4+
gcov
5+
bin
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef CUSTOM_SERIALIZER_H
2+
#define CUSTOM_SERIALIZER_H
3+
4+
/* This generated file contains includes for project dependencies */
5+
#include "custom_serializer/bake_config.h"
6+
7+
#ifdef __cplusplus
8+
extern "C" {
9+
#endif
10+
11+
#ifdef __cplusplus
12+
}
13+
#endif
14+
15+
#endif
16+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
)
3+
(.)
4+
.|.
5+
| |
6+
_.--| |--._
7+
.-'; ;`-'& ; `&.
8+
\ & ; & &_/
9+
|"""---...---"""|
10+
\ | | | | | | | /
11+
`---.|.|.|.---'
12+
13+
* This file is generated by bake.lang.c for your convenience. Headers of
14+
* dependencies will automatically show up in this file. Include bake_config.h
15+
* in your main project file. Do not edit! */
16+
17+
#ifndef CUSTOM_SERIALIZER_BAKE_CONFIG_H
18+
#define CUSTOM_SERIALIZER_BAKE_CONFIG_H
19+
20+
/* Headers of public dependencies */
21+
#include <flecs.h>
22+
23+
#endif
24+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"id": "custom_serializer",
3+
"type": "application",
4+
"value": {
5+
"use": [
6+
"flecs"
7+
]
8+
}
9+
}
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
#include <custom_serializer.h>
2+
#include <stdio.h>
3+
#include <inttypes.h>
4+
5+
// This example demonstrates how to create a serializer for a custom format.
6+
7+
static int indent = 0;
8+
9+
#define printIndented(...)\
10+
printf("\n%*s", indent * 2, ""); printf(__VA_ARGS__)
11+
12+
void serializeOps(ecs_world_t *world, ecs_meta_op_t *ops,
13+
int32_t op_count, const void *ptr);
14+
15+
// Serialize a pointer of a specified type.
16+
int serialize(ecs_world_t *world, ecs_entity_t type, const void *ptr) {
17+
// The TypeSerializer component contains a vector of instructions that tells
18+
// us how to serialize the type.
19+
const EcsTypeSerializer *s = ecs_get(world, type, EcsTypeSerializer);
20+
if (!s) {
21+
printf("type does not have reflection data\n");
22+
return -1;
23+
}
24+
25+
serializeOps(world, ecs_vec_first(&s->ops), ecs_vec_count(&s->ops), ptr);
26+
27+
return 0;
28+
}
29+
30+
// Serialize contents of struct or collection scope
31+
void serializeScope(ecs_world_t *world, ecs_meta_op_t *ops, const void *ptr) {
32+
// A scope starts with a Push and ends with a Pop, so trim the first and
33+
// last instruction before forwarding.
34+
serializeOps(world, ops + 1, ops->op_count - 2, ptr);
35+
}
36+
37+
// Serialize a struct scope
38+
void serializeStruct(ecs_world_t *world, ecs_meta_op_t *ops,
39+
const void *ptr)
40+
{
41+
printf("{");
42+
indent ++;
43+
44+
serializeScope(world, ops, ptr);
45+
46+
indent --;
47+
printIndented("}");
48+
}
49+
50+
// Serialize an array scope
51+
void serializeArray(ecs_world_t *world, ecs_meta_op_t *ops,
52+
int32_t elem_count, const void *ptr)
53+
{
54+
printf("[");
55+
56+
// Iterate elements of the array. Skip the first and last instruction
57+
// since they are PushStruct and Pop.
58+
for (int i = 0; i < elem_count; i ++) {
59+
if (i) {
60+
printf(", ");
61+
}
62+
63+
serializeScope(world, ops, ptr);
64+
65+
ptr = ECS_OFFSET(ptr, ops->elem_size);
66+
}
67+
68+
printf("]");
69+
}
70+
71+
// Serialize a vector scope
72+
void serializeVector(ecs_world_t *world, ecs_meta_op_t *ops,
73+
const void *ptr)
74+
{
75+
const ecs_vec_t *vec = ptr;
76+
serializeArray(world, ops, vec->count, vec->array);
77+
}
78+
79+
// Serialize enum
80+
void serializeEnum(ecs_meta_op_t *op, const void *ptr)
81+
{
82+
const int32_t *value = ptr; // Assume i32, but should use underlying type
83+
ecs_enum_constant_t *c = ecs_map_get_deref(op->is.constants,
84+
ecs_enum_constant_t, (ecs_map_key_t)*value);
85+
printf("%s", c->name);
86+
}
87+
88+
// Iterate over instruction array
89+
void serializeOps(ecs_world_t *world, ecs_meta_op_t *ops, int32_t op_count,
90+
const void *base)
91+
{
92+
for (int i = 0; i < op_count; i ++) {
93+
ecs_meta_op_t *op = &ops[i];
94+
95+
// Member name
96+
if (op->name) {
97+
if (i) {
98+
printf(",");
99+
}
100+
101+
printIndented("%s: ", op->name);
102+
}
103+
104+
// Get pointer for current field
105+
void *ptr = ECS_OFFSET(base, op->offset);
106+
107+
switch(op->kind) {
108+
// Instructions that forward to a type scope, like a (nested) struct or
109+
// collection
110+
case EcsOpPushStruct:
111+
serializeStruct(world, op, ptr);
112+
break;
113+
case EcsOpPushArray:
114+
serializeArray(world, op, ecs_meta_op_get_elem_count(ops, ptr), ptr);
115+
break;
116+
case EcsOpPushVector:
117+
serializeVector(world, op, ptr);
118+
break;
119+
120+
// Opaque types have in-memory representations that are opaque to
121+
// the reflection framework and cannot be serialized by just taking
122+
// a pointer + an offset. See src/addons/script/serialize.c for an
123+
// example of how to handle opaque types.
124+
case EcsOpOpaqueStruct:
125+
case EcsOpOpaqueArray:
126+
case EcsOpOpaqueVector:
127+
case EcsOpOpaqueValue:
128+
break;
129+
130+
// Forward to type. Used for members of array/vector types.
131+
case EcsOpForward:
132+
serialize(world, op->type, ptr);
133+
break;
134+
135+
// Serialize single values
136+
case EcsOpEnum:
137+
serializeEnum(op, ptr);
138+
break;
139+
case EcsOpBitmask:
140+
// Bitmask serialization requires iterating all the bits in a value
141+
// and looking up the corresponding constant. For an example, see
142+
// src/addons/script/serialize.c.
143+
break;
144+
case EcsOpBool:
145+
printf("%s", (*(const bool*)ptr) ? "true" : "false");
146+
break;
147+
case EcsOpChar:
148+
printf("'%c'", *(const char*)ptr);
149+
break;
150+
case EcsOpByte:
151+
case EcsOpU8:
152+
printf("%" PRIu8, *(const uint8_t*)ptr);
153+
break;
154+
case EcsOpU16:
155+
printf("%" PRIu16, *(const uint16_t*)ptr);
156+
break;
157+
case EcsOpU32:
158+
printf("%" PRIu32, *(const uint32_t*)ptr);
159+
break;
160+
case EcsOpU64:
161+
printf("%" PRIu64, *(const uint64_t*)ptr);
162+
break;
163+
case EcsOpI8:
164+
printf("%" PRIi8, *(const int8_t*)ptr);
165+
break;
166+
case EcsOpI16:
167+
printf("%" PRIi16, *(const int16_t*)ptr);
168+
break;
169+
case EcsOpI32:
170+
printf("%" PRIi32, *(const int32_t*)ptr);
171+
break;
172+
case EcsOpI64:
173+
printf("%" PRIi64, *(const int64_t*)ptr);
174+
break;
175+
case EcsOpF32:
176+
printf("%.2f", (double)*(const float*)ptr);
177+
break;
178+
case EcsOpF64:
179+
printf("%.2f", *(const double*)ptr);
180+
break;
181+
case EcsOpUPtr:
182+
printf("%" PRIuPTR, *(const uintptr_t*)ptr);
183+
break;
184+
case EcsOpIPtr:
185+
printf("%" PRIiPTR, *(const intptr_t*)ptr);
186+
break;
187+
case EcsOpString:
188+
printf("\"%s\"", *(const char**)ptr);
189+
break;
190+
case EcsOpEntity: {
191+
char *name = ecs_get_path(world, *(ecs_entity_t*)ptr);
192+
printf("%s\n", name);
193+
ecs_os_free(name);
194+
break;
195+
}
196+
case EcsOpId: {
197+
char *name = ecs_id_str(world, *(ecs_id_t*)ptr);
198+
printf("%s\n", name);
199+
ecs_os_free(name);
200+
break;
201+
}
202+
case EcsOpPop:
203+
case EcsOpScope:
204+
case EcsOpPrimitive:
205+
// Not serializable
206+
break;
207+
}
208+
209+
i += op->op_count - 1; // Skip over already processed instructions
210+
}
211+
}
212+
213+
// Some types to test the serializer with
214+
215+
typedef struct {
216+
uint8_t red;
217+
uint8_t green;
218+
uint8_t blue;
219+
} Rgb;
220+
221+
typedef enum {
222+
Solid, Dashed
223+
} StrokeKind;
224+
225+
typedef struct {
226+
float x, y;
227+
} Point;
228+
229+
typedef struct {
230+
Rgb color;
231+
Rgb stroke_color;
232+
StrokeKind stroke_kind;
233+
ecs_vec_t points;
234+
} Polygon;
235+
236+
int main(int argc, char *argv[]) {
237+
ecs_world_t *world = ecs_init_w_args(argc, argv);
238+
239+
// We need to register reflection data for our types before we can use them
240+
// with the serializer code. We'll do it manually here, but for an easier
241+
// way to insert reflection data see the auto_* examples.
242+
243+
ECS_COMPONENT(world, Rgb);
244+
ECS_COMPONENT(world, StrokeKind);
245+
ECS_COMPONENT(world, Point);
246+
ECS_COMPONENT(world, Polygon);
247+
248+
ecs_struct(world, {
249+
.entity = ecs_id(Rgb),
250+
.members = {
251+
{ .name = "r", .type = ecs_id(ecs_u8_t) },
252+
{ .name = "g", .type = ecs_id(ecs_u8_t) },
253+
{ .name = "b", .type = ecs_id(ecs_u8_t) },
254+
}
255+
});
256+
257+
ecs_enum(world, {
258+
.entity = ecs_id(StrokeKind),
259+
.constants = {
260+
{ .name = "Solid", .value = Solid },
261+
{ .name = "Dashed", .value = Dashed },
262+
}
263+
});
264+
265+
ecs_struct(world, {
266+
.entity = ecs_id(Point),
267+
.members = {
268+
{ .name = "x", .type = ecs_id(ecs_f32_t) },
269+
{ .name = "y", .type = ecs_id(ecs_f32_t) }
270+
}
271+
});
272+
273+
ecs_entity_t PointVector = ecs_vector(world, { .type = ecs_id(Point) });
274+
275+
ecs_struct(world, {
276+
.entity = ecs_id(Polygon),
277+
.members = {
278+
{ .name = "color", .type = ecs_id(Rgb) },
279+
{ .name = "stroke_color", .type = ecs_id(Rgb) },
280+
{ .name = "stroke_kind", .type = ecs_id(StrokeKind) },
281+
{ .name = "points", .type = PointVector }
282+
}
283+
});
284+
285+
// Create the value
286+
ecs_vec_t points;
287+
ecs_vec_init_t(NULL, &points, Point, 0);
288+
*ecs_vec_append_t(NULL, &points, Point) = (Point){0, 0};
289+
*ecs_vec_append_t(NULL, &points, Point) = (Point){1, 1};
290+
*ecs_vec_append_t(NULL, &points, Point) = (Point){-1, 1};
291+
292+
Polygon p = {
293+
.color = {0, 0, 255},
294+
.stroke_color = {255, 0, 0},
295+
.stroke_kind = Dashed,
296+
.points = points
297+
};
298+
299+
// Serialize value
300+
serialize(world, ecs_id(Polygon), &p);
301+
printf("\n");
302+
303+
// Free memory
304+
ecs_vec_fini_t(NULL, &points, Point);
305+
306+
ecs_fini(world);
307+
308+
// Output:
309+
// {
310+
// color: {
311+
// r: 0,
312+
// g: 0,
313+
// b: 255
314+
// },
315+
// stroke_color: {
316+
// r: 255,
317+
// g: 0,
318+
// b: 0
319+
// },
320+
// stroke_kind: Dashed,
321+
// points: [{
322+
// x: 0.00,
323+
// y: 0.00
324+
// }, {
325+
// x: 1.00,
326+
// y: 1.00
327+
// }, {
328+
// x: -1.00,
329+
// y: 1.00
330+
// }]
331+
// }
332+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.bake_cache
2+
.DS_Store
3+
.vscode
4+
gcov
5+
bin

0 commit comments

Comments
 (0)