2025-08-16 16:03:55 +01:00
|
|
|
#include "type.h"
|
|
|
|
|
|
|
|
|
|
#include "class.h"
|
|
|
|
|
#include "object.h"
|
|
|
|
|
|
2026-05-02 21:01:17 +01:00
|
|
|
#include <fx/bst.h>
|
|
|
|
|
#include <fx/endian.h>
|
|
|
|
|
#include <fx/object.h>
|
|
|
|
|
#include <fx/type.h>
|
2025-08-16 16:03:55 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2026-03-16 15:10:49 +00:00
|
|
|
static struct fx_bst type_list = FX_BST_INIT;
|
2026-03-16 10:35:43 +00:00
|
|
|
static union fx_type zero_id = {0};
|
2025-08-16 16:03:55 +01:00
|
|
|
|
|
|
|
|
struct type_init_ctx {
|
|
|
|
|
size_t ctx_class_offset;
|
|
|
|
|
size_t ctx_instance_offset;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline int registration_compare(
|
2026-05-02 21:01:17 +01:00
|
|
|
const struct fx_type_registration *a,
|
|
|
|
|
const struct fx_type_registration *b)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
return fx_type_id_compare(&a->r_info->t_id, &b->r_info->t_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int component_compare(
|
2026-05-02 21:01:17 +01:00
|
|
|
const struct fx_type_component *a,
|
|
|
|
|
const struct fx_type_component *b)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-05-02 21:01:17 +01:00
|
|
|
return fx_type_id_compare(
|
|
|
|
|
&a->c_type->r_info->t_id,
|
|
|
|
|
&b->c_type->r_info->t_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 15:10:49 +00:00
|
|
|
FX_BST_DEFINE_INSERT(
|
2026-05-02 21:01:17 +01:00
|
|
|
struct fx_type_registration,
|
|
|
|
|
r_node,
|
|
|
|
|
r_info->r_id,
|
|
|
|
|
put_type,
|
2025-08-16 16:03:55 +01:00
|
|
|
registration_compare)
|
2026-03-16 15:10:49 +00:00
|
|
|
FX_BST_DEFINE_INSERT(
|
2026-05-02 21:01:17 +01:00
|
|
|
struct fx_type_component,
|
|
|
|
|
c_node,
|
|
|
|
|
&c_type->r_info->t_id,
|
|
|
|
|
put_type_component,
|
|
|
|
|
component_compare)
|
2025-08-16 16:03:55 +01:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static struct fx_type_registration *get_type(
|
2026-05-02 21:01:17 +01:00
|
|
|
const fx_bst *tree,
|
|
|
|
|
const union fx_type *key)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_bst_node *cur = tree->bst_root;
|
2025-08-16 16:03:55 +01:00
|
|
|
while (cur) {
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_registration *cur_node
|
|
|
|
|
= fx_unbox(struct fx_type_registration, cur, r_node);
|
|
|
|
|
int cmp = fx_type_id_compare(key, &cur_node->r_info->t_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
|
|
|
|
|
if (cmp > 0) {
|
2026-03-16 10:35:43 +00:00
|
|
|
cur = fx_bst_right(cur);
|
2025-08-16 16:03:55 +01:00
|
|
|
} else if (cmp < 0) {
|
2026-03-16 10:35:43 +00:00
|
|
|
cur = fx_bst_left(cur);
|
2025-08-16 16:03:55 +01:00
|
|
|
} else {
|
|
|
|
|
return cur_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_component *fx_type_get_component(
|
2026-05-02 21:01:17 +01:00
|
|
|
const fx_bst *tree,
|
|
|
|
|
const union fx_type *key)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_bst_node *cur = tree->bst_root;
|
2025-08-16 16:03:55 +01:00
|
|
|
while (cur) {
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_component *cur_node
|
|
|
|
|
= fx_unbox(struct fx_type_component, cur, c_node);
|
2026-05-02 21:01:17 +01:00
|
|
|
int cmp = fx_type_id_compare(
|
|
|
|
|
key,
|
|
|
|
|
&cur_node->c_type->r_info->t_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
|
|
|
|
|
if (cmp > 0) {
|
2026-03-16 10:35:43 +00:00
|
|
|
cur = fx_bst_right(cur);
|
2025-08-16 16:03:55 +01:00
|
|
|
} else if (cmp < 0) {
|
2026-03-16 10:35:43 +00:00
|
|
|
cur = fx_bst_left(cur);
|
2025-08-16 16:03:55 +01:00
|
|
|
} else {
|
|
|
|
|
return cur_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static struct fx_type_component *create_type_component(
|
|
|
|
|
const struct fx_type_registration *type_reg)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_component *c = malloc(sizeof *c);
|
2025-08-16 16:03:55 +01:00
|
|
|
if (!c) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(c, 0x0, sizeof *c);
|
|
|
|
|
|
|
|
|
|
c->c_type = type_reg;
|
|
|
|
|
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_type_id_init(
|
2026-05-02 21:01:17 +01:00
|
|
|
union fx_type *out,
|
|
|
|
|
uint32_t a,
|
|
|
|
|
uint16_t b,
|
|
|
|
|
uint16_t c,
|
|
|
|
|
uint16_t d,
|
2025-08-16 16:03:55 +01:00
|
|
|
uint64_t e)
|
|
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_i32 x_a = fx_i32_htob(a);
|
|
|
|
|
fx_i16 x_b = fx_i16_htob(b);
|
|
|
|
|
fx_i16 x_c = fx_i16_htob(c);
|
|
|
|
|
fx_i16 x_d = fx_i16_htob(d);
|
|
|
|
|
fx_i64 x_e = fx_i64_htob(e);
|
2025-08-16 16:03:55 +01:00
|
|
|
|
|
|
|
|
memcpy(&out->b[0], x_a.i_bytes, sizeof x_a.i_bytes);
|
|
|
|
|
memcpy(&out->b[4], x_b.i_bytes, sizeof x_b.i_bytes);
|
|
|
|
|
memcpy(&out->b[6], x_c.i_bytes, sizeof x_c.i_bytes);
|
|
|
|
|
memcpy(&out->b[8], x_d.i_bytes, sizeof x_d.i_bytes);
|
|
|
|
|
memcpy(&out->b[10], &x_e.i_bytes[2], sizeof x_e.i_bytes - 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void initialise_type_component(
|
2026-05-02 21:01:17 +01:00
|
|
|
struct fx_type_component *comp,
|
|
|
|
|
const struct fx_type_info *info,
|
2025-08-16 16:03:55 +01:00
|
|
|
struct type_init_ctx *init_ctx)
|
|
|
|
|
{
|
|
|
|
|
comp->c_class_data_offset = init_ctx->ctx_class_offset;
|
|
|
|
|
comp->c_class_data_size = info->t_class_size;
|
|
|
|
|
init_ctx->ctx_class_offset += comp->c_class_data_size;
|
|
|
|
|
|
|
|
|
|
comp->c_instance_private_data_offset = init_ctx->ctx_instance_offset;
|
|
|
|
|
comp->c_instance_private_data_size = info->t_instance_private_size;
|
|
|
|
|
init_ctx->ctx_instance_offset += comp->c_instance_private_data_size;
|
|
|
|
|
|
|
|
|
|
comp->c_instance_protected_data_offset = init_ctx->ctx_instance_offset;
|
|
|
|
|
comp->c_instance_protected_data_size = info->t_instance_protected_size;
|
|
|
|
|
init_ctx->ctx_instance_offset += comp->c_instance_protected_data_size;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static fx_result locate_interface(
|
2026-05-02 21:01:17 +01:00
|
|
|
fx_type interface_id,
|
|
|
|
|
struct fx_type_registration *dest,
|
2025-08-16 16:03:55 +01:00
|
|
|
struct type_init_ctx *init_ctx)
|
|
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_component *interface_comp
|
|
|
|
|
= fx_type_get_component(&dest->r_components, interface_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
if (interface_comp) {
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_SUCCESS;
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_registration *interface_reg
|
2025-08-16 16:03:55 +01:00
|
|
|
= get_type(&type_list, interface_id);
|
|
|
|
|
if (!interface_reg) {
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_ERR(NO_ENTRY);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface_comp = create_type_component(interface_reg);
|
|
|
|
|
if (!interface_comp) {
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_ERR(NO_MEMORY);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-02 21:01:17 +01:00
|
|
|
initialise_type_component(
|
|
|
|
|
interface_comp,
|
|
|
|
|
interface_reg->r_info,
|
|
|
|
|
init_ctx);
|
2025-11-01 09:57:32 +00:00
|
|
|
|
2025-08-16 16:03:55 +01:00
|
|
|
put_type_component(&dest->r_components, interface_comp);
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_SUCCESS;
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static fx_result locate_interfaces(
|
2026-05-02 21:01:17 +01:00
|
|
|
const union fx_type *interfaces,
|
|
|
|
|
size_t nr_interfaces,
|
|
|
|
|
struct fx_type_registration *dest,
|
|
|
|
|
struct type_init_ctx *init_ctx)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_result result = FX_RESULT_SUCCESS;
|
2025-08-16 16:03:55 +01:00
|
|
|
for (size_t i = 0; i < nr_interfaces; i++) {
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_type interface_id = &interfaces[i];
|
2025-08-16 16:03:55 +01:00
|
|
|
result = locate_interface(interface_id, dest, init_ctx);
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
if (fx_result_is_error(result)) {
|
2025-08-16 16:03:55 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static fx_result find_type_components(struct fx_type_registration *reg)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
const struct fx_type_info *current = reg->r_info;
|
|
|
|
|
struct fx_type_component *comp = create_type_component(reg);
|
2025-08-16 16:03:55 +01:00
|
|
|
if (!comp) {
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_ERR(NO_MEMORY);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct type_init_ctx init_ctx = {
|
2026-03-16 10:35:43 +00:00
|
|
|
.ctx_instance_offset = sizeof(struct _fx_object),
|
|
|
|
|
.ctx_class_offset = sizeof(struct _fx_class),
|
2025-08-16 16:03:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
put_type_component(®->r_components, comp);
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_queue_push_front(®->r_class_hierarchy, &comp->c_entry);
|
2025-08-16 16:03:55 +01:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_result result = locate_interfaces(
|
2026-05-02 21:01:17 +01:00
|
|
|
current->t_interfaces,
|
|
|
|
|
current->t_nr_interfaces,
|
|
|
|
|
reg,
|
|
|
|
|
&init_ctx);
|
2025-08-16 16:03:55 +01:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
if (fx_result_is_error(result)) {
|
2025-08-16 16:03:55 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_type current_id = ¤t->t_parent_id;
|
|
|
|
|
if (!current_id || fx_type_id_compare(current_id, &zero_id) == 0) {
|
2025-08-16 16:03:55 +01:00
|
|
|
goto skip_class_hierarchy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_registration *dep_class
|
2025-08-16 16:03:55 +01:00
|
|
|
= get_type(&type_list, current_id);
|
|
|
|
|
if (!dep_class) {
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_ERR(NO_ENTRY);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
comp = fx_type_get_component(®->r_components, current_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
if (comp) {
|
|
|
|
|
/* circular class dependency */
|
2026-03-16 10:35:43 +00:00
|
|
|
// result = FX_RESULT_ERR(INVALID_ARGUMENT);
|
2025-10-24 12:29:24 +01:00
|
|
|
// break;
|
2025-11-01 09:57:32 +00:00
|
|
|
current_id = &dep_class->r_info->t_parent_id;
|
2025-10-24 12:29:24 +01:00
|
|
|
continue;
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
comp = create_type_component(dep_class);
|
|
|
|
|
|
|
|
|
|
result = locate_interfaces(
|
|
|
|
|
dep_class->r_info->t_interfaces,
|
2026-05-02 21:01:17 +01:00
|
|
|
dep_class->r_info->t_nr_interfaces,
|
|
|
|
|
reg,
|
|
|
|
|
&init_ctx);
|
2026-03-16 10:35:43 +00:00
|
|
|
if (fx_result_is_error(result)) {
|
2025-08-16 16:03:55 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
put_type_component(®->r_components, comp);
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_queue_push_front(®->r_class_hierarchy, &comp->c_entry);
|
2025-08-16 16:03:55 +01:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
if (fx_type_id_compare(current_id, FX_TYPE_OBJECT) == 0) {
|
2025-08-16 16:03:55 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2025-10-24 12:29:24 +01:00
|
|
|
|
|
|
|
|
current_id = &dep_class->r_info->t_parent_id;
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_queue_entry *entry = fx_queue_first(®->r_class_hierarchy);
|
2025-10-29 14:31:09 +00:00
|
|
|
while (entry) {
|
2026-03-16 10:35:43 +00:00
|
|
|
comp = fx_unbox(struct fx_type_component, entry, c_entry);
|
2026-05-02 21:01:17 +01:00
|
|
|
initialise_type_component(
|
|
|
|
|
comp,
|
|
|
|
|
comp->c_type->r_info,
|
|
|
|
|
&init_ctx);
|
2026-03-16 10:35:43 +00:00
|
|
|
entry = fx_queue_next(entry);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_bst_node *node = fx_bst_first(®->r_components);
|
2025-10-29 14:31:09 +00:00
|
|
|
while (node) {
|
2026-03-16 10:35:43 +00:00
|
|
|
comp = fx_unbox(struct fx_type_component, node, c_node);
|
|
|
|
|
if (comp->c_type->r_category == FX_TYPE_CLASS) {
|
2025-08-16 16:03:55 +01:00
|
|
|
/* this component was already initialised above */
|
2026-03-16 10:35:43 +00:00
|
|
|
node = fx_bst_next(node);
|
2025-08-16 16:03:55 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 21:01:17 +01:00
|
|
|
initialise_type_component(
|
|
|
|
|
comp,
|
|
|
|
|
comp->c_type->r_info,
|
|
|
|
|
&init_ctx);
|
2026-03-16 10:35:43 +00:00
|
|
|
node = fx_bst_next(node);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skip_class_hierarchy:
|
|
|
|
|
reg->r_instance_size = init_ctx.ctx_instance_offset;
|
|
|
|
|
reg->r_class_size = init_ctx.ctx_class_offset;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static bool type_has_base_class(struct fx_type_info *info)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
if (fx_type_id_compare(&info->t_id, FX_TYPE_OBJECT) == 0) {
|
2025-08-16 16:03:55 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
return fx_type_id_compare(&info->t_parent_id, &zero_id) != 0;
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_result fx_type_register(struct fx_type_info *info)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
|
|
|
|
if (!type_has_base_class(info)) {
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_type_id_copy(FX_TYPE_OBJECT, &info->t_parent_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_registration *r = get_type(&type_list, &info->t_id);
|
2025-08-16 16:03:55 +01:00
|
|
|
if (r) {
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_ERR(NAME_EXISTS);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = malloc(sizeof *r);
|
|
|
|
|
if (!r) {
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_ERR(NO_MEMORY);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(r, 0x0, sizeof *r);
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
r->r_category = FX_TYPE_CLASS;
|
2025-08-16 16:03:55 +01:00
|
|
|
r->r_info = info;
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_result result = find_type_components(r);
|
|
|
|
|
if (fx_result_is_error(result)) {
|
2025-08-16 16:03:55 +01:00
|
|
|
free(r);
|
2026-03-16 10:35:43 +00:00
|
|
|
return fx_result_propagate(result);
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
result = fx_class_instantiate(r, &r->r_class);
|
2025-08-16 16:03:55 +01:00
|
|
|
if (!r->r_class) {
|
|
|
|
|
free(r);
|
2026-03-16 10:35:43 +00:00
|
|
|
return fx_error_with_msg_template_caused_by_error(
|
2026-05-02 21:01:17 +01:00
|
|
|
FX_ERRORS_BUILTIN,
|
|
|
|
|
FX_ERR_TYPE_REGISTRATION_FAILURE,
|
|
|
|
|
result,
|
|
|
|
|
FX_MSG_TYPE_REGISTRATION_FAILURE,
|
2026-03-16 10:35:43 +00:00
|
|
|
FX_ERROR_PARAM("typename", info->t_name));
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
put_type(&type_list, r);
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_RESULT_SUCCESS;
|
2025-08-16 16:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_type_registration *fx_type_get_registration(fx_type id)
|
2025-08-16 16:03:55 +01:00
|
|
|
{
|
|
|
|
|
return get_type(&type_list, id);
|
|
|
|
|
}
|