From af95e867640a967e005afc51ffa3b532d5b1dac6 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 13 Dec 2018 02:12:18 +0700 Subject: [PATCH] promises for async vfs operations --- headers/3rdparty/promise.hpp/promise.hpp | 125 ++++++++++++----------- headers/enduro2d/core/vfs.hpp | 26 +++-- modules/promise.hpp | 2 +- samples/sources/sample_00/sample_00.cpp | 6 +- samples/sources/sample_01/sample_01.cpp | 4 +- samples/sources/sample_02/sample_02.cpp | 4 +- sources/enduro2d/core/vfs.cpp | 82 +++++++-------- sources/enduro2d/high/assets.cpp | 4 +- untests/sources/untests_core/vfs.cpp | 94 +++++++++++------ 9 files changed, 193 insertions(+), 154 deletions(-) diff --git a/headers/3rdparty/promise.hpp/promise.hpp b/headers/3rdparty/promise.hpp/promise.hpp index 79a5663b..84524d30 100644 --- a/headers/3rdparty/promise.hpp/promise.hpp +++ b/headers/3rdparty/promise.hpp/promise.hpp @@ -178,16 +178,16 @@ namespace promise_hpp then([ n = next, f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto np = invoke_hpp::invoke( std::forward(f), - v); - np.then([n]() mutable { + std::forward(v)); + std::move(np).then([n]() mutable { n.resolve(); - }, [n](std::exception_ptr e) mutable { + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -205,16 +205,16 @@ namespace promise_hpp then([ n = next, f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto np = invoke_hpp::invoke( std::forward(f), - v); - np.then([n](const typename ResolveFR::value_type& nv) mutable { - n.resolve(nv); - }, [n](std::exception_ptr e) mutable { + std::forward(v)); + std::move(np).then([n](auto&& nv) mutable { + n.resolve(std::forward(nv)); + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -225,10 +225,10 @@ namespace promise_hpp auto then_all(ResolveF&& on_resolve) { return then([ f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto r = invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); return make_all_promise(std::move(r)); }); } @@ -237,10 +237,10 @@ namespace promise_hpp auto then_any(ResolveF&& on_resolve) { return then([ f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto r = invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); return make_any_promise(std::move(r)); }); } @@ -274,14 +274,13 @@ namespace promise_hpp template < typename RejectF > promise except(RejectF&& on_reject) { return then( - [](const T& value) { return value; }, + [](auto&& v) { return std::forward(v); }, std::forward(on_reject)); } template < typename U > bool resolve(U&& value) { - return state_->resolve( - std::forward(value)); + return state_->resolve(std::forward(value)); } bool reject(std::exception_ptr e) noexcept { @@ -298,6 +297,14 @@ namespace promise_hpp return state_->get(); } + const T& get_or_default(const T& def) const noexcept { + try { + return get(); + } catch (...) { + return def; + } + } + void wait() const noexcept { state_->wait(); } @@ -391,10 +398,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -408,18 +415,15 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h - ](const T& v) mutable { + f = std::forward(on_resolve) + ](auto&& v) mutable { try { invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); n.resolve(); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -429,10 +433,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -446,18 +450,15 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h - ](const T& v) mutable { + f = std::forward(on_resolve) + ](auto&& v) mutable { try { auto r = invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); n.resolve(std::move(r)); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -576,12 +577,12 @@ namespace promise_hpp ]() mutable { auto np = invoke_hpp::invoke( std::forward(f)); - np.then([n]() mutable { + std::move(np).then([n]() mutable { n.resolve(); - }, [n](std::exception_ptr e) mutable { + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -602,12 +603,12 @@ namespace promise_hpp ]() mutable { auto np = invoke_hpp::invoke( std::forward(f)); - np.then([n](const typename ResolveFR::value_type& nv) mutable { - n.resolve(nv); - }, [n](std::exception_ptr e) mutable { + std::move(np).then([n](auto&& nv) mutable { + n.resolve(std::forward(nv)); + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -687,6 +688,14 @@ namespace promise_hpp state_->get(); } + void get_or_default() const noexcept { + try { + return get(); + } catch (...) { + // nothing + } + } + void wait() const noexcept { state_->wait(); } @@ -777,10 +786,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -794,17 +803,14 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h + f = std::forward(on_resolve) ]() mutable { try { invoke_hpp::invoke( std::forward(f)); n.resolve(); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -814,10 +820,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -831,17 +837,14 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h + f = std::forward(on_resolve) ]() mutable { try { auto r = invoke_hpp::invoke( std::forward(f)); n.resolve(std::move(r)); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -1020,11 +1023,11 @@ namespace promise_hpp context, resolver, result_index - ](const child_promise_value_t& v) mutable { - if ( context->apply_result(result_index, v) ) { + ](auto&& v) mutable { + if ( context->apply_result(result_index, std::forward(v)) ) { resolver(std::move(context->results)); } - }, rejector); + }).except(rejector); } }); } @@ -1051,7 +1054,7 @@ namespace promise_hpp return make_promise([begin, end](auto&& resolver, auto&& rejector){ for ( auto iter = begin; iter != end; ++iter ) { - (*iter).then(resolver, rejector); + (*iter).then(resolver).except(rejector); } }); } diff --git a/headers/enduro2d/core/vfs.hpp b/headers/enduro2d/core/vfs.hpp index 8342c4c8..1ee06fe1 100644 --- a/headers/enduro2d/core/vfs.hpp +++ b/headers/enduro2d/core/vfs.hpp @@ -17,6 +17,12 @@ namespace e2d } }; + class vfs_load_async_exception final : public exception { + const char* what() const noexcept final { + return "vfs load async exception"; + } + }; + class vfs final : public module { public: vfs(); @@ -27,8 +33,7 @@ namespace e2d virtual ~file_source() noexcept = default; virtual bool valid() const noexcept = 0; virtual bool exists(str_view path) const = 0; - virtual input_stream_uptr open(str_view path) const = 0; - virtual std::pair load(str_view path) const = 0; + virtual input_stream_uptr read(str_view path) const = 0; virtual output_stream_uptr write(str_view path, bool append) const = 0; virtual bool trace(str_view path, filesystem::trace_func func) const = 0; }; @@ -43,10 +48,15 @@ namespace e2d bool unregister_scheme_alias(str_view scheme); bool exists(const url& url) const; - input_stream_uptr open(const url& url) const; - std::pair load(const url& url) const; + + input_stream_uptr read(const url& url) const; output_stream_uptr write(const url& url, bool append) const; - stdex::promise> load_async(const url& url) const; + + bool load(const url& url, buffer& dst) const; + stdex::promise load_async(const url& url) const; + + bool load_as_string(const url& url, str& dst) const; + stdex::promise load_as_string_async(const url& url) const; template < typename Iter > bool extract(const url& url, Iter result_iter) const; @@ -64,8 +74,7 @@ namespace e2d ~archive_file_source() noexcept final; bool valid() const noexcept final; bool exists(str_view path) const final; - input_stream_uptr open(str_view path) const final; - std::pair load(str_view path) const final; + input_stream_uptr read(str_view path) const final; output_stream_uptr write(str_view path, bool append) const final; bool trace(str_view path, filesystem::trace_func func) const final; private: @@ -79,8 +88,7 @@ namespace e2d ~filesystem_file_source() noexcept final; bool valid() const noexcept final; bool exists(str_view path) const final; - input_stream_uptr open(str_view path) const final; - std::pair load(str_view path) const final; + input_stream_uptr read(str_view path) const final; output_stream_uptr write(str_view path, bool append) const final; bool trace(str_view path, filesystem::trace_func func) const final; }; diff --git a/modules/promise.hpp b/modules/promise.hpp index 4fb77fb4..5871ecea 160000 --- a/modules/promise.hpp +++ b/modules/promise.hpp @@ -1 +1 @@ -Subproject commit 4fb77fb49d2932cf44157f4d154465520f3c420d +Subproject commit 5871ecea027ae745417bdfd33e8e296ad152c3cf diff --git a/samples/sources/sample_00/sample_00.cpp b/samples/sources/sample_00/sample_00.cpp index cefc9f60..a261f708 100644 --- a/samples/sources/sample_00/sample_00.cpp +++ b/samples/sources/sample_00/sample_00.cpp @@ -95,7 +95,7 @@ namespace bool initialize() final { the().register_scheme( "piratepack", - the().open(url("resources://bin/kenney_piratepack.zip"))); + the().read(url("resources://bin/kenney_piratepack.zip"))); the().register_scheme_alias( "ships", @@ -104,9 +104,9 @@ namespace shader_ = the().create_shader( vs_source_cstr, fs_source_cstr); texture1_ = the().create_texture( - the().open(url("ships://ship (2).png"))); + the().read(url("ships://ship (2).png"))); texture2_ = the().create_texture( - the().open(url("ships://ship (19).png"))); + the().read(url("ships://ship (19).png"))); if ( !shader_ || !texture1_ || !texture2_ ) { return false; diff --git a/samples/sources/sample_01/sample_01.cpp b/samples/sources/sample_01/sample_01.cpp index 6e184619..92bdb3ae 100644 --- a/samples/sources/sample_01/sample_01.cpp +++ b/samples/sources/sample_01/sample_01.cpp @@ -155,7 +155,7 @@ namespace bool initialize() final { the().register_scheme( "piratepack", - the().open(url("resources://bin/kenney_piratepack.zip"))); + the().read(url("resources://bin/kenney_piratepack.zip"))); the().register_scheme_alias( "ships", @@ -165,7 +165,7 @@ namespace vs_source_cstr, fs_source_cstr); texture_ = the().create_texture( - the().open(url("ships://ship (3).png"))); + the().read(url("ships://ship (3).png"))); if ( !shader_ || !texture_ ) { return false; diff --git a/samples/sources/sample_02/sample_02.cpp b/samples/sources/sample_02/sample_02.cpp index 0a02ced7..db9516b1 100644 --- a/samples/sources/sample_02/sample_02.cpp +++ b/samples/sources/sample_02/sample_02.cpp @@ -110,7 +110,7 @@ namespace bool initialize() final { the().register_scheme( "piratepack", - the().open(url("resources://bin/kenney_piratepack.zip"))); + the().read(url("resources://bin/kenney_piratepack.zip"))); the().register_scheme_alias( "ships", @@ -120,7 +120,7 @@ namespace vs_source_cstr, fs_source_cstr); texture_ = the().create_texture( - the().open(url("ships://ship (3).png"))); + the().read(url("ships://ship (3).png"))); if ( !shader_ || !texture_ ) { return false; diff --git a/sources/enduro2d/core/vfs.cpp b/sources/enduro2d/core/vfs.cpp index 07cd5957..6cddaed7 100644 --- a/sources/enduro2d/core/vfs.cpp +++ b/sources/enduro2d/core/vfs.cpp @@ -98,7 +98,10 @@ namespace e2d const auto resolved_url = resolve_url(url); const auto scheme_iter = schemes.find(resolved_url.scheme()); return (scheme_iter != schemes.cend() && scheme_iter->second) - ? stdex::invoke(std::forward(f), scheme_iter->second, resolved_url.path()) + ? stdex::invoke( + std::forward(f), + scheme_iter->second, + resolved_url.path()) : std::forward(fallback_result); } }; @@ -140,22 +143,14 @@ namespace e2d }, false); } - input_stream_uptr vfs::open(const url& url) const { + input_stream_uptr vfs::read(const url& url) const { std::lock_guard guard(state_->mutex); return state_->with_file_source(url, [](const file_source_uptr& source, const str& path) { - return source->open(path); + return source->read(path); }, input_stream_uptr()); } - std::pair vfs::load(const url& url) const { - std::lock_guard guard(state_->mutex); - return state_->with_file_source(url, - [](const file_source_uptr& source, const str& path) { - return source->load(path); - }, std::make_pair(buffer(), false)); - } - output_stream_uptr vfs::write(const url& url, bool append) const { std::lock_guard guard(state_->mutex); return state_->with_file_source(url, @@ -164,13 +159,40 @@ namespace e2d }, output_stream_uptr()); } - stdex::promise> vfs::load_async(const url& url) const { - return state_->worker.async([](input_stream_uptr stream){ - buffer buf; - return streams::try_read_tail(buf, stream) - ? std::make_pair(std::move(buf), true) - : std::make_pair(buffer(), false); - }, open(url)); + bool vfs::load(const url& url, buffer& dst) const { + return load_async(url) + .then([&dst](auto&& src){ + dst = std::forward(src); + return true; + }).get_or_default(false); + } + + stdex::promise vfs::load_async(const url& url) const { + return state_->worker.async([this](auto&& url_copy){ + buffer content; + if ( !streams::try_read_tail(content, read(url_copy)) ) { + throw vfs_load_async_exception(); + } + return content; + }, url); + } + + bool vfs::load_as_string(const url& url, str& dst) const { + return load_as_string_async(url) + .then([&dst](auto&& src){ + dst = std::forward(src); + return true; + }).get_or_default(false); + } + + stdex::promise vfs::load_as_string_async(const url& url) const { + return state_->worker.async([this](auto&& url_copy){ + str content; + if ( !streams::try_read_tail(content, read(url_copy)) ) { + throw vfs_load_async_exception(); + } + return content; + }, url); } bool vfs::trace(const url& url, filesystem::trace_func func) const { @@ -250,7 +272,7 @@ namespace e2d MZ_ZIP_FLAG_CASE_SENSITIVE); } - input_stream_uptr archive_file_source::open(str_view path) const { + input_stream_uptr archive_file_source::read(str_view path) const { try { struct owned_state_t { state::archive_ptr archive; @@ -265,19 +287,6 @@ namespace e2d } } - std::pair archive_file_source::load(str_view path) const { - std::size_t mem_size = 0; - void* mem = mz_zip_reader_extract_file_to_heap( - state_->archive.get(), - make_utf8(path).c_str(), - &mem_size, - MZ_ZIP_FLAG_CASE_SENSITIVE); - std::unique_ptr mem_uptr(mem, mz_free); - return mem - ? std::make_pair(buffer(mem, mem_size), true) - : std::make_pair(buffer(), false); - } - output_stream_uptr archive_file_source::write(str_view path, bool append) const { E2D_UNUSED(path, append); return nullptr; @@ -338,17 +347,10 @@ namespace e2d return filesystem::file_exists(path); } - input_stream_uptr filesystem_file_source::open(str_view path) const { + input_stream_uptr filesystem_file_source::read(str_view path) const { return make_read_file(path); } - std::pair filesystem_file_source::load(str_view path) const { - buffer buf; - return filesystem::try_read_all(buf, path) - ? std::make_pair(std::move(buf), true) - : std::make_pair(buffer(), false); - } - output_stream_uptr filesystem_file_source::write(str_view path, bool append) const { if ( !filesystem::create_directory_recursive(path::parent_path(path)) ) { return nullptr; diff --git a/sources/enduro2d/high/assets.cpp b/sources/enduro2d/high/assets.cpp index ae5bba9c..102123e2 100644 --- a/sources/enduro2d/high/assets.cpp +++ b/sources/enduro2d/high/assets.cpp @@ -1390,7 +1390,7 @@ namespace e2d const auto asset_url = library.root() / address; input_stream_uptr stream = modules::is_initialized() - ? the().open(asset_url) + ? the().read(asset_url) : input_stream_uptr(); if ( !stream ) { @@ -1462,7 +1462,7 @@ namespace e2d const auto asset_url = library.root() / address; input_stream_uptr stream = modules::is_initialized() - ? the().open(asset_url) + ? the().read(asset_url) : input_stream_uptr(); if ( !stream ) { diff --git a/untests/sources/untests_core/vfs.cpp b/untests/sources/untests_core/vfs.cpp index 1fb55608..b0c6e6c9 100644 --- a/untests/sources/untests_core/vfs.cpp +++ b/untests/sources/untests_core/vfs.cpp @@ -25,21 +25,27 @@ TEST_CASE("vfs"){ } { buffer b; - auto r = v.open({"file", file_path}); + auto r = v.read({"file", file_path}); REQUIRE(r); REQUIRE(streams::try_read_tail(b, r)); REQUIRE(b == buffer{"hello", 5}); - REQUIRE(v.open({"file2", file_path}) == input_stream_uptr()); - REQUIRE(v.open({"file", nofile_path}) == input_stream_uptr()); + REQUIRE(v.read({"file2", file_path}) == input_stream_uptr()); + REQUIRE(v.read({"file", nofile_path}) == input_stream_uptr()); } { - auto r = v.load({"file", file_path}); - REQUIRE(r.second); - REQUIRE(r.first == buffer{"hello", 5}); + buffer b0; + REQUIRE(v.load({"file", file_path}, b0)); + REQUIRE(b0 == buffer{"hello", 5}); - auto r2 = v.load_async({"file", file_path}).get(); - REQUIRE(r2.second); - REQUIRE(r2.first == buffer{"hello", 5}); + auto b1 = v.load_async({"file", file_path}).get(); + REQUIRE(b1 == buffer{"hello", 5}); + + str b2; + REQUIRE(v.load_as_string({"file", file_path}, b2)); + REQUIRE(b2 == "hello"); + + auto b3 = v.load_as_string_async({"file", file_path}).get(); + REQUIRE(b3 == "hello"); } } { @@ -58,17 +64,17 @@ TEST_CASE("vfs"){ REQUIRE_FALSE(v.register_scheme( "archive", - v.open(url("resources://bin/noresources.zip")))); + v.read(url("resources://bin/noresources.zip")))); REQUIRE(v.register_scheme("file")); REQUIRE_FALSE(v.register_scheme( "archive", - v.open(url("resources://bin/noresources.zip")))); + v.read(url("resources://bin/noresources.zip")))); REQUIRE(v.register_scheme( "archive", - v.open(url("resources://bin/resources.zip")))); + v.read(url("resources://bin/resources.zip")))); REQUIRE(v.exists({"archive", "test.txt"})); REQUIRE_FALSE(v.exists({"archive", "TEst.txt"})); @@ -122,50 +128,70 @@ TEST_CASE("vfs"){ REQUIRE_FALSE(v.extract(url("archive://test.txt"), std::back_inserter(result))); } { - auto f = v.open(url("archive://test.txt")); + auto f = v.read(url("archive://test.txt")); REQUIRE(f); buffer b; REQUIRE(streams::try_read_tail(b, f)); REQUIRE(b == buffer("hello", 5)); } { - auto r = v.load(url("archive://test.txt")); - REQUIRE(r.second); - REQUIRE(r.first == buffer("hello", 5)); + buffer b0; + REQUIRE(v.load(url("archive://test.txt"), b0)); + REQUIRE(b0 == buffer("hello", 5)); - auto r2 = v.load_async(url("archive://test.txt")).get(); - REQUIRE(r2.second); - REQUIRE(r2.first == buffer("hello", 5)); + auto b1 = v.load_async(url("archive://test.txt")).get(); + REQUIRE(b1 == buffer("hello", 5)); + + str b2; + REQUIRE(v.load_as_string(url("archive://test.txt"), b2)); + REQUIRE(b2 == "hello"); + + auto b3 = v.load_as_string_async(url("archive://test.txt")).get(); + REQUIRE(b3 == "hello"); } { - auto f = v.open(url("archive://folder/file.txt")); + auto f = v.read(url("archive://folder/file.txt")); REQUIRE(f); buffer b; REQUIRE(streams::try_read_tail(b, f)); REQUIRE(b == buffer("world", 5)); } { - auto r = v.load(url("archive://folder/file.txt")); - REQUIRE(r.second); - REQUIRE(r.first == buffer("world", 5)); + buffer b0; + REQUIRE(v.load(url("archive://folder/file.txt"), b0)); + REQUIRE(b0 == buffer("world", 5)); - auto r2 = v.load_async(url("archive://folder/file.txt")).get(); - REQUIRE(r2.second); - REQUIRE(r2.first == buffer("world", 5)); + auto b1 = v.load_async(url("archive://folder/file.txt")).get(); + REQUIRE(b1 == buffer("world", 5)); + + str b2; + REQUIRE(v.load_as_string(url("archive://folder/file.txt"), b2)); + REQUIRE(b2 == "world"); + + auto b3 = v.load_as_string_async(url("archive://folder/file.txt")).get(); + REQUIRE(b3 == "world"); } { - REQUIRE(v.open(url("archive://TEst.txt")) == input_stream_uptr()); + REQUIRE(v.read(url("archive://TEst.txt")) == input_stream_uptr()); - auto r = v.load(url("archive://TEst.txt")); - REQUIRE_FALSE(r.second); - REQUIRE(r.first.empty()); + buffer b0; + REQUIRE_FALSE(v.load(url("archive://TEst.txt"), b0)); + REQUIRE(b0.empty()); - auto r2 = v.load_async(url("archive://TEst.txt")).get(); - REQUIRE_FALSE(r2.second); - REQUIRE(r2.first.empty()); + REQUIRE_THROWS_AS( + v.load_async(url("archive://TEst.txt")).get(), + vfs_load_async_exception); + + str b2; + REQUIRE_FALSE(v.load_as_string(url("archive://TEst.txt"), b2)); + REQUIRE(b2.empty()); + + REQUIRE_THROWS_AS( + v.load_as_string_async(url("archive://TEst.txt")).get(), + vfs_load_async_exception); } { - auto f = v.open(url("archive://test.txt")); + auto f = v.read(url("archive://test.txt")); REQUIRE(f); REQUIRE(v.unregister_scheme("archive")); buffer b;