diff --git a/builtin-functions/kphp-light/stdlib/rpc.txt b/builtin-functions/kphp-light/stdlib/rpc.txt index c7ccf4a7a0..f179a800ce 100644 --- a/builtin-functions/kphp-light/stdlib/rpc.txt +++ b/builtin-functions/kphp-light/stdlib/rpc.txt @@ -69,6 +69,12 @@ function rpc_fetch_typed_responses_synchronously(int[] $query_ids) ::: @tl\RpcRe /** @kphp-extern-func-info can_throw */ function fetch_int () ::: int; +/** @kphp-extern-func-info can_throw */ +function fetch_lookup_int () ::: int; + +/** @kphp-extern-func-info can_throw */ +function fetch_lookup_data ($x4_bytes_length ::: int) ::: string; + /** @kphp-extern-func-info can_throw */ function fetch_byte () ::: int; @@ -139,9 +145,6 @@ function new_rpc_connection ($str ::: string, $port ::: int, $actor_id ::: mixed /** @kphp-extern-func-info interruptible stub generation-required */ function store_finish() ::: bool; -/** @kphp-extern-func-info interruptible stub generation-required can_throw */ -function fetch_lookup_int () ::: int; - /** @kphp-generate-stub-class */ final class RpcConnection { /** @kphp-extern-func-info stub generation-required */ diff --git a/runtime-light/stdlib/rpc/rpc-api.h b/runtime-light/stdlib/rpc/rpc-api.h index fdef374024..4e162f775b 100644 --- a/runtime-light/stdlib/rpc/rpc-api.h +++ b/runtime-light/stdlib/rpc/rpc-api.h @@ -143,6 +143,29 @@ inline int64_t f$fetch_int() noexcept { return DEFAULT_VALUE; } +inline int64_t f$fetch_lookup_int() noexcept { + static constexpr int64_t DEFAULT_VALUE{0}; + auto tl_fetcher{RpcServerInstanceState::get().tl_fetcher}; // copy + if (tl::i32 val{}; val.fetch(tl_fetcher)) [[likely]] { + return static_cast(val.value); + } + THROW_EXCEPTION(kphp::rpc::exception::not_enough_data_to_fetch::make()); + return DEFAULT_VALUE; +} + +inline string f$fetch_lookup_data(int64_t x4_bytes_length) noexcept { + static constexpr size_t BYTES_PER_WORD{sizeof(int32_t)}; + const auto& tl_fetcher{RpcServerInstanceState::get().tl_fetcher}; + if (x4_bytes_length < 0 || static_cast(x4_bytes_length) > (tl_fetcher.remaining() / BYTES_PER_WORD)) [[unlikely]] { + THROW_EXCEPTION(kphp::rpc::exception::not_enough_data_to_fetch::make()); + return {}; + } + + const auto bytes_length{static_cast(x4_bytes_length) * BYTES_PER_WORD}; + const auto bytes{tl_fetcher.view().subspan(tl_fetcher.pos(), bytes_length)}; + return string{reinterpret_cast(bytes.data()), static_cast(bytes.size())}; +} + inline int64_t f$fetch_long() noexcept { static constexpr int64_t DEFAULT_VALUE = 0; if (tl::i64 val{}; val.fetch(RpcServerInstanceState::get().tl_fetcher)) [[likely]] { diff --git a/tests/k2_kphp_tracked_builtins_list.txt b/tests/k2_kphp_tracked_builtins_list.txt index d72ec258bb..525981f16e 100644 --- a/tests/k2_kphp_tracked_builtins_list.txt +++ b/tests/k2_kphp_tracked_builtins_list.txt @@ -176,6 +176,8 @@ extract_kphp_rpc_response_extra_info fclose fetch_double fetch_int +fetch_lookup_int +fetch_lookup_data fetch_long fetch_string fflush @@ -491,7 +493,6 @@ openssl_x509_verify preg_last_error new_rpc_connection store_finish -fetch_lookup_int gethostbynamel localtime system diff --git a/tests/python/tests/tl_primitives/php/index.php b/tests/python/tests/tl_primitives/php/index.php index 310e851a61..5aed56203a 100644 --- a/tests/python/tests/tl_primitives/php/index.php +++ b/tests/python/tests/tl_primitives/php/index.php @@ -23,6 +23,28 @@ critical_error('expected ' . $op['expected'] . ' but ' . $res . ' found'); } break; + case 'fetch_lookup_int': + $pos_before = fetch_get_pos(); + $res = fetch_lookup_int(); + $pos_after = fetch_get_pos(); + if ($pos_after !== $pos_before) { + critical_error('fetch_lookup_int changed fetch position from ' . $pos_before . ' to ' . $pos_after); + } + if ($res != $op['expected']) { + critical_error('expected ' . $op['expected'] . ' but ' . $res . ' found'); + } + break; + case 'fetch_lookup_data': + $pos_before = fetch_get_pos(); + $res = fetch_lookup_data($op['x4_bytes_length']); + $pos_after = fetch_get_pos(); + if ($pos_after !== $pos_before) { + critical_error('fetch_lookup_data changed fetch position from ' . $pos_before . ' to ' . $pos_after); + } + if ($res != $op['expected']) { + critical_error('expected ' . $op['expected'] . ' but ' . $res . ' found'); + } + break; case 'fetch_long': $res = fetch_long(); if ($res != $op['expected']) { diff --git a/tests/python/tests/tl_primitives/test_tl_primitives.py b/tests/python/tests/tl_primitives/test_tl_primitives.py index c5de676e51..2c320a191d 100644 --- a/tests/python/tests/tl_primitives/test_tl_primitives.py +++ b/tests/python/tests/tl_primitives/test_tl_primitives.py @@ -30,6 +30,17 @@ def _assert_fetch_int(expected_result: int, expected_exception: bool = False): return _operation('fetch_int', dict(), expected_result, expected_exception=expected_exception) +def _assert_fetch_lookup_int(expected_result: int, expected_exception: bool = False): + return _operation('fetch_lookup_int', dict(), expected_result, expected_exception=expected_exception) + + +def _assert_fetch_lookup_data(x4_bytes_length: int, expected_result: str, expected_exception: bool = False): + return _operation( + 'fetch_lookup_data', dict(x4_bytes_length=x4_bytes_length), expected_result, + expected_exception=expected_exception + ) + + def _assert_fetch_long(expected_result: int, expected_exception: bool = False): return _operation('fetch_long', dict(), expected_result, expected_exception=expected_exception) @@ -53,6 +64,8 @@ def test_fetch(self): _assert_rpc_parse( '\x12\x34\x56\x78\x42\x00\x00\x00\x00\x00\x00\x00\x68\x56\x5b\x56\x06\x22\x09\x40\x03abc', True ), + _assert_fetch_lookup_int(0x78563412), + _assert_fetch_lookup_data(1, '\x12\x34\x56\x78'), _assert_fetch_int(0x78563412), _assert_fetch_long(0x42), _assert_fetch_double(3.14161365),