1#include "include/pw.h"
  2
  3bool _pw_get(PwValuePtr result, PwValuePtr container, ...)
  4{
  5    PwValue obj = pw_clone(container);
  6    va_list ap;
  7    va_start(ap);
  8    for (;;) {
  9        char8_t* key = va_arg(ap, char8_t*);
 10        if (key == nullptr) {
 11            va_end(ap);
 12            return true;
 13        }
 14        pw_destroy(result);
 15
 16        // get RandomAccess interface
 17        PwInterface_RandomAccess* interface = pw_lookup_interface(obj.type_id, RandomAccess);
 18        if (!interface) {
 19            va_end(ap);
 20            pw_set_status(PwStatus(PW_ERROR_KEY_NOT_FOUND));
 21            return false;
 22        }
 23
 24        // get value by key
 25        PwValue k = PW_NULL;
 26        if (!pw_create_string(&k, key)) {
 27            va_end(ap);
 28            return false;
 29        }
 30        if (!pw_call2(interface, get_item, &obj, &k, result)) {
 31            va_end(ap);
 32            return false;
 33        }
 34
 35        // go to the deeper object
 36        pw_clone2(&obj, result);
 37    }
 38}
 39
 40bool _pw_set(PwValuePtr container, ...)
 41{
 42    PwValue obj = pw_clone(container);
 43    va_list ap;
 44    va_start(ap);
 45
 46    // get first key
 47    char8_t* key = va_arg(ap, char8_t*);
 48    if (key == nullptr) {
 49        va_end(ap);
 50        pw_set_status(PwStatus(PW_ERROR_KEY_NOT_FOUND));
 51        return false;
 52    }
 53    // get next argument that could be the last one, a value to set
 54    void* last_arg = va_arg(ap, void*);
 55    for (;;) {
 56        void* arg = va_arg(ap, void*);
 57        if (arg == nullptr) {
 58            break;
 59        }
 60        // arg becomes last_arg and last_arg eas the next key
 61        char8_t* next_key = last_arg;
 62        last_arg = arg;
 63        // get RandomAccess interface
 64        PwInterface_RandomAccess* interface = pw_lookup_interface(obj.type_id, RandomAccess);
 65        if (!interface) {
 66            pw_set_status(PwStatus(PW_ERROR_KEY_NOT_FOUND));
 67            va_end(ap);
 68            return false;
 69        }
 70
 71        // get nested object by key
 72        PwValue k = PW_NULL;
 73        if (!pw_create_string(&k, key)) {
 74            va_end(ap);
 75            return false;
 76        }
 77        PwValue nested_obj = PW_NULL;
 78        if (!pw_call2(interface, get_item, &obj, &k, &nested_obj)) {
 79            va_end(ap);
 80            return false;
 81        }
 82        // go to the deeper object
 83        pw_move(&obj, &nested_obj);
 84        key = next_key;
 85    }
 86    va_end(ap);
 87
 88    // set value
 89    PwValuePtr value = last_arg;
 90    PwInterface_RandomAccess* interface = pw_lookup_interface(obj.type_id, RandomAccess);
 91    if (!interface) {
 92        pw_set_status(PwStatus(PW_ERROR_KEY_NOT_FOUND));
 93        return false;
 94    }
 95    PwValue k = PW_NULL;
 96    if (!pw_create_string(&k, key)) {
 97        return false;
 98    }
 99    return pw_call2(interface, set_item, &obj, &k, value);
100}