diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-23 08:01:36 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-06 11:50:46 -0600 |
commit | a83c95e9f46ef695a55fc7a6911e11846da9903c (patch) | |
tree | 42abde5f3b34b239bb95e84200ea16ad4a4c562d /libobj | |
parent | b3ee525e9e0d49485714770d898cf9c28769313a (diff) |
Merge libobj into libmisc
Diffstat (limited to 'libobj')
-rw-r--r-- | libobj/CMakeLists.txt | 13 | ||||
-rw-r--r-- | libobj/include/libobj/obj.h | 173 | ||||
l--------- | libobj/tests/test.h | 1 | ||||
-rw-r--r-- | libobj/tests/test_nest.c | 73 | ||||
-rw-r--r-- | libobj/tests/test_obj.c | 61 |
5 files changed, 0 insertions, 321 deletions
diff --git a/libobj/CMakeLists.txt b/libobj/CMakeLists.txt deleted file mode 100644 index f452e8a..0000000 --- a/libobj/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# libobj/CMakeLists.txt - A simple Go-ish object system built on GCC -fplan9-extensions -# -# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> -# SPDX-License-Identifier: AGPL-3.0-or-later - -add_library(libobj INTERFACE) -target_include_directories(libobj PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) -target_link_libraries(libobj INTERFACE - libmisc -) - -add_lib_test(libobj test_obj) -add_lib_test(libobj test_nest) diff --git a/libobj/include/libobj/obj.h b/libobj/include/libobj/obj.h deleted file mode 100644 index 06b7298..0000000 --- a/libobj/include/libobj/obj.h +++ /dev/null @@ -1,173 +0,0 @@ -/* libobj/obj.h - A simple Go-ish object system - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBOBJ_OBJ_H_ -#define _LIBOBJ_OBJ_H_ - -#include <libmisc/macro.h> - -/** - * Use `lo_interface` similarly to how you would use - * `struct`/`enum`/`union` when writing the type of an interface - * value. - */ -#define lo_interface struct - -/** - * Use `LO_INTERFACE` in a .h file to define an interface. - * - * First define a macro named `{iface_name}_LO_IFACE` consisting of a - * series of calls to LO_NEST and/or LO_FUNC, then call - * `LO_INTERFACE({iface_name})`: - * - * #define myiface_LO_IFACE \ - * LO_NEST(wrapped_iface_name) \ - * LO_FUNC(ret_type, func_name, args...) - * LO_INTERFACE(myiface) - * - * Use `lo_interface {iface_name}` as the type of this interface; it - * should not be a pointer type. - * - * If there are any LO_NEST interfaces, this will define a - * `lo_box_{iface_name}_as_{wrapped_iface_name}(obj)` function for - * each. - */ -#define LO_NEST(_ARG_child_iface_name) \ - (lo_nest, _ARG_child_iface_name) -#define LO_FUNC(_ARG_ret_type, _ARG_func_name, ...) \ - (lo_func, _ARG_ret_type, _ARG_func_name __VA_OPT__(,) __VA_ARGS__) -#define LO_INTERFACE(_ARG_iface_name) \ - struct _lo_##_ARG_iface_name##_vtable { \ - LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \ - _LO_IFACE_VTABLE) \ - }; \ - struct _ARG_iface_name { \ - void *self; \ - const struct _lo_##_ARG_iface_name##_vtable *vtable; \ - }; \ - LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \ - _LO_IFACE_PROTO, _ARG_iface_name) \ - extern int LM_CAT2_(_HIDDEN_BOGUS_, __COUNTER__) - -#define _LO_IFACE_VTABLE(_tuple_typ, ...) _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__) -#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE2) -#define _LO_IFACE_VTABLE_lo_func(_ARG_ret_type, _ARG_func_name, ...) _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__); - -#define _LO_IFACE_VTABLE2(_tuple_typ, ...) _LO_IFACE_VTABLE2_##_tuple_typ(__VA_ARGS__) -#define _LO_IFACE_VTABLE2_lo_nest(_ARG_child_iface_name) const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; LM_FOREACH_TUPLE3(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE3) -#define _LO_IFACE_VTABLE2_lo_func(_ARG_ret_type, _ARG_func_name, ...) _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__); - -#define _LO_IFACE_VTABLE3(_tuple_typ, ...) _LO_IFACE_VTABLE3_##_tuple_typ(__VA_ARGS__) -#define _LO_IFACE_VTABLE3_lo_nest(_ARG_child_iface_name) const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; LM_FOREACH_TUPLE4(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE4) -#define _LO_IFACE_VTABLE3_lo_func(_ARG_ret_type, _ARG_func_name, ...) _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__); - -#define _LO_IFACE_VTABLE4(_tuple_typ, ...) _LO_IFACE_VTABLE4_##_tuple_typ(__VA_ARGS__) -#define _LO_IFACE_VTABLE4_lo_nest(_ARG_child_iface_name) static_assert(0, "BUG: libobj cannot nest interfaces more than 4 deep"); -#define _LO_IFACE_VTABLE4_lo_func(_ARG_ret_type, _ARG_func_name, ...) _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__); - -#define _LO_IFACE_PROTO(_ARG_iface_name, _tuple_typ, ...) _LO_IFACE_PROTO_##_tuple_typ(_ARG_iface_name, __VA_ARGS__) -#define _LO_IFACE_PROTO_lo_nest(_ARG_iface_name, _ARG_child_iface_name) \ - LM_ALWAYS_INLINE static lo_interface _ARG_child_iface_name \ - box_##_ARG_iface_name##_as_##_ARG_child_iface_name(lo_interface _ARG_iface_name obj) { \ - return (lo_interface _ARG_child_iface_name){ \ - .self = obj.self, \ - .vtable = obj.vtable->_lo_##_ARG_child_iface_name##_vtable, \ - }; \ - } -#define _LO_IFACE_PROTO_lo_func(_ARG_iface_name, _ARG_ret_type, _ARG_func_name, ...) \ - /* empty */ - -/** - * `LO_NULL(iface_name)` is the null/nil/zero value for `lo_interface {iface_name}`. - */ -#define LO_NULL(_ARG_iface_name) ((lo_interface _ARG_iface_name){0}) - -/** - * `LO_IS_NULL(iface_val)` returns whether `iface_val` is LO_NULL. - */ -#define LO_IS_NULL(_ARG_iface_val) ((_ARG_iface_val).vtable == NULL) - -/** - * `LO_IFACE_EQ(a, b)` returns whether the interface values `a` and - * `b` are the same object. - */ -#define LO_EQ(_ARG_iface_val_a, _ARG_iface_val_b) \ - ((_ARG_iface_val_a).self == (_ARG_iface_val_b).self) - -/** - * Use LO_CALL(obj, method_name, args...) to call a method on an `lo_interface`. - */ -#define LO_CALL(_ARG_obj, _ARG_meth, ...) \ - (_ARG_obj).vtable->_ARG_meth((_ARG_obj).self __VA_OPT__(,) __VA_ARGS__) - -/** - * Use `LO_IMPLEMENTATION_H(iface_name, impl_type, impl_name)` in a .h - * file to declare that `{impl_type}` implements the `{iface_name}` - * interface with functions named `{impl_name}_{method_name}`. - * - * This will also define a `lo_box_{impl_name}_as_{iface_name}(obj)` - * function. - * - * You must also call the LO_IMPLEMENTATION_C in a single .c file. - */ -#define LO_IMPLEMENTATION_H(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \ - /* Vtable. */ \ - extern const struct _lo_##_ARG_iface_name##_vtable \ - _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable; \ - /* Boxing. */ \ - LM_ALWAYS_INLINE static lo_interface _ARG_iface_name \ - lo_box_##_ARG_impl_name##_as_##_ARG_iface_name(_ARG_impl_type *self) { \ - return (lo_interface _ARG_iface_name){ \ - .self = self, \ - .vtable = &_lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable, \ - }; \ - } \ - LM_FORCE_SEMICOLON - -/** - * Use `LO_IMPLEMENTATION_C(iface_name, impl_type, impl_name[, static])` in a .c - * file to declare that `{impl_type}` implements the `{iface_name}` interface - * with functions named `{impl_name}_{method_name}`. - * - * You must also call the LO_IMPLEMENTATION_H in the corresponding .h file. - * - * If `iface_name` contains a nested interface, then the - * implementation of the nested interfaces must be declared with - * `LO_IMPLEMENTATION_C` first. - */ -#define LO_IMPLEMENTATION_C(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name, ...) \ - /* Method prototypes. */ \ - LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \ - _LO_IMPL_PROTO, _ARG_impl_type, _ARG_impl_name, __VA_ARGS__) \ - /* Vtable. */ \ - const struct _lo_##_ARG_iface_name##_vtable \ - _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable = { \ - LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \ - _LO_IMPL_VTABLE, _ARG_impl_name) \ - } - -#define _LO_IMPL_PROTO( _ARG_impl_type, _ARG_impl_name, _ARG_quals, _tuple_typ, ...) _LO_IMPL_PROTO_##_tuple_typ(_ARG_impl_type, _ARG_impl_name, _ARG_quals, __VA_ARGS__) -#define _LO_IMPL_PROTO_lo_nest(_ARG_impl_type, _ARG_impl_name, _ARG_quals, _ARG_child_iface_name) /* empty */ -#define _LO_IMPL_PROTO_lo_func(_ARG_impl_type, _ARG_impl_name, _ARG_quals, _ARG_ret_type, _ARG_func_name, ...) _ARG_quals _ARG_ret_type _ARG_impl_name##_##_ARG_func_name(_ARG_impl_type * __VA_OPT__(,) __VA_ARGS__); - -#define _LO_IMPL_VTABLE(_ARG_impl_name, _tuple_typ, ...) _LO_IMPL_VTABLE_##_tuple_typ(_ARG_impl_name, __VA_ARGS__) -#define _LO_IMPL_VTABLE_lo_nest(_ARG_impl_name, _ARG_child_iface_name) ._lo_##_ARG_child_iface_name##_vtable = &_lo_##_ARG_impl_name##_##_ARG_child_iface_name##_vtable, LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IMPL_VTABLE2, _ARG_impl_name) -#define _LO_IMPL_VTABLE_lo_func(_ARG_impl_name, _ARG_ret_type, _ARG_func_name, ...) ._ARG_func_name = (void*)_ARG_impl_name##_##_ARG_func_name, - -#define _LO_IMPL_VTABLE2(_ARG_impl_name, _tuple_typ, ...) _LO_IMPL_VTABLE2_##_tuple_typ(_ARG_impl_name, __VA_ARGS__) -#define _LO_IMPL_VTABLE2_lo_nest(_ARG_impl_name, _ARG_child_iface_name) ._lo_##_ARG_child_iface_name##_vtable = &_lo_##_ARG_impl_name##_##_ARG_child_iface_name##_vtable, LM_FOREACH_TUPLE3(_ARG_child_iface_name##_LO_IFACE, _LO_IMPL_VTABLE3, _ARG_impl_name) -#define _LO_IMPL_VTABLE2_lo_func(_ARG_impl_name, _ARG_ret_type, _ARG_func_name, ...) ._ARG_func_name = (void*)_ARG_impl_name##_##_ARG_func_name, - -#define _LO_IMPL_VTABLE3(_ARG_impl_name, _tuple_typ, ...) _LO_IMPL_VTABLE3_##_tuple_typ(_ARG_impl_name, __VA_ARGS__) -#define _LO_IMPL_VTABLE3_lo_nest(_ARG_impl_name, _ARG_child_iface_name) ._lo_##_ARG_child_iface_name##_vtable = &_lo_##_ARG_impl_name##_##_ARG_child_iface_name##_vtable, LM_FOREACH_TUPLE4(_ARG_child_iface_name##_LO_IFACE, _LO_IMPL_VTABLE4, _ARG_impl_name) -#define _LO_IMPL_VTABLE3_lo_func(_ARG_impl_name, _ARG_ret_type, _ARG_func_name, ...) ._ARG_func_name = (void*)_ARG_impl_name##_##_ARG_func_name, - -#define _LO_IMPL_VTABLE4(_ARG_impl_name, _tuple_typ, ...) _LO_IMPL_VTABLE4_##_tuple_typ(_ARG_impl_name, __VA_ARGS__) -#define _LO_IMPL_VTABLE4_lo_nest(_ARG_impl_name, _ARG_child_iface_name) static_assert(0, "BUG: libobj cannot nest interfaces more than 4 deep"); -#define _LO_IMPL_VTABLE4_lo_func(_ARG_impl_name, _ARG_ret_type, _ARG_func_name, ...) ._ARG_func_name = (void*)_ARG_impl_name##_##_ARG_func_name, - - -#endif /* _LIBOBJ_OBJ_H_ */ diff --git a/libobj/tests/test.h b/libobj/tests/test.h deleted file mode 120000 index 2fb1bd5..0000000 --- a/libobj/tests/test.h +++ /dev/null @@ -1 +0,0 @@ -../../libmisc/tests/test.h
\ No newline at end of file diff --git a/libobj/tests/test_nest.c b/libobj/tests/test_nest.c deleted file mode 100644 index f18b018..0000000 --- a/libobj/tests/test_nest.c +++ /dev/null @@ -1,73 +0,0 @@ -/* libobj/tests/test_nest.c - Tests for <libobj/obj.h> - * - * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#include <string.h> /* for memcpy() */ - -#include <libobj/obj.h> - -#include "test.h" - -/* interfaces *****************************************************************/ - -#define reader_LO_IFACE \ - LO_FUNC(ssize_t, read, void *, size_t) -LO_INTERFACE(reader); - -#define writer_LO_IFACE \ - LO_FUNC(ssize_t, write, void *, size_t) -LO_INTERFACE(writer); - -#define read_writer_LO_IFACE \ - LO_NEST(reader) \ - LO_NEST(writer) -LO_INTERFACE(read_writer); - -/* implementation header ******************************************************/ - -struct myclass { - size_t len; - char buf[512]; -}; -LO_IMPLEMENTATION_H(reader, struct myclass, myclass); -LO_IMPLEMENTATION_H(writer, struct myclass, myclass); -LO_IMPLEMENTATION_H(read_writer, struct myclass, myclass); - -/* implementation main ********************************************************/ - -LO_IMPLEMENTATION_C(reader, struct myclass, myclass, static); -LO_IMPLEMENTATION_C(writer, struct myclass, myclass, static); -LO_IMPLEMENTATION_C(read_writer, struct myclass, myclass, static); - -static ssize_t myclass_read(struct myclass *self, void *buf, size_t count) { - test_assert(self); - if (count > self->len) - count = self->len; - memcpy(buf, self->buf, count); - return count; -} - -static ssize_t myclass_write(struct myclass *self, void *buf, size_t count) { - test_assert(self); - if (self->len) - return -1; - if (count > sizeof(self->buf)) - count = sizeof(self->buf); - memcpy(self->buf, buf, count); - self->len = count; - return count; -} - -/* main test body *************************************************************/ - -int main() { - struct myclass _obj = {0}; - lo_interface read_writer obj = lo_box_myclass_as_read_writer(&_obj); - test_assert(LO_CALL(obj, write, "Hello", 6) == 6); - char buf[6] = {0}; - test_assert(LO_CALL(obj, read, buf, 3) == 3); - test_assert(memcmp(buf, "Hel\0\0\0", 6) == 0); - return 0; -} diff --git a/libobj/tests/test_obj.c b/libobj/tests/test_obj.c deleted file mode 100644 index d6861dc..0000000 --- a/libobj/tests/test_obj.c +++ /dev/null @@ -1,61 +0,0 @@ -/* libobj/tests/test_obj.c - Tests for <libobj/obj.h> - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#include <libobj/obj.h> - -#include "test.h" - -/* `lo_inteface frobber` header ***********************************************/ - -#define frobber_LO_IFACE \ - /** Basic function. */ \ - LO_FUNC(int, frob) \ - /** Function that takes 1 argument. */ \ - LO_FUNC(int, frob1, int) \ - /** Function that returns nothing. */ \ - LO_FUNC(void, frob0) -LO_INTERFACE(frobber); - -/* `struct myclass` header ****************************************************/ - -struct myclass { - int a; -}; -LO_IMPLEMENTATION_H(frobber, struct myclass, myclass); - -/* `struct myclass` implementation ********************************************/ - -LO_IMPLEMENTATION_C(frobber, struct myclass, myclass, static); - -static int myclass_frob(struct myclass *self) { - test_assert(self); - return self->a; -} - -static int myclass_frob1(struct myclass *self, int arg) { - test_assert(self); - return arg; -} - -static void myclass_frob0(struct myclass *self) { - test_assert(self); -} - -/* main test body *************************************************************/ - -#define MAGIC1 909837 -#define MAGIC2 657441 - -int main() { - struct myclass obj = { - .a = MAGIC1, - }; - lo_interface frobber iface = lo_box_myclass_as_frobber(&obj); - test_assert(LO_CALL(iface, frob) == MAGIC1); - test_assert(LO_CALL(iface, frob1, MAGIC2) == MAGIC2); - LO_CALL(iface, frob0); - return 0; -} |