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
 19typedef struct {
 20    char* name;
 21    char** method_names;
 22    unsigned num_methods;
 23} InterfaceInfo;
 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_undefined_interface()
 59{
 60    pw_set_status(PwStatus(PW_ERROR_INTERFACE_NOT_DEFINED));
 61}
 62
 63void pw_destroy_compound2(PwValuePtr value, _PwCompoundChain* tail)
 64/*
 65 * Destroy value: call destructor (if refcount drops to zero for refcounted values) and make `value` Null.
 66 */
 67{
 68    uint16_t type_id = value->type_id;
 69
 70    if (_pw_likely(type_id < PW_NUM_INTEGRAL_TYPES)) {
 71        return;
 72    }
 73
 74    if (_pw_unlikely(_pw_on_chain(value, tail))) {
 75        return;
 76    }
 77
 78    PwMethod_Basic_decref* meth_decref;
 79    pw_method(type_id, Basic, decref, &meth_decref);
 80    PwFunc_Basic_decref fn_decref = meth_decref->func;
 81    if (_pw_unlikely(fn_decref)) {
 82        if (fn_decref(meth_decref, value)) {
 83            // refcount is still above zero
 84            // clean value holder but do not call destructor
 85            *value = PwNull();
 86            return;
 87        }
 88    }
 89
 90    PwMethod_Basic_destroy* meth_destroy;
 91    pw_method(type_id, Basic, destroy, &meth_destroy);
 92    PwFunc_Basic_destroy fn_destroy = meth_destroy->func;
 93    if (_pw_unlikely(fn_destroy)) {
 94        fn_destroy(meth_destroy, value, tail);
 95    }
 96    *value = PwNull();
 97}
 98
 99[[gnu::constructor]]
100void _pw_init_interfaces()
101{
102    if (registered_interfaces) {
103        return;
104    }
105
106    arena = create_arena(0);
107    registered_interfaces = mmarray_allocate(65536, 0, sizeof(InterfaceInfo*));
108
109    // register built-in interfaces
110
111#   define X(name, ...) #name __VA_OPT__(,)
112    pw_assert(PwInterfaceId_Basic        == pw_register_interface("Basic",        PW_BASIC_INTERFACE_METHODS,         nullptr ));
113    pw_assert(PwInterfaceId_RandomAccess == pw_register_interface("RandomAccess", PW_RANDOM_ACCESS_INTERFACE_METHODS, nullptr ));
114    pw_assert(PwInterfaceId_Reader       == pw_register_interface("Reader",       PW_READER_INTERFACE_METHODS,        nullptr ));
115    pw_assert(PwInterfaceId_Writer       == pw_register_interface("Writer",       PW_WRITER_INTERFACE_METHODS,        nullptr ));
116    pw_assert(PwInterfaceId_LineReader   == pw_register_interface("LineReader",   PW_LINE_READER_INTERFACE_METHODS,   nullptr ));
117    pw_assert(PwInterfaceId_Append       == pw_register_interface("Append",       PW_APPEND_INTERFACE_METHODS,        nullptr ));
118    pw_assert(PwInterfaceId_Fd           == pw_register_interface("Fd",           PW_FD_INTERFACE_METHODS,            nullptr ));
119#   undef X
120}
121
122uint16_t pw_register_interface(char* name, ...)
123{
124    _pw_init_interfaces();
125    if (mmarray_grow(registered_interfaces, 1)) { /* no op, address not changed */ }
126
127    uint16_t interface_id = num_registered_interfaces++;
128    InterfaceInfo* iinfo = registered_interfaces[interface_id] = _pw_arena_alloc(1, InterfaceInfo);
129    iinfo->name = name;
130    iinfo->num_methods = 0;
131
132    va_list ap;
133    va_list temp_ap;
134    va_start(ap);
135
136    // count method names
137    va_copy(temp_ap, ap);
138    for(;;) {
139        char* method_name = va_arg(temp_ap, char*);
140        if (!method_name) {
141            break;
142        }
143        iinfo->num_methods++;
144    }
145    va_end(temp_ap);
146
147    // allocate array for method names
148    char** method_names = _pw_arena_alloc(iinfo->num_methods, char*);
149    iinfo->method_names = method_names;
150
151    // init method names
152    for (;;) {
153        char* method_name = va_arg(ap, char*);
154        if (!method_name) {
155            break;
156        }
157        *method_names++ = method_name;
158    }
159    va_end(ap);
160    return interface_id;
161}
162
163bool pw_interface_exists(uint16_t interface_id)
164{
165    return interface_id < num_registered_interfaces;
166}
167
168char* pw_get_interface_name(uint16_t interface_id)
169{
170    if (interface_id >= num_registered_interfaces) {
171        pw_panic_interface_not_registered(interface_id);
172    }
173    return registered_interfaces[interface_id]->name;
174}
175
176unsigned _pw_get_num_interface_methods(uint16_t interface_id)
177{
178    if (interface_id >= num_registered_interfaces) {
179        pw_panic_interface_not_registered(interface_id);
180    }
181    return registered_interfaces[interface_id]->num_methods;
182}
183
184
185static PwInterface_Generic* find_interface_definition(PwType* type, uint16_t interface_id)
186// helper for _pw_make_interface
187{
188    unsigned n = type->num_interface_definitions;
189    if (n) {
190        PwInterface_Generic** idef = type->interface_definitions;
191        PwInterface_Generic** idef_end = idef + n;
192        while (idef < idef_end) {
193            if ((*idef)->id == interface_id) {
194                return *idef;
195            }
196            idef++;
197        }
198    }
199    return nullptr;
200}
201
202PwInterface_Generic* _pw_make_interface(PwType* type, uint16_t interface_id)
203{
204    if (interface_id >= num_registered_interfaces) {
205        pw_panic_interface_not_registered(interface_id);
206    }
207
208    InterfaceInfo* iinfo = registered_interfaces[interface_id];
209
210    // allocate and initialize interface structure
211
212    unsigned memsize = sizeof(PwInterface_Generic) + iinfo->num_methods * sizeof(PwMethod_Generic);
213    PwInterface_Generic* interface = _pw_arena_alloc_bytes(memsize, alignof(PwInterface_Generic));
214    interface->id           = interface_id;
215    interface->num_methods  = iinfo->num_methods;
216    interface->name         = iinfo->name;
217    interface->method_names = iinfo->method_names;
218    interface->type         = type;
219
220    // make interface methods
221
222    PwMethod_Generic* method = interface->methods;
223    PwMethod_Generic* method_end = method + interface->num_methods;
224    unsigned method_index = 0;
225    while (method < method_end) {
226        method->func  = nullptr;
227        method->super = nullptr;
228        method->self  = nullptr;
229        method->struct_offset = 0;
230        method->type_id = 0;
231
232        // build MRO chain
233
234        PwMethod_Generic* sub_method = method;  // current method in the chain
235        unsigned* struct_offset = type->struct_offsets;
236
237        PwInterface_Generic* idef = find_interface_definition(type, interface_id);
238
239        if (idef && idef->methods[method_index].func) {
240            // have func defined for this type
241            sub_method->func = idef->methods[method_index].func;
242            sub_method->self = interface;
243            sub_method->struct_offset = struct_offset? *struct_offset : 0;
244            sub_method->type_id = type->id;
245        }
246        struct_offset++;
247
248        PwType** base_type = type->base_types;
249        PwType** base_type_end = base_type + type->num_base_types;
250        while (base_type < base_type_end) {
251            PwType* t = *base_type;
252            idef = find_interface_definition(t, interface_id);
253
254            if (idef && idef->methods[method_index].func) {
255
256                // have super func
257
258                if (sub_method->func) {
259                    // sub_method already initialized, allocate new one
260                    PwMethod_Generic* super_method = _pw_arena_alloc(1, PwMethod_Generic);
261                    super_method->super = nullptr;
262                    sub_method->super = super_method;
263                    sub_method = super_method;
264                }
265                // initialize current method
266                sub_method->func = idef->methods[method_index].func;
267                sub_method->self = _pw_lookup_interface_t(t, interface_id);
268                if (!sub_method->self) {
269                    pw_panic("Interface %s must be initialized for %s\n", iinfo->name, t->name);
270                }
271                pw_assert(sub_method->self->type->id == t->id);
272                sub_method->struct_offset = struct_offset? *struct_offset : 0;
273                sub_method->type_id = type->id;
274            }
275            base_type++;
276            struct_offset++;
277        }
278        method++;
279        method_index++;
280    }
281    return interface;
282}