diff --git a/include/rtti/typeinfo.h b/include/rtti/typeinfo.h index 4352a97..e82f218 100644 --- a/include/rtti/typeinfo.h +++ b/include/rtti/typeinfo.h @@ -180,6 +180,15 @@ typedef struct { vclear_fn_t vclear; } intf_varray_t; +/* attrs API */ +typedef int (*attr_get_fn_t)(meta_obj_t*, void*, void**); +typedef int (*attr_set_fn_t)(meta_obj_t*, void*, void*); + +typedef struct { + attr_get_fn_t get; + attr_set_fn_t set; +} intf_attr_t; + typedef struct { intf_lock_t* lock; intf_tostring_t* toString; @@ -190,6 +199,7 @@ typedef struct { intf_bitmap_t* bitmap; intf_kv_t* kv; intf_varray_t* varray; + intf_attr_t* attrs; } interface_table_t; struct typeinfo_ { @@ -248,4 +258,6 @@ extern int vput(var, int, void*); extern int vput_vec(var, int, int*, void**); extern int vclear(var, int); +extern int attr_get(var, void*, void**); +extern int attr_set(var, void*, void*); #endif diff --git a/src/attr.c b/src/attr.c new file mode 100644 index 0000000..e02d8d0 --- /dev/null +++ b/src/attr.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "rtti.h" + +int attr_get(var v, void* attr, void** value) +{ + meta_obj_t* obj = NULL; + attr_get_fn_t method = NULL; + + obj = RTTI_DATA_TO_OBJ(v); + if (RTTI_OBJ_INVALID(obj)) { + return -EINVAL; + } + + RTTI_GET_METHOD(method, obj, attrs, get); + if (method == NULL) { + return -EINVAL; + } + + return method(obj, attr, value); +} + +int attr_set(var v, void* attr, void* value) +{ + meta_obj_t* obj = NULL; + attr_set_fn_t method = NULL; + + obj = RTTI_DATA_TO_OBJ(v); + if (RTTI_OBJ_INVALID(obj)) { + return -EINVAL; + } + + RTTI_GET_METHOD(method, obj, attrs, set); + if (method == NULL) { + return -EINVAL; + } + + return method(obj, attr, value); +} diff --git a/src/meson.build b/src/meson.build index d9c5858..f9630b2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,7 @@ librtti_c_srcs=[ 'bitmap.c', 'kv.c', 'varray.c', + 'attr.c', ] diff --git a/testsuite/meson.build b/testsuite/meson.build index fe744b7..4c018f8 100644 --- a/testsuite/meson.build +++ b/testsuite/meson.build @@ -2,6 +2,7 @@ librtti_test_srcs = [ 'test.c', 'test_iter.c', 'test_invalid_obj.c', + 'test_attr.c', ] unity_dep = dependency('unity') diff --git a/testsuite/test.c b/testsuite/test.c index e1f9989..0a29d8f 100644 --- a/testsuite/test.c +++ b/testsuite/test.c @@ -17,6 +17,7 @@ void tearDown(void) extern void test_type(void); extern void test_iter(void); extern void test_invalid(void); +extern void test_attr(void); #define TEST(x) x() @@ -27,6 +28,7 @@ int main(int argc, char* argv[]) TEST(test_type); TEST(test_iter); TEST(test_invalid); + TEST(test_attr); return UNITY_END(); } diff --git a/testsuite/test_attr.c b/testsuite/test_attr.c new file mode 100644 index 0000000..4ccb6c4 --- /dev/null +++ b/testsuite/test_attr.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +#include "rtti.h" + +#define ATTR_ID (0) +#define ATTR_NAME (1) + +typedef struct { + int id; + char* name; +} my_attrset_t; + +static int my_attrset_init(meta_obj_t* obj, va_list ap) +{ + my_attrset_t* attrs = RTTI_OBJ_TO_DATA(my_attrset_t, obj); + + attrs->id = -1; + attrs->name = NULL; + + return 1; +} + +static void my_attrset_destroy(meta_obj_t* obj) +{ + /* do nothing */ + return; +} + +static int my_attrset_get(meta_obj_t* obj, void* attr, void** value) +{ + my_attrset_t* attrs = RTTI_OBJ_TO_DATA(my_attrset_t, obj); + + switch ((int)(long)attr) { + case ATTR_ID: + *value = (void*)(long)attrs->id; + break; + case ATTR_NAME: + *value = (void*)attrs->name; + break; + default: + return -EINVAL; + } + + return 1; +} + +static int my_attrset_set(meta_obj_t* obj, void* attr, void* value) +{ + my_attrset_t* attrs = RTTI_OBJ_TO_DATA(my_attrset_t, obj); + + switch ((int)(long)attr) { + case ATTR_ID: + attrs->id = (int)(long)value; + break; + case ATTR_NAME: + attrs->name = (char*)value; + break; + default: + return -EINVAL; + } + + return 1; +} + +static size_t my_attrset_datasize(va_list ap) +{ + size_t sz = sizeof(my_attrset_t); + + return sz; +} + +static typeinfo_t my_attrset_type + = { .name = "my_attrset", + .privateSize = 0, + .dataSize = (datasize_fn_t)my_attrset_datasize, + .init = (obj_init_fn_t)my_attrset_init, + .destroy = (obj_destroy_fn_t)my_attrset_destroy, + .interfaces = { .attrs = &(intf_attr_t) { + .get = (attr_get_fn_t)my_attrset_get, + .set = (attr_set_fn_t)my_attrset_set } } }; + +static void test_attr_setget(void) +{ + var attrs = makeInstance(&my_attrset_type); + void* id; + char* name; + int rc = 0; + + TEST_ASSERT_TRUE(attrs != NULL); + + rc = attr_set(attrs, (void*)(long)ATTR_ID, (void *)(long)1); + + TEST_ASSERT_TRUE(rc >= 0); + + rc = attr_set(attrs, (void*)(long)ATTR_NAME, "tester"); + TEST_ASSERT_TRUE(rc >= 0); + + rc = attr_get(attrs, (void*)(long)ATTR_ID, &id); + TEST_ASSERT_TRUE(rc >= 0); + + TEST_ASSERT_TRUE((int)(long)id == 1); + + rc = attr_get(attrs, (void*)(long)ATTR_NAME, (void**)&name); + TEST_ASSERT_TRUE(rc >= 0); + + TEST_ASSERT_TRUE((strcmp(name, "tester") == 0)); + + destroy(attrs); +} + +void test_attr(void) +{ + printf("\n attr test\n\n"); + + RUN_TEST(test_attr_setget); +}