blob: ddea784e9353b397bd79110b15b3d675d6079bc7 [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
* Copyright (C) NGINX, Inc.
*/
#ifndef _NJS_OBJECT_H_INCLUDED_
#define _NJS_OBJECT_H_INCLUDED_
typedef enum {
NJS_OBJECT_PROP_DESCRIPTOR,
NJS_OBJECT_PROP_GETTER,
NJS_OBJECT_PROP_SETTER,
} njs_object_prop_define_t;
struct njs_object_init_s {
const njs_object_prop_t *properties;
njs_uint_t items;
};
typedef struct njs_traverse_s njs_traverse_t;
struct njs_traverse_s {
struct njs_traverse_s *parent;
njs_object_prop_t *prop;
njs_object_t *object;
njs_lvlhsh_t *hash;
njs_lvlhsh_each_t lhe;
#define NJS_TRAVERSE_MAX_DEPTH 32
};
typedef njs_int_t (*njs_object_traverse_cb_t)(njs_vm_t *vm,
njs_traverse_t *traverse, void *ctx);
njs_object_t *njs_object_alloc(njs_vm_t *vm);
njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value);
njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value,
njs_uint_t type);
njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object,
njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object,
njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
njs_int_t njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
njs_object_traverse_cb_t cb);
njs_int_t njs_object_hash_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
const njs_object_prop_t *prop, njs_uint_t n);
njs_int_t njs_primitive_prototype_get_proto(njs_vm_t *vm,
njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
njs_value_t *retval);
njs_int_t njs_object_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
njs_value_t *njs_property_prototype_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
njs_object_t *prototype);
njs_int_t njs_object_prototype_proto(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
njs_int_t njs_object_prototype_create_constructor(njs_vm_t *vm,
njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
njs_value_t *retval);
njs_value_t *njs_property_constructor_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
njs_value_t *constructor);
njs_int_t njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
njs_int_t njs_object_length(njs_vm_t *vm, njs_value_t *value, int64_t *dst);
njs_int_t njs_prop_private_copy(njs_vm_t *vm, njs_property_query_t *pq);
njs_object_prop_t *njs_object_prop_alloc(njs_vm_t *vm, const njs_value_t *name,
const njs_value_t *value, uint8_t attributes);
njs_int_t njs_object_property(njs_vm_t *vm, const njs_value_t *value,
njs_lvlhsh_query_t *lhq, njs_value_t *retval);
njs_object_prop_t *njs_object_property_add(njs_vm_t *vm, njs_value_t *object,
njs_value_t *key, njs_bool_t replace);
njs_int_t njs_object_prop_define(njs_vm_t *vm, njs_value_t *object,
njs_value_t *name, njs_value_t *value, njs_object_prop_define_t type);
njs_int_t njs_object_prop_descriptor(njs_vm_t *vm, njs_value_t *dest,
njs_value_t *value, njs_value_t *setval);
const char *njs_prop_type_string(njs_object_prop_type_t type);
njs_int_t njs_object_prop_init(njs_vm_t *vm, const njs_object_init_t* init,
const njs_object_prop_t *base, njs_value_t *value, njs_value_t *retval);
njs_inline njs_bool_t
njs_is_data_descriptor(njs_object_prop_t *prop)
{
return prop->writable != NJS_ATTRIBUTE_UNSET || njs_is_valid(&prop->value);
}
njs_inline njs_bool_t
njs_is_accessor_descriptor(njs_object_prop_t *prop)
{
return njs_is_function_or_undefined(&prop->getter)
|| njs_is_function_or_undefined(&prop->setter);
}
njs_inline njs_bool_t
njs_is_generic_descriptor(njs_object_prop_t *prop)
{
return !njs_is_data_descriptor(prop) && !njs_is_accessor_descriptor(prop);
}
njs_inline void
njs_object_property_key_set(njs_lvlhsh_query_t *lhq, const njs_value_t *key,
uint32_t hash)
{
if (njs_is_symbol(key)) {
lhq->key.length = 0;
lhq->key.start = NULL;
lhq->key_hash = njs_symbol_key(key);
} else {
/* string. */
njs_string_get(key, &lhq->key);
if (hash == 0) {
lhq->key_hash = njs_djb_hash(lhq->key.start, lhq->key.length);
} else {
lhq->key_hash = hash;
}
}
}
njs_inline void
njs_object_property_init(njs_lvlhsh_query_t *lhq, const njs_value_t *key,
uint32_t hash)
{
lhq->proto = &njs_object_hash_proto;
njs_object_property_key_set(lhq, key, hash);
}
njs_inline njs_int_t
njs_primitive_value_to_key(njs_vm_t *vm, njs_value_t *dst,
const njs_value_t *src)
{
const njs_value_t *value;
switch (src->type) {
case NJS_NULL:
value = &njs_string_null;
break;
case NJS_UNDEFINED:
value = &njs_string_undefined;
break;
case NJS_BOOLEAN:
value = njs_is_true(src) ? &njs_string_true : &njs_string_false;
break;
case NJS_NUMBER:
return njs_number_to_string(vm, dst, src);
case NJS_SYMBOL:
case NJS_STRING:
/* GC: njs_retain(src); */
value = src;
break;
default:
return NJS_ERROR;
}
*dst = *value;
return NJS_OK;
}
njs_inline njs_int_t
njs_value_to_key(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
{
njs_int_t ret;
njs_value_t primitive;
if (njs_slow_path(!njs_is_primitive(value))) {
if (njs_slow_path(value->type == NJS_OBJECT_SYMBOL)) {
/* should fail */
value = njs_object_value(value);
} else {
ret = njs_value_to_primitive(vm, &primitive, value, 1);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
value = &primitive;
}
}
return njs_primitive_value_to_key(vm, dst, value);
}
njs_inline njs_int_t
njs_key_string_get(njs_vm_t *vm, njs_value_t *key, njs_str_t *str)
{
njs_int_t ret;
if (njs_slow_path(njs_is_symbol(key))) {
ret = njs_symbol_descriptive_string(vm, key, key);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
}
njs_string_get(key, str);
return NJS_OK;
}
njs_inline njs_int_t
njs_object_length_set(njs_vm_t *vm, njs_value_t *value, int64_t length)
{
njs_value_t index;
static const njs_value_t string_length = njs_string("length");
njs_value_number_set(&index, length);
return njs_value_property_set(vm, value, njs_value_arg(&string_length),
&index);
}
njs_inline njs_int_t
njs_object_string_tag(njs_vm_t *vm, njs_value_t *value, njs_value_t *tag)
{
njs_int_t ret;
static const njs_value_t to_string_tag =
njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG);
ret = njs_value_property(vm, value, njs_value_arg(&to_string_tag), tag);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
if (!njs_is_string(tag)) {
return NJS_DECLINED;
}
return NJS_OK;
}
njs_inline njs_object_t *
_njs_object_proto_lookup(njs_object_t *proto, njs_value_type_t type)
{
do {
if (njs_fast_path(proto->type == type)) {
break;
}
proto = proto->__proto__;
} while (proto != NULL);
return proto;
}
#define njs_object_proto_lookup(proto, vtype, ctype) \
(ctype *) _njs_object_proto_lookup(proto, vtype)
extern const njs_object_type_init_t njs_obj_type_init;
#endif /* _NJS_OBJECT_H_INCLUDED_ */