fx.reflection: update iterator semantics
This commit is contained in:
+64
-48
@@ -71,10 +71,12 @@ struct fx_assembly_p {
|
|||||||
|
|
||||||
struct fx_assembly_iterator_p {
|
struct fx_assembly_iterator_p {
|
||||||
fx_namemap_entry *it_cur;
|
fx_namemap_entry *it_cur;
|
||||||
|
fx_value it_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fx_assembly_type_iterator_p {
|
struct fx_assembly_type_iterator_p {
|
||||||
struct type *it_item;
|
struct type *it_item;
|
||||||
|
fx_value it_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||||
@@ -165,11 +167,11 @@ static struct map_item *map_item_next(struct map_item *item)
|
|||||||
struct map_bucket *bucket = item->i_entry.e_bucket;
|
struct map_bucket *bucket = item->i_entry.e_bucket;
|
||||||
struct map_entry *next_item = NULL;
|
struct map_entry *next_item = NULL;
|
||||||
if (bucket) {
|
if (bucket) {
|
||||||
struct fx_queue_entry *q_item = fx_queue_next(
|
struct fx_queue_entry *q_item
|
||||||
&item->i_entry.e_entry);
|
= fx_queue_next(&item->i_entry.e_entry);
|
||||||
if (!q_item) {
|
if (!q_item) {
|
||||||
struct fx_bst_node *node = fx_bst_next(
|
struct fx_bst_node *node
|
||||||
&bucket->b_entry.e_node);
|
= fx_bst_next(&bucket->b_entry.e_node);
|
||||||
next_item = fx_unbox(struct map_entry, node, e_node);
|
next_item = fx_unbox(struct map_entry, node, e_node);
|
||||||
} else {
|
} else {
|
||||||
next_item = fx_unbox(struct map_entry, q_item, e_entry);
|
next_item = fx_unbox(struct map_entry, q_item, e_entry);
|
||||||
@@ -185,8 +187,8 @@ static struct map_item *map_item_next(struct map_item *item)
|
|||||||
|
|
||||||
if (next_item->e_type == MAP_ENTRY_BUCKET) {
|
if (next_item->e_type == MAP_ENTRY_BUCKET) {
|
||||||
bucket = (struct map_bucket *)next_item;
|
bucket = (struct map_bucket *)next_item;
|
||||||
struct fx_queue_entry *q_item = fx_queue_first(
|
struct fx_queue_entry *q_item
|
||||||
&bucket->b_items);
|
= fx_queue_first(&bucket->b_items);
|
||||||
next_item = fx_unbox(struct map_entry, q_item, e_entry);
|
next_item = fx_unbox(struct map_entry, q_item, e_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,10 +257,8 @@ static void assembly_dump(struct fx_assembly_p *assembly)
|
|||||||
|
|
||||||
fx_bst_node *cur_node = fx_bst_first(&assembly->a_types.m_entries);
|
fx_bst_node *cur_node = fx_bst_first(&assembly->a_types.m_entries);
|
||||||
while (cur_node) {
|
while (cur_node) {
|
||||||
struct map_entry *entry = fx_unbox(
|
struct map_entry *entry
|
||||||
struct map_entry,
|
= fx_unbox(struct map_entry, cur_node, e_node);
|
||||||
cur_node,
|
|
||||||
e_node);
|
|
||||||
switch (entry->e_type) {
|
switch (entry->e_type) {
|
||||||
case MAP_ENTRY_ITEM: {
|
case MAP_ENTRY_ITEM: {
|
||||||
struct map_item *item = (struct map_item *)entry;
|
struct map_item *item = (struct map_item *)entry;
|
||||||
@@ -268,8 +268,8 @@ static void assembly_dump(struct fx_assembly_p *assembly)
|
|||||||
|
|
||||||
case MAP_ENTRY_BUCKET: {
|
case MAP_ENTRY_BUCKET: {
|
||||||
struct map_bucket *bucket = (struct map_bucket *)entry;
|
struct map_bucket *bucket = (struct map_bucket *)entry;
|
||||||
fx_queue_entry *cur_qentry = fx_queue_first(
|
fx_queue_entry *cur_qentry
|
||||||
&bucket->b_items);
|
= fx_queue_first(&bucket->b_items);
|
||||||
while (cur_qentry) {
|
while (cur_qentry) {
|
||||||
struct map_item *item = fx_unbox(
|
struct map_item *item = fx_unbox(
|
||||||
struct map_item,
|
struct map_item,
|
||||||
@@ -289,8 +289,8 @@ static void assembly_dump(struct fx_assembly_p *assembly)
|
|||||||
|
|
||||||
static fx_iterator *assembly_get_types(const struct fx_assembly_p *assembly)
|
static fx_iterator *assembly_get_types(const struct fx_assembly_p *assembly)
|
||||||
{
|
{
|
||||||
fx_assembly_type_iterator *it = fx_object_create(
|
fx_assembly_type_iterator *it
|
||||||
fx_assembly_type_iterator_get_type());
|
= fx_object_create(fx_assembly_type_iterator_get_type());
|
||||||
if (!it) {
|
if (!it) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -299,12 +299,15 @@ static fx_iterator *assembly_get_types(const struct fx_assembly_p *assembly)
|
|||||||
it,
|
it,
|
||||||
fx_assembly_type_iterator_get_type());
|
fx_assembly_type_iterator_get_type());
|
||||||
struct map_item *item = map_first_item(&assembly->a_types);
|
struct map_item *item = map_first_item(&assembly->a_types);
|
||||||
if (item) {
|
if (!item) {
|
||||||
it_p->it_item = fx_unbox(struct type, item, e_map_item);
|
|
||||||
} else {
|
|
||||||
fx_iterator_set_status(it, FX_ERR_NO_DATA);
|
fx_iterator_set_status(it, FX_ERR_NO_DATA);
|
||||||
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it_p->it_item = fx_unbox(struct type, item, e_map_item);
|
||||||
|
const fx_type *ty = fx_type_get_by_id(it_p->it_item->e_type);
|
||||||
|
it_p->it_value = FX_VALUE_OBJECT_REF(ty);
|
||||||
|
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,20 +344,25 @@ static void assembly_get_version(
|
|||||||
|
|
||||||
fx_iterator *fx_assembly_get_all(void)
|
fx_iterator *fx_assembly_get_all(void)
|
||||||
{
|
{
|
||||||
fx_assembly_iterator *it = fx_object_create(
|
fx_assembly_iterator *it
|
||||||
fx_assembly_iterator_get_type());
|
= fx_object_create(fx_assembly_iterator_get_type());
|
||||||
if (!it) {
|
if (!it) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fx_assembly_iterator_p *it_p = fx_object_get_private(
|
struct fx_assembly_iterator_p *it_p
|
||||||
it,
|
= fx_object_get_private(it, fx_assembly_iterator_get_type());
|
||||||
fx_assembly_iterator_get_type());
|
|
||||||
it_p->it_cur = fx_namemap_first(&assembly_map);
|
it_p->it_cur = fx_namemap_first(&assembly_map);
|
||||||
if (!it_p->it_cur) {
|
if (!it_p->it_cur) {
|
||||||
fx_iterator_set_status(it, FX_ERR_NO_DATA);
|
fx_iterator_set_status(it, FX_ERR_NO_DATA);
|
||||||
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fx_assembly_p *assembly
|
||||||
|
= fx_unbox(struct fx_assembly_p, it_p->it_cur, a_entry);
|
||||||
|
|
||||||
|
it_p->it_value = FX_VALUE_OBJECT_REF(assembly->a_self);
|
||||||
|
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,10 +373,8 @@ const fx_assembly *fx_assembly_get_by_name(const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fx_assembly_p *assembly = fx_unbox(
|
struct fx_assembly_p *assembly
|
||||||
struct fx_assembly_p,
|
= fx_unbox(struct fx_assembly_p, entry, a_entry);
|
||||||
entry,
|
|
||||||
a_entry);
|
|
||||||
return assembly->a_self;
|
return assembly->a_self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,51 +489,61 @@ static enum fx_status type_iterator_move_next(const fx_iterator *obj)
|
|||||||
return FX_ERR_NO_DATA;
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fx_value_unset(&it->it_value);
|
||||||
struct map_item *next = map_item_next(&it->it_item->e_map_item);
|
struct map_item *next = map_item_next(&it->it_item->e_map_item);
|
||||||
it->it_item = fx_unbox(struct type, next, e_map_item);
|
it->it_item = fx_unbox(struct type, next, e_map_item);
|
||||||
return it->it_item ? FX_SUCCESS : FX_ERR_NO_DATA;
|
if (!it->it_item) {
|
||||||
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fx_value type_iterator_get_value(const fx_iterator *obj)
|
const fx_type *ty = fx_type_get_by_id(it->it_item->e_type);
|
||||||
|
it->it_value = FX_VALUE_OBJECT_REF(ty);
|
||||||
|
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fx_value *type_iterator_get_value(const fx_iterator *obj)
|
||||||
{
|
{
|
||||||
struct fx_assembly_type_iterator_p *it = fx_object_get_private(
|
struct fx_assembly_type_iterator_p *it = fx_object_get_private(
|
||||||
obj,
|
obj,
|
||||||
fx_assembly_type_iterator_get_type());
|
fx_assembly_type_iterator_get_type());
|
||||||
if (!it->it_item) {
|
if (!it->it_item) {
|
||||||
return FX_VALUE_EMPTY;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fx_type *ty = fx_type_get_by_id(it->it_item->e_type);
|
return &it->it_value;
|
||||||
return FX_VALUE_OBJECT(ty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum fx_status assembly_iterator_move_next(const fx_iterator *obj)
|
static enum fx_status assembly_iterator_move_next(const fx_iterator *obj)
|
||||||
{
|
{
|
||||||
struct fx_assembly_iterator_p *it = fx_object_get_private(
|
struct fx_assembly_iterator_p *it
|
||||||
obj,
|
= fx_object_get_private(obj, fx_assembly_iterator_get_type());
|
||||||
fx_assembly_iterator_get_type());
|
|
||||||
if (!it->it_cur) {
|
if (!it->it_cur) {
|
||||||
return FX_ERR_NO_DATA;
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fx_value_unset(&it->it_value);
|
||||||
it->it_cur = fx_namemap_next(&assembly_map, it->it_cur);
|
it->it_cur = fx_namemap_next(&assembly_map, it->it_cur);
|
||||||
return it->it_cur ? FX_SUCCESS : FX_ERR_NO_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
static fx_value assembly_iterator_get_value(const fx_iterator *obj)
|
|
||||||
{
|
|
||||||
struct fx_assembly_iterator_p *it = fx_object_get_private(
|
|
||||||
obj,
|
|
||||||
fx_assembly_iterator_get_type());
|
|
||||||
if (!it->it_cur) {
|
if (!it->it_cur) {
|
||||||
return FX_VALUE_EMPTY;
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fx_assembly_p *assembly = fx_unbox(
|
struct fx_assembly_p *assembly
|
||||||
struct fx_assembly_p,
|
= fx_unbox(struct fx_assembly_p, it->it_cur, a_entry);
|
||||||
it->it_cur,
|
|
||||||
a_entry);
|
it->it_value = FX_VALUE_OBJECT_REF(assembly->a_self);
|
||||||
return FX_VALUE_OBJECT(assembly->a_self);
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fx_value *assembly_iterator_get_value(const fx_iterator *obj)
|
||||||
|
{
|
||||||
|
struct fx_assembly_iterator_p *it
|
||||||
|
= fx_object_get_private(obj, fx_assembly_iterator_get_type());
|
||||||
|
if (!it->it_cur) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &it->it_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** CLASS DEFINITION *********************************************************/
|
/*** CLASS DEFINITION *********************************************************/
|
||||||
|
|||||||
+47
-31
@@ -31,12 +31,14 @@ struct fx_type_p {
|
|||||||
struct fx_type_function_iterator_p {
|
struct fx_type_function_iterator_p {
|
||||||
struct fx_namemap *it_src;
|
struct fx_namemap *it_src;
|
||||||
struct fx_namemap_entry *it_cur;
|
struct fx_namemap_entry *it_cur;
|
||||||
|
fx_value it_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fx_type_property_iterator_p {
|
struct fx_type_property_iterator_p {
|
||||||
const fx_type_info *it_cur_type;
|
const fx_type_info *it_cur_type;
|
||||||
struct fx_namemap *it_src;
|
struct fx_namemap *it_src;
|
||||||
struct fx_namemap_entry *it_cur;
|
struct fx_namemap_entry *it_cur;
|
||||||
|
fx_value it_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||||
@@ -77,8 +79,8 @@ const fx_function *type_get_function(
|
|||||||
|
|
||||||
fx_iterator *type_get_functions(const struct fx_type_p *ty)
|
fx_iterator *type_get_functions(const struct fx_type_p *ty)
|
||||||
{
|
{
|
||||||
fx_type_function_iterator *it_obj = fx_object_create(
|
fx_type_function_iterator *it_obj
|
||||||
FX_REFLECTION_TYPE_TYPE_FUNCTION_ITERATOR);
|
= fx_object_create(FX_REFLECTION_TYPE_TYPE_FUNCTION_ITERATOR);
|
||||||
struct fx_type_function_iterator_p *it = fx_object_get_private(
|
struct fx_type_function_iterator_p *it = fx_object_get_private(
|
||||||
it_obj,
|
it_obj,
|
||||||
FX_REFLECTION_TYPE_TYPE_FUNCTION_ITERATOR);
|
FX_REFLECTION_TYPE_TYPE_FUNCTION_ITERATOR);
|
||||||
@@ -95,9 +97,8 @@ const fx_property *type_get_property(
|
|||||||
{
|
{
|
||||||
struct fx_type_info *cur = ty->ty_info;
|
struct fx_type_info *cur = ty->ty_info;
|
||||||
while (cur) {
|
while (cur) {
|
||||||
const fx_property *prop = fx_type_info_get_property_by_name(
|
const fx_property *prop
|
||||||
cur,
|
= fx_type_info_get_property_by_name(cur, name);
|
||||||
name);
|
|
||||||
if (prop) {
|
if (prop) {
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
@@ -114,8 +115,8 @@ const fx_property *type_get_property(
|
|||||||
|
|
||||||
static fx_iterator *type_get_properties(const struct fx_type_p *ty)
|
static fx_iterator *type_get_properties(const struct fx_type_p *ty)
|
||||||
{
|
{
|
||||||
fx_type_property_iterator *it_obj = fx_object_create(
|
fx_type_property_iterator *it_obj
|
||||||
FX_REFLECTION_TYPE_TYPE_PROPERTY_ITERATOR);
|
= fx_object_create(FX_REFLECTION_TYPE_TYPE_PROPERTY_ITERATOR);
|
||||||
struct fx_type_property_iterator_p *it = fx_object_get_private(
|
struct fx_type_property_iterator_p *it = fx_object_get_private(
|
||||||
it_obj,
|
it_obj,
|
||||||
FX_REFLECTION_TYPE_TYPE_PROPERTY_ITERATOR);
|
FX_REFLECTION_TYPE_TYPE_PROPERTY_ITERATOR);
|
||||||
@@ -129,8 +130,9 @@ static fx_iterator *type_get_properties(const struct fx_type_p *ty)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct fx_type_info *next_type = fx_type_info_get_by_id(
|
const struct fx_type_info *next_type
|
||||||
&it->it_cur_type->ty_parent_id);
|
= fx_type_info_get_by_id(&it->it_cur_type
|
||||||
|
->ty_parent_id);
|
||||||
if (!next_type) {
|
if (!next_type) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -143,6 +145,10 @@ static fx_iterator *type_get_properties(const struct fx_type_p *ty)
|
|||||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fx_type_property *prop
|
||||||
|
= fx_unbox(struct fx_type_property, it->it_cur, p_entry);
|
||||||
|
it->it_value = FX_VALUE_OBJECT_REF(prop->p_prop);
|
||||||
|
|
||||||
return it_obj;
|
return it_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,9 +182,8 @@ fx_type *__fx_type_create(struct fx_type_info *type_info)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fx_type_p *p = fx_object_get_private(
|
struct fx_type_p *p
|
||||||
out,
|
= fx_object_get_private(out, FX_REFLECTION_TYPE_TYPE);
|
||||||
FX_REFLECTION_TYPE_TYPE);
|
|
||||||
p->ty_info = type_info;
|
p->ty_info = type_info;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
@@ -300,25 +305,29 @@ static enum fx_status function_iterator_move_next(const fx_iterator *obj)
|
|||||||
return FX_ERR_NO_DATA;
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fx_value_unset(&it->it_value);
|
||||||
it->it_cur = fx_namemap_next(it->it_src, it->it_cur);
|
it->it_cur = fx_namemap_next(it->it_src, it->it_cur);
|
||||||
return it->it_cur ? FX_SUCCESS : FX_ERR_NO_DATA;
|
if (!it->it_cur) {
|
||||||
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fx_value function_iterator_get_value(const fx_iterator *obj)
|
struct fx_type_function *func
|
||||||
|
= fx_unbox(struct fx_type_function, it->it_cur, f_entry);
|
||||||
|
it->it_value = FX_VALUE_OBJECT_REF(func->f_func);
|
||||||
|
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fx_value *function_iterator_get_value(const fx_iterator *obj)
|
||||||
{
|
{
|
||||||
struct fx_type_function_iterator_p *it = fx_object_get_private(
|
struct fx_type_function_iterator_p *it = fx_object_get_private(
|
||||||
obj,
|
obj,
|
||||||
FX_REFLECTION_TYPE_TYPE_FUNCTION_ITERATOR);
|
FX_REFLECTION_TYPE_TYPE_FUNCTION_ITERATOR);
|
||||||
if (!it->it_cur) {
|
if (!it->it_cur) {
|
||||||
return FX_VALUE_EMPTY;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fx_type_function *func = fx_unbox(
|
return &it->it_value;
|
||||||
struct fx_type_function,
|
|
||||||
it->it_cur,
|
|
||||||
f_entry);
|
|
||||||
|
|
||||||
return FX_VALUE_OBJECT(func->f_func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum fx_status property_iterator_move_next(const fx_iterator *obj)
|
static enum fx_status property_iterator_move_next(const fx_iterator *obj)
|
||||||
@@ -337,8 +346,9 @@ static enum fx_status property_iterator_move_next(const fx_iterator *obj)
|
|||||||
return FX_ERR_NO_DATA;
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct fx_type_info *next_type = fx_type_info_get_by_id(
|
const struct fx_type_info *next_type
|
||||||
&it->it_cur_type->ty_parent_id);
|
= fx_type_info_get_by_id(&it->it_cur_type
|
||||||
|
->ty_parent_id);
|
||||||
if (!next_type) {
|
if (!next_type) {
|
||||||
return FX_ERR_NO_DATA;
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
@@ -347,24 +357,30 @@ static enum fx_status property_iterator_move_next(const fx_iterator *obj)
|
|||||||
it->it_cur = fx_namemap_first(&it->it_cur_type->ty_properties);
|
it->it_cur = fx_namemap_first(&it->it_cur_type->ty_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
return it->it_cur ? FX_SUCCESS : FX_ERR_NO_DATA;
|
if (!it->it_cur) {
|
||||||
|
return FX_ERR_NO_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fx_value property_iterator_get_value(const fx_iterator *obj)
|
struct fx_type_property *prop
|
||||||
|
= fx_unbox(struct fx_type_property, it->it_cur, p_entry);
|
||||||
|
it->it_value = FX_VALUE_OBJECT_REF(prop->p_prop);
|
||||||
|
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fx_value *property_iterator_get_value(const fx_iterator *obj)
|
||||||
{
|
{
|
||||||
struct fx_type_property_iterator_p *it = fx_object_get_private(
|
struct fx_type_property_iterator_p *it = fx_object_get_private(
|
||||||
obj,
|
obj,
|
||||||
FX_REFLECTION_TYPE_TYPE_PROPERTY_ITERATOR);
|
FX_REFLECTION_TYPE_TYPE_PROPERTY_ITERATOR);
|
||||||
if (!it->it_cur) {
|
if (!it->it_cur) {
|
||||||
return FX_VALUE_EMPTY;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fx_type_property *prop = fx_unbox(
|
struct fx_type_property *prop
|
||||||
struct fx_type_property,
|
= fx_unbox(struct fx_type_property, it->it_cur, p_entry);
|
||||||
it->it_cur,
|
|
||||||
p_entry);
|
|
||||||
|
|
||||||
return FX_VALUE_OBJECT(prop->p_prop);
|
return &it->it_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** CLASS DEFINITION *********************************************************/
|
/*** CLASS DEFINITION *********************************************************/
|
||||||
|
|||||||
Reference in New Issue
Block a user