finish first pass sketching out basic base-layer-defined codebase type info & serialization/deserialization path with basic pointer cases

This commit is contained in:
Ryan Fleury
2024-09-18 14:52:39 -07:00
parent 9ae3b2eb92
commit 7e5759ed03
4 changed files with 305 additions and 124 deletions
+226 -69
View File
@@ -8,7 +8,7 @@ internal Member *
member_from_name(Type *type, String8 name)
{
Member *member = &member_nil;
if(type->members != 0)
if(type->members != 0 && name.size != 0)
{
for(U64 idx = 0; idx < type->count; idx += 1)
{
@@ -26,7 +26,7 @@ member_from_name(Type *type, String8 name)
//~ rjf: Type Info * Instance Operations
internal String8
serialized_from_typed_data(Arena *arena, Type *type, void *ptr, TypeSerializeParams *params)
serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
{
Temp scratch = scratch_begin(&arena, 1);
String8List strings = {0};
@@ -37,29 +37,30 @@ serialized_from_typed_data(Arena *arena, Type *type, void *ptr, TypeSerializePar
{
Task *next;
Type *type;
void *ptr;
U64 count;
U8 *src;
Type *containing_type;
void *containing_ptr;
U8 *containing_ptr;
B32 is_post_header;
};
Task start_task = {0, type, ptr, 1};
Task start_task = {0, type, 1, data.str};
Task *first_task = &start_task;
Task *last_task = first_task;
for(Task *t = first_task; t != 0; t = t->next)
{
switch(t->type->kind)
{
//- rjf: leaf serialiation -> just write the data directly
//- rjf: leaf -> just copy the data directly
default:
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
{
str8_serial_push_string(scratch.arena, &strings, str8((U8 *)t->ptr, type_leaves[t->type->kind].size*t->count));
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
}break;
//- rjf: pointers -> try to interpret/understand pointer & write, otherwise skip
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
case TypeKind_Ptr:
{
// rjf: gather info about pointer references of this type
// rjf: unpack info about this pointer
TypeSerializePtrRefInfo *ptr_ref_info = 0;
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
{
@@ -70,60 +71,57 @@ serialized_from_typed_data(Arena *arena, Type *type, void *ptr, TypeSerializePar
}
}
// rjf: read ptr value
void *ptr_value = 0;
MemoryCopy(&ptr_value, t->ptr, sizeof(ptr_value));
// rjf: indexification -> subtract base, divide direct size, write index
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
{
U64 ptr_offsetified = (U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base;
U64 ptr_indexified = ptr_offsetified / t->type->direct->size;
str8_serial_push_struct(scratch.arena, &strings, &ptr_indexified);
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size);
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
}
// rjf: explicit identification -> descend to ID member at destination, write that
else if(ptr_ref_info != 0 && ptr_ref_info->id_member.size != 0)
// rjf: offsetification -> subtract base, write offsets
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
{
Member *member = member_from_name(t->type->direct, ptr_ref_info->id_member);
if(member != &member_nil)
{
Task *task = push_array(scratch.arena, Task, 1);
task->type = member->type;
task->ptr = ((U8 *)ptr_value) + member->value;
task->count = 1;
task->containing_type = t->type->direct;
task->containing_ptr = ptr_value;
SLLQueuePush(first_task, last_task, task);
}
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base);
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
}
// rjf: count-delimited pointers -> read count from member in containing type,
// descend & write destination that way
else if(t->type->count_delimiter_name.size != 0 && t->containing_type != 0)
{
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
if(count_member != &member_nil)
{
U64 count = 0;
MemoryCopy(&count, (U8 *)t->containing_ptr + count_member->value, count_member->type->size);
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->ptr = ptr_value;
task->count = count;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}
}
// rjf: any other nonzero pointer -> descend to pointer destination. trust usage code
else if(ptr_value != 0)
// rjf: size-by-member (pre-header): still potentially dependent on other members which
// delimit our size, so push a new post-header task for pointer.
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
{
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->ptr = ptr_value;
task->count = 1;
task->type = t->type;
task->count = t->count;
task->src = t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
task->is_post_header = 1;
SLLQueuePush(first_task, last_task, task);
}
// rjf: size-by-member (post-header): all flat parts of containing struct have been
// iterated, so now we can read the size, & descend to new task to read pointer
// destination contents
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
{
// rjf: determine count of this pointer
U64 count = 0;
{
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
}
// rjf: push task
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->count = count;
task->src = *(void **)t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}
}break;
@@ -132,9 +130,175 @@ serialized_from_typed_data(Arena *arena, Type *type, void *ptr, TypeSerializePar
case TypeKind_Array:
{
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->ptr = t->ptr;
task->count = t->type->count;
task->type = t->type->direct;
task->count = t->type->count;
task->src = t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}break;
//- rjf: struct -> descend to members
case TypeKind_Struct:
{
U64 off = 0;
for(U64 idx = 0; idx < t->count; idx += 1)
{
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
{
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
{
continue;
}
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->members[member_idx].type;
task->count = 1;
task->src = t->src + t->type->members[member_idx].value;
task->containing_type = t->type;
task->containing_ptr = t->src;
SLLQueuePush(first_task, last_task, task);
}
}
}break;
//- rjf: enum -> descend to basic type interpretation
case TypeKind_Enum:
{
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->count = t->count;
task->src = t->src;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}break;
}
}
}
String8 result = str8_serial_end(arena, &strings);
scratch_end(scratch);
return result;
}
internal String8
deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
{
String8 result = {0};
result.size = type->size;
result.str = push_array(arena, U8, result.size);
{
Temp scratch = scratch_begin(&arena, 1);
typedef struct Task Task;
struct Task
{
Task *next;
Type *type;
U64 count;
U8 *dst;
Type *containing_type;
U8 *containing_ptr;
B32 is_post_header;
};
U64 read_off = 0;
Task start_task = {0, type, 1, result.str};
Task *first_task = &start_task;
Task *last_task = first_task;
for(Task *t = first_task; t != 0; t = t->next)
{
U8 *t_src = data.str + read_off;
switch(t->type->kind)
{
//- rjf: leaf -> copy the data directly
default:
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
{
MemoryCopy(t->dst, t_src, t->type->size*t->count);
read_off += t->type->size*t->count;
}break;
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
case TypeKind_Ptr:
{
// rjf: unpack info about this pointer
TypeSerializePtrRefInfo *ptr_ref_info = 0;
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
{
if(params->ptr_ref_infos[idx].type == t->type->direct)
{
ptr_ref_info = &params->ptr_ref_infos[idx];
break;
}
}
// rjf: indexification -> add base, multiply direct size
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
{
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size;
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
read_off += sizeof(ptr_value);
}
// rjf: offsetification -> subtract base, write offsets
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
{
U64 ptr_value = 0;
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base;
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
read_off += sizeof(ptr_value);
}
// rjf: size-by-member (pre-header): still potentially dependent on other members which
// delimit our size, so push a new post-header task for pointer.
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
{
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type;
task->count = t->count;
task->dst = t->dst;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
task->is_post_header = 1;
SLLQueuePush(first_task, last_task, task);
}
// rjf: size-by-member (post-header): all flat parts of containing struct have been
// iterated, so now we can read the size, & descend to new task to read pointer
// destination contents
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
{
// rjf: determine count of this pointer
U64 count = 0;
{
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
}
// rjf: allocate buffer for pointer destination; write address into pointer value slot
U64 ptr_dest_buffer_size = count*t->type->direct->size;
U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size);
MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer));
// rjf: push task
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->count = count;
task->dst = ptr_dest_buffer;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}
}break;
//- rjf: arrays -> descend to underlying type, + count
case TypeKind_Array:
{
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->count = t->type->count;
task->dst = t->dst;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
@@ -153,10 +317,10 @@ serialized_from_typed_data(Arena *arena, Type *type, void *ptr, TypeSerializePar
}
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->members[member_idx].type;
task->ptr = (U8 *)t->ptr + t->type->size*idx + t->type->members[member_idx].value;
task->count = 1;
task->dst = t->dst + t->type->members[member_idx].value;
task->containing_type = t->type;
task->containing_ptr = t->ptr;
task->containing_ptr = t->dst;
SLLQueuePush(first_task, last_task, task);
}
}
@@ -166,23 +330,16 @@ serialized_from_typed_data(Arena *arena, Type *type, void *ptr, TypeSerializePar
case TypeKind_Enum:
{
Task *task = push_array(scratch.arena, Task, 1);
task->type = t->type->direct;
task->ptr = t->ptr;
task->count = t->count;
task->type = t->type->direct;
task->count = t->count;
task->dst = t->dst;
task->containing_type = t->containing_type;
task->containing_ptr = t->containing_ptr;
SLLQueuePush(first_task, last_task, task);
}break;
}
}
scratch_end(scratch);
}
String8 result = str8_serial_end(scratch.arena, &strings);
scratch_end(scratch);
return result;
}
internal void *
data_from_typed_serialized(Arena *arena, Type *type, String8 string, TypeSerializeParams *params)
{
}