Commit d12398ad authored by Dominik Charousset's avatar Dominik Charousset

Allow parsing JSON directly from file

parent e8db2cb1
...@@ -682,7 +682,19 @@ const array* empty_array() noexcept; ...@@ -682,7 +682,19 @@ const array* empty_array() noexcept;
// -- parsing ------------------------------------------------------------------ // -- parsing ------------------------------------------------------------------
// Parses the input and makes a deep copy of all strings. // Specialization for parsers operating on mutable character sequences.
using mutable_string_parser_state = parser_state<char*>;
// Specialization for parsers operating on files.
using file_parser_state = parser_state<std::istreambuf_iterator<char>>;
// Parses the input string and makes a deep copy of all strings.
value* parse(string_parser_state& ps, monotonic_buffer_resource* storage);
// Parses the input string and makes a deep copy of all strings.
value* parse(file_parser_state& ps, monotonic_buffer_resource* storage);
// Parses the input file and makes a deep copy of all strings.
value* parse(string_parser_state& ps, monotonic_buffer_resource* storage); value* parse(string_parser_state& ps, monotonic_buffer_resource* storage);
// Parses the input and makes a shallow copy of strings whenever possible. // Parses the input and makes a shallow copy of strings whenever possible.
......
...@@ -133,6 +133,17 @@ public: ...@@ -133,6 +133,17 @@ public:
/// @note Implicitly calls `reset`. /// @note Implicitly calls `reset`.
bool load(std::string_view json_text); bool load(std::string_view json_text);
/// Parses the content of the file under the given @p path. After loading the
/// content of the JSON file, the reader is ready for attempting to
/// deserialize inspectable objects.
/// @note Implicitly calls `reset`.
bool load_file(const char* path);
/// @copydoc load_file
bool load_file(const std::string& path) {
return load_file(path.c_str());
}
/// Reverts the state of the reader back to where it was after calling `load`. /// Reverts the state of the reader back to where it was after calling `load`.
/// @post The reader is ready for attempting to deserialize another /// @post The reader is ready for attempting to deserialize another
/// inspectable object. /// inspectable object.
......
...@@ -134,6 +134,13 @@ public: ...@@ -134,6 +134,13 @@ public:
/// objects created from that value. /// objects created from that value.
static expected<json_value> parse_in_situ(std::string& str); static expected<json_value> parse_in_situ(std::string& str);
/// Attempts to parse the content of the file at @p path as JSON input into a
/// self-contained value.
static expected<json_value> parse_file(const char* path);
/// @copydoc parse_file
static expected<json_value> parse_file(const std::string& path);
// -- printing --------------------------------------------------------------- // -- printing ---------------------------------------------------------------
template <class Buffer> template <class Buffer>
......
...@@ -141,7 +141,4 @@ auto make_error(const parser_state<Iterator, Sentinel>& ps, Ts&&... xs) ...@@ -141,7 +141,4 @@ auto make_error(const parser_state<Iterator, Sentinel>& ps, Ts&&... xs)
/// Specialization for parsers operating on string views. /// Specialization for parsers operating on string views.
using string_parser_state = parser_state<std::string_view::iterator>; using string_parser_state = parser_state<std::string_view::iterator>;
/// Specialization for parsers operating on mutable character sequences.
using mutable_string_parser_state = parser_state<char*>;
} // namespace caf } // namespace caf
This diff is collapsed.
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "caf/detail/print.hpp" #include "caf/detail/print.hpp"
#include "caf/string_algorithms.hpp" #include "caf/string_algorithms.hpp"
#include <fstream>
namespace { namespace {
static constexpr const char class_name[] = "caf::json_reader"; static constexpr const char class_name[] = "caf::json_reader";
...@@ -150,14 +152,36 @@ bool json_reader::load(std::string_view json_text) { ...@@ -150,14 +152,36 @@ bool json_reader::load(std::string_view json_text) {
set_error(make_error(ps)); set_error(make_error(ps));
st_ = nullptr; st_ = nullptr;
return false; return false;
} else {
err_.reset();
detail::monotonic_buffer_resource::allocator<stack_type> alloc{&buf_};
st_ = new (alloc.allocate(1)) stack_type(stack_allocator{&buf_});
st_->reserve(16);
st_->emplace_back(root_);
return true;
} }
err_.reset();
detail::monotonic_buffer_resource::allocator<stack_type> alloc{&buf_};
st_ = new (alloc.allocate(1)) stack_type(stack_allocator{&buf_});
st_->reserve(16);
st_->emplace_back(root_);
return true;
}
bool json_reader::load_file(const char* path) {
using iterator_t = std::istreambuf_iterator<char>;
reset();
std::ifstream input{path};
if (!input.is_open()) {
emplace_error(sec::cannot_open_file);
return false;
}
detail::json::file_parser_state ps{iterator_t{input}, iterator_t{}};
root_ = detail::json::parse(ps, &buf_);
if (ps.code != pec::success) {
set_error(make_error(ps));
st_ = nullptr;
return false;
}
err_.reset();
detail::monotonic_buffer_resource::allocator<stack_type> alloc{&buf_};
st_ = new (alloc.allocate(1)) stack_type(stack_allocator{&buf_});
st_->reserve(16);
st_->emplace_back(root_);
return true;
} }
void json_reader::revert() { void json_reader::revert() {
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "caf/make_counted.hpp" #include "caf/make_counted.hpp"
#include "caf/parser_state.hpp" #include "caf/parser_state.hpp"
#include <fstream>
namespace caf { namespace caf {
// -- conversion --------------------------------------------------------------- // -- conversion ---------------------------------------------------------------
...@@ -92,35 +94,49 @@ expected<json_value> json_value::parse(std::string_view str) { ...@@ -92,35 +94,49 @@ expected<json_value> json_value::parse(std::string_view str) {
auto storage = make_counted<detail::json::storage>(); auto storage = make_counted<detail::json::storage>();
string_parser_state ps{str.begin(), str.end()}; string_parser_state ps{str.begin(), str.end()};
auto root = detail::json::parse(ps, &storage->buf); auto root = detail::json::parse(ps, &storage->buf);
if (ps.code != pec::success) { if (ps.code == pec::success)
return {make_error(ps)};
} else {
return {json_value{root, std::move(storage)}}; return {json_value{root, std::move(storage)}};
} return {make_error(ps)};
} }
expected<json_value> json_value::parse_shallow(std::string_view str) { expected<json_value> json_value::parse_shallow(std::string_view str) {
auto storage = make_counted<detail::json::storage>(); auto storage = make_counted<detail::json::storage>();
string_parser_state ps{str.begin(), str.end()}; string_parser_state ps{str.begin(), str.end()};
auto root = detail::json::parse_shallow(ps, &storage->buf); auto root = detail::json::parse_shallow(ps, &storage->buf);
if (ps.code != pec::success) { if (ps.code == pec::success)
return {make_error(ps)};
} else {
return {json_value{root, std::move(storage)}}; return {json_value{root, std::move(storage)}};
} return {make_error(ps)};
} }
expected<json_value> json_value::parse_in_situ(std::string& str) { expected<json_value> json_value::parse_in_situ(std::string& str) {
auto storage = make_counted<detail::json::storage>(); auto storage = make_counted<detail::json::storage>();
mutable_string_parser_state ps{str.data(), str.data() + str.size()}; detail::json::mutable_string_parser_state ps{str.data(),
str.data() + str.size()};
auto root = detail::json::parse_in_situ(ps, &storage->buf); auto root = detail::json::parse_in_situ(ps, &storage->buf);
if (ps.code != pec::success) { if (ps.code == pec::success)
return {make_error(ps)};
} else {
return {json_value{root, std::move(storage)}}; return {json_value{root, std::move(storage)}};
} return {make_error(ps)};
}
expected<json_value> json_value::parse_file(const char* path) {
using iterator_t = std::istreambuf_iterator<char>;
std::ifstream input{path};
if (!input.is_open())
return make_error(sec::cannot_open_file);
auto storage = make_counted<detail::json::storage>();
detail::json::file_parser_state ps{iterator_t{input}, iterator_t{}};
auto root = detail::json::parse(ps, &storage->buf);
if (ps.code == pec::success)
return {json_value{root, std::move(storage)}};
return {make_error(ps)};
} }
expected<json_value> json_value::parse_file(const std::string& path) {
return parse_file(path.c_str());
}
// -- free functions -----------------------------------------------------------
std::string to_string(const json_value& val) { std::string to_string(const json_value& val) {
std::string result; std::string result;
val.print_to(result); val.print_to(result);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment