1#include "include/pw.h"
  2#include "src/pw_alloc.h"
  3#include "src/pw_interfaces_internal.h"
  4
  5#include <libpussy/arena.h>
  6#include <libpussy/mmarray.h>
  7
  8static Arena* arena = nullptr;
  9
 10void* _pw_arena_alloc_bytes(unsigned size, unsigned alignment)
 11{
 12    void* result = _arena_fit(arena, size, alignment);
 13    if (!result) {
 14        pw_panic("Out of memory\n");
 15    }
 16    return result;
 17}
 18
 19PW_STRUCT(InterfaceInfo) {
 20    char* name;
 21    char** method_names;
 22    unsigned num_methods;
 23};
 24
 25static InterfaceInfo** registered_interfaces = nullptr;
 26static unsigned num_registered_interfaces = 0;
 27
 28static char s_interface_not_registered[] = "Interface %u is not registered yet\n";
 29#define pw_panic_interface_not_registered(interface_id)  pw_panic(s_interface_not_registered, (interface_id));
 30
 31[[noreturn]]
 32void _pw_panic_no_interface(uint16_t type_id, uint16_t interface_id)
 33{
 34    char* iname;
 35    if (registered_interfaces) {
 36        iname = registered_interfaces[interface_id]->name;
 37    } else {
 38        iname = "unknown";
 39    }
 40    pw_panic("Interface %s (%u) is not defined for %s\n", iname, interface_id, _pw_types[type_id]->name);
 41}
 42
 43PwInterface_Generic* __pw_do_lookup_interface(PwType* type, uint16_t interface_id)
 44{
 45    PwInterface_Generic** iface = type->other_interfaces;
 46    if (iface) {
 47        PwInterface_Generic** iface_end = iface + type->num_other_interfaces;
 48        do {
 49            if ((*iface)->id == interface_id) {
 50                return *iface;
 51            }
 52            iface++;
 53        } while (iface < iface_end);
 54    }
 55    return nullptr;
 56}
 57
 58void pw_destroy_compound(PwValuePtr value, _PwCompoundChain* tail)
 59{
 60    uint16_t type_id = value->type_id;
 61
 62    if (_pw_likely(type_id < PW_NUM_INTEGRAL_TYPES)) {
 63        *value = PwNull();
 64        return;
 65    }
 66
 67    if (_pw_unlikely(_pw_on_chain(value, tail))) {
 68        return;
 69    }
 70
 71    PwMethod_Basic_decref* meth_decref;
 72    pw_method(type_id, Basic, decref, &meth_decref);
 73    PwFunc_Basic_decref fn_decref = meth_decref->func;
 74    if (_pw_unlikely(fn_decref)) {
 75        if (fn_decref(meth_decref, value)) {
 76            // refcount is still above zero
 77            // clean value holder but do not call destructor
 78            *value = PwNull();
 79            return;
 80        }
 81    }
 82
 83    PwMethod_Basic_destroy* meth_destroy;
 84    pw_method(type_id, Basic, destroy, &meth_destroy);
 85    PwFunc_Basic_destroy fn_destroy = meth_destroy->func;
 86    if (_pw_unlikely(fn_destroy)) {
 87        fn_destroy(meth_destroy, value, tail);
 88    }
 89    *value = PwNull();
 90}
 91
 92
 93#define builtin(name, ...)  \
 94    pw_hard_assert(PwInterfaceId_##name == pw_register_interface(#name, __VA_ARGS__))
 95
 96[[gnu::constructor]]
 97void _pw_init_interfaces()
 98{
 99    if (registered_interfaces) {
100        return;
101    }
102
103    arena = create_arena(0);
104    registered_interfaces = mmarray_allocate(65536, 0, sizeof(InterfaceInfo*));
105
106    // register built-in interfaces
107
108#   define X(name, ...) #name __VA_OPT__(,)
109    builtin(Basic,        PW_BASIC_INTERFACE_METHODS,         nullptr);
110    builtin(RandomAccess, PW_RANDOM_ACCESS_INTERFACE_METHODS, nullptr);
111    builtin(Reader,       PW_READER_INTERFACE_METHODS,        nullptr);
112    builtin(Writer,       PW_WRITER_INTERFACE_METHODS,        nullptr);
113    builtin(LineReader,   PW_LINE_READER_INTERFACE_METHODS,   nullptr);
114    builtin(Append,       PW_APPEND_INTERFACE_METHODS,        nullptr);
115    builtin(Fd,           PW_FD_INTERFACE_METHODS,            nullptr);
116#   undef X
117}
118
119uint16_t pw_register_interface(char* name, ...)
120{
121    _pw_init_interfaces();
122    if (mmarray_grow(registered_interfaces, 1)) { /* no op, address not changed */ }
123
124    uint16_t interface_id = num_registered_interfaces++;
125    InterfaceInfo* iinfo = registered_interfaces[interface_id] = _pw_arena_alloc(1, InterfaceInfo);
126    iinfo->name = name;
127    iinfo->num_methods = 0;
128
129    va_list ap;
130    va_list temp_ap;
131    va_start(ap);
132
133    // count method names
134    va_copy(temp_ap, ap);
135    for(;;) {
136        char* method_name = va_arg(temp_ap, char*);
137        if (!method_name) {
138            break;
139        }
140        iinfo->num_methods++;
141    }
142    va_end(temp_ap);
143
144    // allocate array for method names
145    char** method_names = _pw_arena_alloc(iinfo->num_methods, char*);
146    iinfo->method_names = method_names;
147
148    // init method names
149    for (;;) {
150        char* method_name = va_arg(ap, char*);
151        if (!method_name) {
152            break;
153        }
154        *method_names++ = method_name;
155    }
156    va_end(ap);
157    return interface_id;
158}
159
160bool pw_interface_exists(uint16_t interface_id)
161{
162    return interface_id < num_registered_interfaces;
163}
164
165char* pw_get_interface_name(uint16_t interface_id)
166{
167    if (interface_id >= num_registered_interfaces) {
168        pw_panic_interface_not_registered(interface_id);
169    }
170    return registered_interfaces[interface_id]->name;
171}
172
173unsigned _pw_get_num_interface_methods(uint16_t interface_id)
174{
175    if (interface_id >= num_registered_interfaces) {
176        pw_panic_interface_not_registered(interface_id);
177    }
178    return registered_interfaces[interface_id]->num_methods;
179}
180
181
182static PwInterface_Generic* find_interface_definition(PwType* type, uint16_t interface_id)
183// helper for _pw_make_interface
184{
185    unsigned n = type->num_interface_definitions;
186    if (n) {
187        PwInterface_Generic** idef = type->interface_definitions;
188        PwInterface_Generic** idef_end = idef + n;
189        while (idef < idef_end) {
190            if ((*idef)->id == interface_id) {
191                return *idef;
192            }
193            idef++;
194        }
195    }
196    return nullptr;
197}
198
199PwInterface_Generic* _pw_make_interface(PwType* type, uint16_t interface_id)
200{
201    if (interface_id >= num_registered_interfaces) {
202        pw_panic_interface_not_registered(interface_id);
203    }
204
205    InterfaceInfo* iinfo = registered_interfaces[interface_id];
206
207    // allocate and initialize interface structure
208
209    unsigned memsize = sizeof(PwInterface_Generic) + iinfo->num_methods * sizeof(PwMethod_Generic);
210    PwInterface_Generic* interface = _pw_arena_alloc_bytes(memsize, alignof(PwInterface_Generic));
211    interface->id           = interface_id;
212    interface->num_methods  = iinfo->num_methods;
213    interface->name         = iinfo->name;
214    interface->method_names = iinfo->method_names;
215    interface->type         = type;
216
217    // make interface methods
218
219    PwMethod_Generic* method = interface->methods;
220    PwMethod_Generic* method_end = method + interface->num_methods;
221    unsigned method_index = 0;
222    while (method < method_end) {
223        method->func  = nullptr;
224        method->super = nullptr;
225        method->self  = nullptr;
226        method->struct_offset = 0;
227        method->type_id = 0;
228
229        // build MRO chain
230
231        PwMethod_Generic* sub_method = method;  // current method in the chain
232        unsigned* struct_offset = type->struct_offsets;
233
234        PwInterface_Generic* idef = find_interface_definition(type, interface_id);
235
236        if (idef && idef->methods[method_index].func) {
237            // have func defined for this type
238            sub_method->func = idef->methods[method_index].func;
239            sub_method->self = interface;
240            sub_method->struct_offset = struct_offset? *struct_offset : 0;
241            sub_method->type_id = type->id;
242        }
243        struct_offset++;
244
245        PwType** base_type = type->base_types;
246        PwType** base_type_end = base_type + type->num_base_types;
247        while (base_type < base_type_end) {
248            PwType* t = *base_type;
249            idef = find_interface_definition(t, interface_id);
250
251            if (idef && idef->methods[method_index].func) {
252
253                // have super func
254
255                if (sub_method->func) {
256                    // sub_method already initialized, allocate new one
257                    PwMethod_Generic* super_method = _pw_arena_alloc(1, PwMethod_Generic);
258                    super_method->super = nullptr;
259                    sub_method->super = super_method;
260                    sub_method = super_method;
261                }
262                // initialize current method
263                sub_method->func = idef->methods[method_index].func;
264                sub_method->self = _pw_lookup_interface_t(t, interface_id);
265                if (!sub_method->self) {
266                    pw_panic("Interface %s must be initialized for %s\n", iinfo->name, t->name);
267                }
268                pw_hard_assert(sub_method->self->type->id == t->id);
269                sub_method->struct_offset = struct_offset? *struct_offset : 0;
270                sub_method->type_id = t->id;
271            }
272            base_type++;
273            struct_offset++;
274        }
275        method++;
276        method_index++;
277    }
278    return interface;
279}