File Explorer

/var/runtime/node_modules/@aws-sdk/node_modules/aws-crt/source

This explorer reads the filesystem of the server it runs on, so /workspace/user isn't present here. Browsing and the terminal still work against this server's own disk from /.

1 dir
34 files
class_binder.c16.3 KB · 514 lines
/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include "class_binder.h" #ifdef _MSC_VER#    pragma warning(disable : 4204)#endif /* _MSC_VER */ struct aws_napi_class_info_impl {    const struct aws_napi_method_info *ctor_method;     napi_ref constructor;     struct {        void *instance;        napi_finalize finalizer;        bool is_wrapping;    } wrapping;}; /* Make sure our static storage is big enough */AWS_STATIC_ASSERT(sizeof(struct aws_napi_class_info) >= sizeof(struct aws_napi_class_info_impl)); /* * Populates an aws_napi_argument object from a napi value. * * \param env               The node environment. * \param value             The value to pull the value from. * \param expected_type     The type you expect the value to be. Pass napi_undefined to accept anything. * \param accept_undefined  Whether or not to accept expected_type OR undefined * \param out_value         The argument object to populate. */static napi_status s_argument_parse(    napi_env env,    napi_value value,    napi_valuetype expected_type,    bool accept_undefined,    struct aws_napi_argument *out_value) {     out_value->node = value;    AWS_NAPI_CALL(env, napi_typeof(env, value, &out_value->type), { return status; });     if (expected_type != napi_undefined && out_value->type != expected_type &&        !(accept_undefined && out_value->type == napi_undefined)) {        switch (expected_type) {            case napi_string:                napi_throw_type_error(env, NULL, "Class binder argument expected a string");                return napi_string_expected;             case napi_number:                napi_throw_type_error(env, NULL, "Class binder argument expected a number");                return napi_number_expected;             default:                napi_throw_type_error(env, NULL, "Class binder argument wrong type");                return napi_generic_failure;        }    }     switch (out_value->type) {        case napi_boolean: {            AWS_NAPI_CALL(env, napi_get_value_bool(env, value, &out_value->native.boolean), { return status; });             break;        }         case napi_string: {            AWS_NAPI_CALL(env, aws_byte_buf_init_from_napi(&out_value->native.string, env, value), { return status; });             break;        }         case napi_number: {            AWS_NAPI_CALL(env, napi_get_value_int64(env, value, &out_value->native.number), {                napi_throw_type_error(env, NULL, "Class binder argument expected a number");                return status;            });             break;        }         case napi_external: {            AWS_NAPI_CALL(env, napi_get_value_external(env, value, &out_value->native.external), {                napi_throw_type_error(env, NULL, "Class binder argument expected an external");                return status;            });             break;        }         case napi_object: {            /* Attempt to unwrap the object, just in case */            napi_status result = napi_unwrap(env, value, &out_value->native.external);            if (result != napi_ok) {                out_value->native.external = NULL;            }             break;        }         default:            /* Don't process, just leave as node value */            break;    }     return napi_ok;} /* * Cleans up an aws_napi_argument object populated by s_argument_parse. * * \param env           The node environment. * \param value         The value to clean up. */static void s_argument_cleanup(napi_env env, struct aws_napi_argument *value) {    (void)env;     switch (value->type) {        case napi_string:            aws_byte_buf_clean_up(&value->native.string);            break;         default:            break;    }} /* * Used as the class's constructor */static napi_value s_constructor(napi_env env, napi_callback_info info) {     napi_value node_args[AWS_NAPI_METHOD_MAX_ARGS];    napi_value node_this = NULL;    size_t num_args = AWS_ARRAY_SIZE(node_args);    struct aws_napi_class_info_impl *class_info = NULL;    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, node_args, &node_this, (void **)&class_info), {        napi_throw_error(env, NULL, "Failed to retreive callback information");        return NULL;    });    if (num_args > AWS_NAPI_METHOD_MAX_ARGS) {        num_args = AWS_NAPI_METHOD_MAX_ARGS;    }     napi_value result = NULL;     /* Check if we're wrapping an existing object or creating a new one */    if (class_info->wrapping.is_wrapping) {        AWS_FATAL_ASSERT(num_args == 0);         AWS_NAPI_CALL(            env,            napi_wrap(env, node_this, class_info->wrapping.instance, class_info->wrapping.finalizer, class_info, NULL),            {                napi_throw_error(env, NULL, "Failed to wrap http_request");                return NULL;            });     } else {        const struct aws_napi_method_info *method = class_info->ctor_method;         /* If there is no ctor method, don't both doing anything more, just return the empty object */        if (method->method) {            struct aws_napi_argument args[AWS_NAPI_METHOD_MAX_ARGS];            AWS_ZERO_ARRAY(args);             if (num_args < method->num_arguments) {                napi_throw_error(env, NULL, "Class binder constructor given incorrect number of arguments");                return NULL;            }             for (size_t i = 0; i < num_args; ++i) {                if (s_argument_parse(env, node_args[i], method->arg_types[i], i >= method->num_arguments, &args[i])) {                    goto cleanup_arguments;                }            }             struct aws_napi_callback_info cb_info = {                .node_this = node_this,                .native_this = node_this,                .num_args = num_args,            };            cb_info.arguments = args;             method->method(env, &cb_info);         cleanup_arguments:            for (size_t i = 0; i < method->num_arguments; ++i) {                s_argument_cleanup(env, &args[i]);            }        }    }     return result;} /* * Callback used to return the value of a property. Expects 0 arguments. */static napi_value s_property_getter(napi_env env, napi_callback_info info) {     void *native_this = NULL;     napi_value node_this = NULL;    size_t num_args = 0;    void *data = NULL;    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, NULL, &node_this, &data), {        napi_throw_error(env, NULL, "Failed to retreive callback information");        return NULL;    });    if (num_args != 0) {        napi_throw_error(env, NULL, "Class binder getter needs exactly 0 arguments");        return NULL;    }     AWS_NAPI_CALL(env, napi_unwrap(env, node_this, &native_this), {        napi_throw_error(env, NULL, "Class binder property getter must be called on a wrapped object");        return NULL;    });     const struct aws_napi_property_info *property = data;     if (!property->getter) {        napi_throw_error(env, NULL, "Property is not readable");        return NULL;    }     napi_value result = property->getter(env, native_this); #if DEBUG_BUILD    /* In debug builds, validate that getters are returning the correct type */    napi_valuetype result_type = napi_undefined;    AWS_NAPI_CALL(env, napi_typeof(env, result, &result_type), { return NULL; });    AWS_FATAL_ASSERT(property->type == napi_undefined || property->type == result_type);#endif     return result;} /* * Callback used to set the value of a property. Expects 1 argument. */static napi_value s_property_setter(napi_env env, napi_callback_info info) {     void *native_this = NULL;     napi_value node_this = NULL;    napi_value node_value;    size_t num_args = 1;    void *data = NULL;    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, &node_value, &node_this, &data), {        napi_throw_error(env, NULL, "Failed to retreive callback information");        return NULL;    });    if (num_args != 1) {        napi_throw_error(env, NULL, "Class binder setter needs exactly 1 arguments");        return NULL;    }     AWS_NAPI_CALL(env, napi_unwrap(env, node_this, &native_this), {        napi_throw_error(env, NULL, "Class binder setter must be called on instance of a wrapped object");        return NULL;    });     const struct aws_napi_property_info *property = data;     if (!property->setter) {        napi_throw_error(env, NULL, "Property is not writable");        return NULL;    }     struct aws_napi_argument new_value;    if (s_argument_parse(env, node_value, property->type, false, &new_value)) {        return NULL;    }     property->setter(env, native_this, &new_value);     s_argument_cleanup(env, &new_value);     return NULL;} /* * Callback used to call a method on a bound object. */static napi_value s_method_call(napi_env env, napi_callback_info info) {     void *native_this = NULL;    struct aws_napi_argument args[AWS_NAPI_METHOD_MAX_ARGS];    AWS_ZERO_ARRAY(args);     napi_value node_this = NULL;    napi_value node_args[AWS_NAPI_METHOD_MAX_ARGS];    size_t num_args = AWS_ARRAY_SIZE(node_args);    void *data = NULL;    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, node_args, &node_this, &data), {        napi_throw_error(env, NULL, "Failed to retreive callback information");        return NULL;    });    if (num_args > AWS_NAPI_METHOD_MAX_ARGS) {        num_args = AWS_NAPI_METHOD_MAX_ARGS;    }     struct aws_napi_method_info *method = data;    if (num_args < method->num_arguments) {        napi_throw_error(env, NULL, "Bound class's method requires more arguments");        return NULL;    }     if ((method->attributes & napi_static) == 0) {        AWS_NAPI_CALL(env, napi_unwrap(env, node_this, &native_this), {            napi_throw_error(env, NULL, "Bound class's method must be called on instance of the class");            return NULL;        });    }     napi_value result = NULL;     for (size_t i = 0; i < num_args; ++i) {        if (s_argument_parse(env, node_args[i], method->arg_types[i], i >= method->num_arguments, &args[i])) {            goto cleanup_arguments;        }    }     struct aws_napi_callback_info cb_info = {        .node_this = node_this,        .native_this = native_this,        .num_args = num_args,    };    cb_info.arguments = args;     result = method->method(env, &cb_info); cleanup_arguments:    for (size_t i = 0; i < num_args; ++i) {        s_argument_cleanup(env, &args[i]);    }    return result;} bool aws_napi_method_next_argument(    napi_valuetype expected_type,    const struct aws_napi_callback_info *cb_info,    const struct aws_napi_argument **next_arg) {     if (!*next_arg) {        *next_arg = cb_info->arguments;    } else {        (*next_arg)++;    }     const size_t current_index = (*next_arg) - cb_info->arguments;    return current_index <= cb_info->num_args &&           ((expected_type == napi_undefined && (*next_arg)->type != napi_undefined) ||            (expected_type == (*next_arg)->type));} static napi_status s_get_symbol(napi_env env, const char *symbol_name, napi_value *result) {    napi_value global = NULL;    AWS_NAPI_CALL(env, napi_get_global(env, &global), { return status; });     napi_value symbol = NULL;    AWS_NAPI_CALL(env, napi_get_named_property(env, global, "Symbol", &symbol), { return status; });    AWS_NAPI_CALL(env, napi_get_named_property(env, symbol, symbol_name, result), { return status; });     return napi_ok;} napi_status aws_napi_define_class(    napi_env env,    napi_value exports,    const struct aws_napi_method_info *constructor,    const struct aws_napi_property_info *properties,    size_t num_properties,    const struct aws_napi_method_info *methods,    size_t num_methods,    struct aws_napi_class_info *class_info) {     AWS_FATAL_ASSERT(constructor->name);    AWS_FATAL_ASSERT(constructor->attributes == napi_default);     struct aws_napi_class_info_impl *impl = (struct aws_napi_class_info_impl *)class_info;    impl->ctor_method = constructor;     struct aws_allocator *allocator = aws_napi_get_allocator();     const size_t num_descriptors = num_properties + num_methods;    napi_property_descriptor *descriptors =        aws_mem_calloc(allocator, num_descriptors, sizeof(napi_property_descriptor));     size_t desc_i = 0;     for (size_t prop_i = 0; prop_i < num_properties; ++prop_i) {        napi_property_descriptor *desc = &descriptors[desc_i++];        const struct aws_napi_property_info *property = &properties[prop_i];         AWS_FATAL_ASSERT(property->name || property->symbol);        AWS_FATAL_ASSERT(property->getter || property->setter);         if (property->symbol) {            AWS_NAPI_CALL(env, s_get_symbol(env, property->symbol, &desc->name), { return status; });        } else {            desc->utf8name = property->name;        }        desc->data = (void *)property;        desc->getter = s_property_getter;        desc->setter = s_property_setter;        desc->attributes = property->attributes;    }     for (size_t method_i = 0; method_i < num_methods; ++method_i) {        napi_property_descriptor *desc = &descriptors[desc_i++];        const struct aws_napi_method_info *method = &methods[method_i];         AWS_FATAL_ASSERT(method->name || method->symbol);        AWS_FATAL_ASSERT(method->method);         if (method->symbol) {            AWS_NAPI_CALL(env, s_get_symbol(env, method->symbol, &desc->name), { return status; });        } else {            desc->utf8name = method->name;        }        desc->data = (void *)method;        desc->method = s_method_call;        desc->attributes = method->attributes;    }     napi_value node_constructor = NULL;    AWS_NAPI_CALL(        env,        napi_define_class(            env,            constructor->name,            NAPI_AUTO_LENGTH,            s_constructor,            class_info,            num_descriptors,            descriptors,            &node_constructor),        { return status; });     /* Don't need descriptors anymore */    aws_mem_release(allocator, descriptors);     /* Reference the constructor for later user */    AWS_NAPI_CALL(env, napi_create_reference(env, node_constructor, 1, &impl->constructor), { return status; });     AWS_NAPI_CALL(env, napi_set_named_property(env, exports, constructor->name, node_constructor), { return status; });     return napi_ok;} napi_status aws_napi_wrap(    napi_env env,    struct aws_napi_class_info *class_info,    void *native,    napi_finalize finalizer,    napi_value *result) {     struct aws_napi_class_info_impl *impl = (struct aws_napi_class_info_impl *)class_info;     /* Retrieve the constructor */    napi_value constructor = NULL;    AWS_NAPI_CALL(env, napi_get_reference_value(env, impl->constructor, &constructor), {        napi_throw_error(env, NULL, "Failed to dereference constructor value");        return status;    });     /* Set our handy-dandy global state */    impl->wrapping.is_wrapping = true;    impl->wrapping.instance = native;    impl->wrapping.finalizer = finalizer;    AWS_NAPI_CALL(env, napi_new_instance(env, constructor, 0, NULL, result), {        napi_throw_error(env, NULL, "Failed to construct class-bound object");        return status;    });    AWS_ZERO_STRUCT(impl->wrapping);     /* The constructor function will have called napi_wrap onto result */     return napi_ok;} napi_status aws_napi_define_function(napi_env env, napi_value exports, struct aws_napi_method_info *method) {     /* Set static attribute so that s_method_call doesn't try to unwrap the this object */    method->attributes = napi_static;     /* Create the function object */    napi_value node_function = NULL;    AWS_NAPI_CALL(        env, napi_create_function(env, method->name, NAPI_AUTO_LENGTH, s_method_call, method, &node_function), {            return status;        });     /* Initialize the name from the symbol if necessary, otherwise use the utf8 name */    napi_value node_name = NULL;    if (method->symbol) {        AWS_NAPI_CALL(env, s_get_symbol(env, method->symbol, &node_name), { return status; });    } else {        AWS_NAPI_CALL(            env, napi_create_string_utf8(env, method->name, NAPI_AUTO_LENGTH, &node_name), { return status; });    }     /* Export the function */    AWS_NAPI_CALL(env, napi_set_property(env, exports, node_name, node_function), { return status; });     return napi_ok;}