Skip to content

Commit

Permalink
[runtime] unit runtime&runtime-light json functions into runtime-common
Browse files Browse the repository at this point in the history
  • Loading branch information
irlgirl committed Nov 28, 2024
1 parent 568499b commit 7032b33
Show file tree
Hide file tree
Showing 24 changed files with 150 additions and 929 deletions.
1 change: 1 addition & 0 deletions builtin-functions/kphp-light/functions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require_once __DIR__ . '/file.txt';
require_once __DIR__ . '/hash.txt';
require_once __DIR__ . '/job-workers.txt';
require_once __DIR__ . '/rpc.txt';
require_once __DIR__ . '/serialize.txt';
require_once __DIR__ . '/string.txt';
require_once __DIR__ . '/server.txt';
require_once __DIR__ . '/kphp-toggles.txt';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,11 @@
<?php

/** @kphp-extern-func-info generate-stub */
function serialize($v ::: mixed) ::: string;
/**
* @kphp-extern-func-info generate-stub
* @kphp-pure-function
*/
function unserialize ($v ::: string) ::: mixed;

/** @kphp-extern-func-info generate-stub */
function msgpack_serialize($v ::: mixed) ::: string | null;
/** @kphp-extern-func-info generate-stub */
function msgpack_deserialize($v ::: string) ::: mixed;
/** @kphp-extern-func-info can_throw generate-stub */
function msgpack_serialize_safe($v ::: mixed) ::: string;
/** @kphp-extern-func-info can_throw generate-stub */
function msgpack_deserialize_safe($v ::: string) ::: mixed;

function instance_serialize(object $instance) ::: string | null;
/** @kphp-extern-func-info can_throw */
function instance_serialize_safe(object $instance) ::: string;
/** @kphp-extern-func-info cpp_template_call */
function instance_deserialize($serialized ::: string, $to_type ::: string) ::: instance<^2>;
/** @kphp-extern-func-info cpp_template_call can_throw */
function instance_deserialize_safe($serialized ::: string, $to_type ::: string) ::: instance<^2>;

define('JSON_UNESCAPED_UNICODE', 1);
define('JSON_FORCE_OBJECT', 16);
define('JSON_PRETTY_PRINT', 128); // TODO: add actual support
define('JSON_PARTIAL_OUTPUT_ON_ERROR', 512);
define('JSON_PRESERVE_ZERO_FRACTION', 1024);

/** @kphp-generate-stub-class */
class JsonEncoder {
const rename_policy = 'none';
const visibility_policy = 'all';
Expand All @@ -52,4 +26,3 @@ class JsonEncoder {
/** @kphp-extern-func-info cpp_template_call */
static function from_json_impl(string $encoder_tag, string $json, string $class_name) ::: instance<^3>;
}

2 changes: 1 addition & 1 deletion builtin-functions/kphp-light/unsupported-functions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require_once __DIR__ . '/unsupported/math.txt';
require_once __DIR__ . '/unsupported/memcache.txt';
require_once __DIR__ . '/unsupported/misc.txt';
require_once __DIR__ . '/unsupported/regex.txt';
require_once __DIR__ . '/unsupported/serialize.txt';
require_once __DIR__ . '/unsupported/unsupported-serialize.txt';
require_once __DIR__ . '/unsupported/spl.txt';
require_once __DIR__ . '/unsupported/uberh3.txt';
require_once __DIR__ . '/unsupported/unsupported-server.txt';
27 changes: 27 additions & 0 deletions builtin-functions/kphp-light/unsupported/unsupported-serialize.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/** @kphp-extern-func-info generate-stub */
function serialize($v ::: mixed) ::: string;
/**
* @kphp-extern-func-info generate-stub
* @kphp-pure-function
*/
function unserialize ($v ::: string) ::: mixed;

/** @kphp-extern-func-info generate-stub */
function msgpack_serialize($v ::: mixed) ::: string | null;
/** @kphp-extern-func-info generate-stub */
function msgpack_deserialize($v ::: string) ::: mixed;
/** @kphp-extern-func-info can_throw generate-stub */
function msgpack_serialize_safe($v ::: mixed) ::: string;
/** @kphp-extern-func-info can_throw generate-stub */
function msgpack_deserialize_safe($v ::: string) ::: mixed;

function instance_serialize(object $instance) ::: string | null;
/** @kphp-extern-func-info can_throw */
function instance_serialize_safe(object $instance) ::: string;
/** @kphp-extern-func-info cpp_template_call */
function instance_deserialize($serialized ::: string, $to_type ::: string) ::: instance<^2>;
/** @kphp-extern-func-info cpp_template_call can_throw */
function instance_deserialize_safe($serialized ::: string, $to_type ::: string) ::: instance<^2>;

6 changes: 4 additions & 2 deletions runtime-common/stdlib/stdlib.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
prepend(STDLIB_STRING stdlib/string/ string-functions.cpp
mbstring-functions.cpp)
prepend(STDLIB_STRING stdlib/string/ json-functions.cpp
json-writer.cpp
mbstring-functions.cpp
string-functions.cpp)
prepend(STDLIB_SERVER stdlib/server/ url-functions.cpp)
prepend(STDLIB_VKEXT stdlib/vkext/ vkext.cpp vkext_stats.cpp string-processing.cpp)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

#pragma once

#include <string_view>
#include "runtime/context/runtime-context.h"

#include "runtime-common/core/runtime-core.h"
#include "runtime/json-functions.h"
#include "runtime/json-processor-utils.h"
#include "runtime-common/stdlib/string/json-functions.h"
#include "runtime-common/stdlib/string/json-processor-utils.h"
#include "runtime-common/stdlib/string/string-context.h"

template<class Tag>
class FromJsonVisitor {
Expand Down Expand Up @@ -91,13 +92,13 @@ class FromJsonVisitor {
}

void do_set(JsonRawString &value, const mixed &json) noexcept {
kphp_runtime_context.static_SB.clean();
if (!impl_::JsonEncoder{0, false, get_json_obj_magic_key()}.encode(json)) {
RuntimeContext::get().static_SB.clean();
if (!impl_::JsonEncoder{0, false, get_json_obj_magic_key()}.encode(json, RuntimeContext::get().static_SB)) {
error_.append("failed to decode @kphp-json raw_string field ");
error_.append(json_path_.to_string());
return;
}
value.str = kphp_runtime_context.static_SB.str();
value.str = RuntimeContext::get().static_SB.str();
}

template<class T>
Expand Down Expand Up @@ -169,14 +170,14 @@ class_instance<I> from_json_impl(const mixed &json, JsonPath &json_path) noexcep
FromJsonVisitor<Tag> visitor{json, impl_::IsJsonFlattenClass<I>::value, json_path};
instance.get()->accept(visitor);
if (visitor.has_error()) {
JsonEncoderError::msg.append(visitor.get_error());
StringLibContext::get().last_json_processor_error.append(visitor.get_error());
return {};
}
}
if constexpr (impl_::HasClassWakeupMethod<I>::value) {
instance.get()->wakeup(instance);
}
return JsonEncoderError::msg.empty() ? instance : class_instance<I>{};
return StringLibContext::get().last_json_processor_error.empty() ? instance : class_instance<I>{};
}

template<class Tag>
Expand All @@ -196,18 +197,19 @@ void FromJsonVisitor<Tag>::do_set(class_instance<I> &klass, const mixed &json) n

template<class ClassName, class Tag>
ClassName f$JsonEncoder$$from_json_impl(Tag /*tag*/, const string &json_string, const string &/*class_mame*/) noexcept {
JsonEncoderError::msg = {};
auto &msg = StringLibContext::get().last_json_processor_error;
msg = {};

auto [json, success] = json_decode(json_string, FromJsonVisitor<Tag>::get_json_obj_magic_key());

if (!success) {
JsonEncoderError::msg.append(json_string.empty() ? "provided empty json string" : "failed to parse json string");
msg.append(json_string.empty() ? "provided empty json string" : "failed to parse json string");
return {};
}
if constexpr (!impl_::IsJsonFlattenClass<typename ClassName::ClassType>::value) {
if (!json.is_array() || json.as_array().is_vector()) {
JsonEncoderError::msg.append("root element of json string must be an object type, got ");
JsonEncoderError::msg.append(json.get_type_c_str());
msg.append("root element of json string must be an object type, got ");
msg.append(json.get_type_c_str());
return {};
}
}
Expand All @@ -216,4 +218,6 @@ ClassName f$JsonEncoder$$from_json_impl(Tag /*tag*/, const string &json_string,
return from_json_impl<typename ClassName::ClassType, Tag>(json, json_path);
}

string f$JsonEncoder$$getLastError() noexcept;
inline string f$JsonEncoder$$getLastError() noexcept {
return StringLibContext::get().last_json_processor_error;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
// Copyright (c) 2020 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#include "runtime-light/utils/json-functions.h"
#include "runtime-common/stdlib/string/json-functions.h"

#include "common/algorithms/find.h"
//#include "runtime/string_functions.h"
#include "runtime-common/stdlib/string/string-functions.h"

// note: json-functions.cpp is used for non-typed json implementation: for json_encode() and json_decode()
// for classes, e.g. `JsonEncoder::encode(new A)`, see json-writer.cpp and from/to visitors
namespace {

void json_append_one_char(unsigned int c, string_buffer & sb) noexcept {
void json_append_one_char(unsigned int c, string_buffer &sb) noexcept {
sb.append_char('\\');
sb.append_char('u');
sb.append_char("0123456789abcdef"[c >> 12]);
Expand All @@ -20,7 +20,7 @@ void json_append_one_char(unsigned int c, string_buffer & sb) noexcept {
sb.append_char("0123456789abcdef"[c & 15]);
}

bool json_append_char(unsigned int c, string_buffer & sb) noexcept {
bool json_append_char(unsigned int c, string_buffer &sb) noexcept {
if (c < 0x10000) {
if (0xD7FF < c && c < 0xE000) {
return false;
Expand All @@ -37,8 +37,7 @@ bool json_append_char(unsigned int c, string_buffer & sb) noexcept {
return false;
}


bool do_json_encode_string_php(const JsonPath &json_path, const char *s, int len, int64_t options, string_buffer & sb) noexcept {
bool do_json_encode_string_php(const JsonPath &json_path, const char *s, int len, int64_t options, string_buffer &sb) noexcept {
int begin_pos = sb.size();
if (options & JSON_UNESCAPED_UNICODE) {
sb.reserve(2 * len + 2);
Expand Down Expand Up @@ -176,7 +175,7 @@ string JsonPath::to_string() const {
}
unsigned num_parts = std::clamp(depth, 0U, static_cast<unsigned>(arr.size()));
string result;
result.reserve_at_least((num_parts+1) * 8);
result.reserve_at_least((num_parts + 1) * 8);
result.push_back('/');
for (unsigned i = 0; i < num_parts; i++) {
const char *key = arr[i];
Expand All @@ -198,13 +197,12 @@ string JsonPath::to_string() const {

namespace impl_ {

JsonEncoder::JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key) noexcept:
options_(options),
simple_encode_(simple_encode),
json_obj_magic_key_(json_obj_magic_key) {
}
JsonEncoder::JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key) noexcept
: options_(options)
, simple_encode_(simple_encode)
, json_obj_magic_key_(json_obj_magic_key) {}

bool JsonEncoder::encode(bool b, string_buffer & sb) noexcept {
bool JsonEncoder::encode(bool b, string_buffer &sb) noexcept {
if (b) {
sb.append("true", 4);
} else {
Expand All @@ -213,17 +211,17 @@ bool JsonEncoder::encode(bool b, string_buffer & sb) noexcept {
return true;
}

bool JsonEncoder::encode_null(string_buffer & sb) const noexcept {
bool JsonEncoder::encode_null(string_buffer &sb) const noexcept {
sb.append("null", 4);
return true;
}

bool JsonEncoder::encode(int64_t i, string_buffer & sb) noexcept {
bool JsonEncoder::encode(int64_t i, string_buffer &sb) noexcept {
sb << i;
return true;
}

bool JsonEncoder::encode(double d, string_buffer & sb) noexcept {
bool JsonEncoder::encode(double d, string_buffer &sb) noexcept {
if (vk::any_of_equal(std::fpclassify(d), FP_INFINITE, FP_NAN)) {
php_warning("%s: strange double %lf in function json_encode", json_path_.to_string().c_str(), d);
if (options_ & JSON_PARTIAL_OUTPUT_ON_ERROR) {
Expand All @@ -232,17 +230,16 @@ bool JsonEncoder::encode(double d, string_buffer & sb) noexcept {
return false;
}
} else {
//todo:k2 implement f$number_format
sb << /*(simple_encode_ ? f$number_format(d, 6, string{"."}, string{}) : */ string{d}/*)*/;
sb << (simple_encode_ ? f$number_format(d, 6, string{"."}, string{}) : string{d});
}
return true;
}

bool JsonEncoder::encode(const string &s, string_buffer & sb) noexcept {
bool JsonEncoder::encode(const string &s, string_buffer &sb) noexcept {
return do_json_encode_string_php(json_path_, s.c_str(), s.size(), options_, sb);
}

bool JsonEncoder::encode(const mixed &v, string_buffer & sb) noexcept {
bool JsonEncoder::encode(const mixed &v, string_buffer &sb) noexcept {
switch (v.get_type()) {
case mixed::type::NUL:
return encode_null(sb);
Expand Down Expand Up @@ -278,29 +275,22 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json
json_skip_blanks(s, i);
switch (s[i]) {
case 'n':
if (s[i + 1] == 'u' &&
s[i + 2] == 'l' &&
s[i + 3] == 'l') {
if (s[i + 1] == 'u' && s[i + 2] == 'l' && s[i + 3] == 'l') {
i += 4;
return true;
}
break;
case 't':
if (s[i + 1] == 'r' &&
s[i + 2] == 'u' &&
s[i + 3] == 'e') {
if (s[i + 1] == 'r' && s[i + 2] == 'u' && s[i + 3] == 'e') {
i += 4;
new(&v) mixed(true);
new (&v) mixed(true);
return true;
}
break;
case 'f':
if (s[i + 1] == 'a' &&
s[i + 2] == 'l' &&
s[i + 3] == 's' &&
s[i + 4] == 'e') {
if (s[i + 1] == 'a' && s[i + 2] == 'l' && s[i + 3] == 's' && s[i + 4] == 'e') {
i += 5;
new(&v) mixed(false);
new (&v) mixed(false);
return true;
}
break;
Expand Down Expand Up @@ -362,8 +352,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json
}

if (0xD7FF < num && num < 0xE000) {
if (s[i + 1] == '\\' && s[i + 2] == 'u' &&
isxdigit(s[i + 3]) && isxdigit(s[i + 4]) && isxdigit(s[i + 5]) && isxdigit(s[i + 6])) {
if (s[i + 1] == '\\' && s[i + 2] == 'u' && isxdigit(s[i + 3]) && isxdigit(s[i + 4]) && isxdigit(s[i + 5]) && isxdigit(s[i + 6])) {
i += 2;
int u = 0;
for (int t = 0; t < 4; t++) {
Expand Down Expand Up @@ -417,7 +406,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json
}
value.shrink(l);

new(&v) mixed(value);
new (&v) mixed(value);
i++;
return true;
}
Expand All @@ -444,7 +433,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json
i++;
}

new(&v) mixed(res);
new (&v) mixed(res);
return true;
}
case '{': {
Expand Down Expand Up @@ -481,7 +470,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json
res[string{json_obj_magic_key}] = true;
}

new(&v) mixed(res);
new (&v) mixed(res);
return true;
}
default: {
Expand All @@ -493,15 +482,15 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json
int64_t intval = 0;
if (php_try_to_int(s + i, j - i, &intval)) {
i = j;
new(&v) mixed(intval);
new (&v) mixed(intval);
return true;
}

char *end_ptr;
double floatval = strtod(s + i, &end_ptr);
if (end_ptr == s + j) {
i = j;
new(&v) mixed(floatval);
new (&v) mixed(floatval);
return true;
}
}
Expand Down
Loading

0 comments on commit 7032b33

Please sign in to comment.