static cx_int16 cx_ser_reference(cx_serializer s, cx_value *info, void *userData) { cx_compare_ser_t *data = userData; void *_this = cx_valueValue(info); void *value = (void*)((cx_word)cx_valueValue(&data->value) + ((cx_word)_this - (cx_word)data->base)); CX_UNUSED(s); if (*(cx_object*)_this != *(cx_object*)value) { data->result = CX_NEQ; } else { data->result = CX_EQ; } return data->result != CX_EQ; }
static cx_int16 serializeText(cx_value *value, cx_string *out) { cx_type type = cx_valueType(value); cx_void *v = cx_valueValue(value); cx_primitiveKind kind = cx_primitive(type)->kind; if (kind == CX_CHARACTER || (kind == CX_TEXT && (*(cx_string *)v))) { cx_string raw; size_t length; int needEscape = 0; if (cx_convert(cx_primitive(type), v, cx_primitive(cx_string_o), &raw)) { goto error; } if (*raw == '@') { needEscape = 1; } length = stresc(NULL, 0, raw); *out = cx_malloc(length + 3 + needEscape); (*out)[0] = '"'; (*out)[1] = '@'; stresc(*out + 1 + needEscape, length, raw); (*out)[length + needEscape + 1] = '"'; (*out)[length + needEscape + 2] = '\0'; cx_dealloc(raw); } else { *out = cx_malloc(sizeof("null")); strcpy(*out, "null"); } return 0; error: return -1; }
static cx_int16 cx_ser_construct(cx_serializer s, cx_value *info, void *userData) { cx_compare_ser_t *data = userData; cx_bool compare = FALSE; CX_UNUSED(s); cx_type t1 = cx_valueType(info); cx_type t2 = cx_valueType(&data->value); /* If types are different, validate whether comparison should take place */ if (t1 != t2) { /* Certain types of collections can be compared with each other as long as their elementTypes * are equal */ if ((t1->kind == CX_COLLECTION) && (t1->kind == t2->kind)) { switch(cx_collection(t1)->kind) { case CX_ARRAY: case CX_SEQUENCE: case CX_LIST: switch(cx_collection(t2)->kind) { case CX_ARRAY: case CX_SEQUENCE: case CX_LIST: if (cx_collection(t1)->elementType == cx_collection(t2)->elementType) { compare = TRUE; } break; case CX_MAP: compare = FALSE; break; } break; case CX_MAP: if (cx_collection(t2)->kind == CX_MAP) { if (cx_collection(t1)->elementType == cx_collection(t2)->elementType) { if (cx_map(t1)->keyType == cx_map(t2)->keyType) { compare = TRUE; } } } break; } } else { if ((!t1->reference && (t1->kind == CX_VOID)) && (t2->reference || ((t2->kind == CX_PRIMITIVE) && (cx_primitive(t2)->kind == CX_TEXT)))) { compare = TRUE; } if ((!t2->reference && (t2->kind == CX_VOID)) && (t1->reference || ((t1->kind == CX_PRIMITIVE) && (cx_primitive(t1)->kind == CX_TEXT)))) { compare = TRUE; } } } else { compare = TRUE; } data->result = compare ? CX_EQ : CX_NEQ; data->base = cx_valueValue(info); return !compare; }
static cx_int16 serializeBoolean(cx_value *value, cx_string *out) { cx_bool b = *(cx_bool *)cx_valueValue(value); if (b) { *out = cx_malloc(sizeof("true")); strcpy(*out, "true"); } else { *out = cx_malloc(sizeof("false")); strcpy(*out, "false"); } return 0; }
static cx_int16 serializeScopeMeta(cx_serializer s, cx_value* v, void* userData) { CX_UNUSED(s); /* should we receive s for scalability or should we dismiss it? */ int last; size_t sizeBefore, sizeAfter; cx_json_ser_t *data = userData; sizeBefore = strlen(data->buffer); cx_object object = cx_valueValue(v); last = cx_scopeWalk(object, serializeMetaWalkScopeAction, userData); sizeAfter = strlen(data->buffer); if (sizeAfter && sizeBefore < sizeAfter) { data->buffer[sizeAfter - 1] = '\0'; } return last; }
static cx_int16 serializeNumericWithPrefix(cx_value *value, cx_string *out, const char *prefix) { cx_string raw; cx_void *v = cx_valueValue(value); if (cx_convert(cx_primitive(cx_valueType(value)), v, cx_primitive(cx_string_o), &raw)) { goto error; } int length = snprintf(NULL, 0, "\"%s\" %s", prefix, raw); if (length < 0) { goto error; } *out = cx_malloc(length + 1); if (sprintf(*out, "\"%s %s\"", prefix, raw) < 0) { goto error; } cx_dealloc(raw); return 0; error: cx_dealloc(raw); return -1; }
static cx_int16 serializeReference(cx_serializer s, cx_value *v, void *userData) { CX_UNUSED(s); cx_json_ser_t *data; void *o; cx_object object; cx_id id; data = userData; o = cx_valueValue(v); object = *(cx_object*)o; if (object) { if (cx_checkAttr(object, CX_ATTR_SCOPED) || (cx_valueObject(v) == object)) { cx_uint32 length; cx_fullname(object, id); /* Escape value */ cx_string escapedValue = cx_malloc((length = stresc(NULL, 0, id)) + 1); stresc(escapedValue, length, id); if (!cx_ser_appendstr(data, "\"@R %s\"", escapedValue)) { cx_dealloc(escapedValue); goto finished; } cx_dealloc(escapedValue); } else { cx_ser_appendstr(data, "\"anonymous\""); } } else { if (!cx_ser_appendstrbuff(data, "null")) { goto finished; } } return 0; finished: return 1; }
/* Serialize dependencies on references */ cx_int16 cx_genDepReference(cx_serializer s, cx_value* info, void* userData) { cx_object o; g_depWalk_t data; CX_UNUSED(s); data = userData; o = *(cx_object*)cx_valueValue(info); if (o && g_mustParse(data->data->g, o)) { cx_member m; m = NULL; if (info->kind == CX_MEMBER) { m = info->is.member.t; if (!m->type->reference) { m = NULL; } } /* Add dependency on item */ if (m) { cx_depresolver_depend(data->data->resolver, data->o, CX_DEFINED, o, m->state); } else { cx_depresolver_depend(data->data->resolver, data->o, CX_DEFINED, o, CX_DEFINED); } /* Include dependencies on anonymous types */ if (!cx_checkAttr(o, CX_ATTR_SCOPED)) { cx_genDepBuildAction(o, data->data); } } return 0; }
/* Compare collections */ static cx_int16 cx_ser_collection(cx_serializer s, cx_value *info, void* userData) { cx_type t1, t2; void *v1, *v2; cx_equalityKind result = CX_EQ; cx_uint32 size1 = 0, size2 = 0; cx_compare_ser_t *data = userData; cx_any a1, a2; CX_UNUSED(s); /* If this function is reached, collection-types are either equal or comparable. When the * base-object was a collection, the collection type can be different. When the base-object * was a composite type, the collection type has to be equal, since different composite * types are considered non-comparable. */ t1 = cx_valueType(info); v1 = cx_valueValue(info); /* Verify whether current serialized object is the base-object */ if (info->parent) { t2 = t1; v2 = (void*)((cx_word)cx_valueValue(&data->value) + ((cx_word)v1 - (cx_word)data->base)); } else { t2 = cx_valueType(&data->value); v2 = cx_valueValue(&data->value); } /* Prepare any structures for determining sizes of collections */ a1.type = t1; a1.value = v1; a2.type = t2; a2.value = v2; if ((size1 = cx_collection_size(a1)) == (size2 = cx_collection_size(a2))) { void *array1=NULL, *array2=NULL; cx_ll list1=NULL, list2=NULL; cx_uint32 elementSize=0, mem=0; elementSize = cx_type_sizeof(cx_collection(t1)->elementType); switch(cx_collection(t1)->kind) { case CX_ARRAY: array1 = v1; elementSize = cx_type_sizeof(cx_collection(t1)->elementType); mem = cx_collection(t1)->max * elementSize; break; case CX_SEQUENCE: array1 = ((cx_objectSeq*)v1)->buffer; elementSize = cx_type_sizeof(cx_collection(t1)->elementType); mem = ((cx_objectSeq*)v1)->length * elementSize; break; case CX_LIST: list1 = *(cx_ll*)v1; break; case CX_MAP: break; } switch(cx_collection(t2)->kind) { case CX_ARRAY: array2 = v2; break; case CX_SEQUENCE: array2 = ((cx_objectSeq*)v2)->buffer; break; case CX_LIST: list2 = *(cx_ll*)v2; break; case CX_MAP: break; } if (array1) { if (array2) { result = memcmp(array1,array2,mem); /* TODO: do a serialized compare */ } else if (list2) { result = cx_collection_compareArrayWithList(cx_collection(t1), array1, elementSize, list2); } } else if (list1) { if (array2) { result = cx_collection_compareArrayWithList(cx_collection(t1), array2, elementSize, list1); /* Reverse result */ if (result != CX_EQ) { if (result == CX_GT) { result = CX_LT; } else { result = CX_GT; } } } else if (list2) { result = cx_collection_compareListWithList(cx_collection(t1), list1, list2); } } } else { result = size1 > size2 ? CX_GT : CX_LT; } data->result = result < 0 ? -1 : result > 0 ? 1 : 0; return data->result != CX_EQ; }
static cx_int16 cx_ser_primitive(cx_serializer s, cx_value *info, void *userData) { cx_equalityKind result = CX_EQ; cx_compare_ser_t *data = userData; cx_type type = cx_valueType(info); void *_this = cx_valueValue(info); void *value = (void*)((cx_word)cx_valueValue(&data->value) + ((cx_word)_this - (cx_word)data->base)); CX_UNUSED(s); switch(cx_primitive(type)->kind) { case CX_BINARY: switch(cx_primitive(type)->width) { case CX_WIDTH_8: result = CX_COMPARE(cx_octet, _this, value); break; case CX_WIDTH_16: result = CX_COMPARE(cx_uint16, _this, value); break; case CX_WIDTH_32: result = CX_COMPARE(cx_uint32, _this, value); break; case CX_WIDTH_64: result = CX_COMPARE(cx_uint64, _this, value); break; case CX_WIDTH_WORD: result = CX_COMPARE(cx_word, _this, value); break; } break; case CX_BOOLEAN: result = CX_COMPARE(cx_bool, _this, value); break; case CX_CHARACTER: result = CX_COMPARE(cx_char, _this, value); break; case CX_INTEGER: switch(cx_primitive(type)->width) { case CX_WIDTH_8: result = CX_COMPARE(cx_int8, _this, value); break; case CX_WIDTH_16: result = CX_COMPARE(cx_int16, _this, value); break; case CX_WIDTH_32: result = CX_COMPARE(cx_int32, _this, value); break; case CX_WIDTH_64: result = CX_COMPARE(cx_int64, _this, value); break; case CX_WIDTH_WORD: result = CX_COMPARE(intptr_t, _this, value); break; } break; case CX_UINTEGER: switch(cx_primitive(type)->width) { case CX_WIDTH_8: result = CX_COMPARE(cx_uint8, _this, value); break; case CX_WIDTH_16: result = CX_COMPARE(cx_uint16, _this, value); break; case CX_WIDTH_32: result = CX_COMPARE(cx_uint32, _this, value); break; case CX_WIDTH_64: result = CX_COMPARE(cx_uint64, _this, value); break; case CX_WIDTH_WORD: result = CX_COMPARE(uintptr_t, _this, value); break; } break; case CX_FLOAT: switch(cx_primitive(type)->width) { case CX_WIDTH_32: result = CX_COMPARE(cx_float32, _this, value); break; case CX_WIDTH_64: result = CX_COMPARE(cx_float64, _this, value); break; default: break; } break; case CX_TEXT: { cx_string thisStr = *(cx_string*)_this; cx_string valueStr = *(cx_string*)value; if (thisStr && valueStr) { result = strcmp(thisStr, valueStr); } else { result = !(thisStr == valueStr); } break; } case CX_ENUM: case CX_BITMASK: result = CX_COMPARE(cx_int32, _this, value); break; case CX_ALIAS: result = CX_COMPARE(cx_word, _this, value); break; } data->result = result; return data->result != CX_EQ; }
static cx_int16 serializeNumber(cx_value *value, cx_string *out) { cx_type t = cx_valueType(value); cx_void *v = cx_valueValue(value); cx_int16 result = cx_convert(cx_primitive(t), v, cx_primitive(cx_string_o), out); return result; }
static cx_int16 serializeMeta(cx_serializer s, cx_value* v, void* userData) { CX_UNUSED(s); cx_json_ser_t *data = userData; cx_object o = cx_valueValue(v); if (!data->serializeMeta) { goto error; } if (!cx_ser_appendstr(userData, "{")) { goto finished; } cx_string name = cx_nameof(o); if (name) { if (!cx_appendStringAttr("name", name, userData)) { goto finished; } } else { if (!cx_ser_appendstr(userData, "\"name\":\"::\",")) { goto finished; } } cx_id type_fullname; cx_fullname(cx_typeof(o), type_fullname); if (!cx_appendStringAttr("type", type_fullname, userData)) { goto finished; } if (cx_checkAttr(o, CX_ATTR_PERSISTENT)) { cx_time t = cx_timestampof(o); if (!cx_ser_appendstr(data, "\"timestamp\":\"%d.%.9d\",", t.tv_sec, t.tv_nsec)) { goto finished; } } char states[sizeof("V|DCL|DEF")]; dbsh_stateStr(o, states); if (!cx_ser_appendstr(data, "\"states\":\"%s\",", states)) { goto finished; } char attributes[sizeof("S|W|O|P")]; dbsh_attrStr(o, attributes); if (!cx_ser_appendstr(data, "\"attributes\":\"%s\",", attributes)) { goto finished; } cx_id parent_fullname; cx_fullname(cx_parentof(o), parent_fullname); if (!cx_ser_appendstr(data, "\"parent\":\"%s\",", parent_fullname)) { goto finished; } cx_uint32 scopeSize = cx_scopeSize(o); if (!cx_ser_appendstr(data, "\"childCount\":%"PRId32"", scopeSize)) { goto finished; } if (!cx_ser_appendstr(data, "}")) { goto finished; } return 0; error: return -1; finished: return 1; }