Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: fluent parsing interface #1023

Closed
markand opened this issue Mar 23, 2018 · 8 comments
Closed

RFC: fluent parsing interface #1023

markand opened this issue Mar 23, 2018 · 8 comments
Labels
state: needs more info the author of the issue needs to provide more details

Comments

@markand
Copy link

markand commented Mar 23, 2018

Feature Request

I'm searching a convenient way for destructuring data where I can have the following requirements:

  • I do not need intermediate value, result should be returned in any case
  • If I require a value from a JSON object and...
    • ... value is not defined: I throw a custom exception
    • ... value is not the good type: I throw an exception
  • If I search an optional value and...
    • ... value is not defined: I return a default value given
    • ... value is not the good type: I throw an exception

Final code should look like this:

const nlohmann::json json{
    { "hostname", "localhost" }
};

const parser ps(json);

// s is a object I want to convert from JSON.
server s;
s.set_host(ps.get<std::string>("hostname")
             .error<std::invalid_argument>("invalid hostname"));
s.set_port(ps.get<std::string>("port")
             .optional("irc")
             .error<std::runtime_error>("invalid port number"));

In this case, I require hostname property, if it's missing std::invalid_argument("invalid hostname") will be thrown. For port property, if the value is not defined, I return irc otherwise if it's defined in the wrong type I throw std::invalid_argument("invalid port number").

The code is not complete yet, but you can see a simple POC in this gist:

https://gist.github.com/markand/45c9f6a3f9239802850badd8869117e3

What are your thoughts? How do you usually deserialize unverified input?

@OvermindDL1
Copy link

OvermindDL1 commented Mar 23, 2018

I'd probably just opt for an API like:

server s;
s.set_host(ps.get<std::string>("hostname", [](nlohmann::json*){
             throw std::invalid_argument("invalid hostname");
           });
s.set_port(ps.get<std::string>("port", [](nlohmann::json *value){
             if(value == null) return "irc";
             throw std::runtime_error("invalid port number");
           });

Or even have it be a 3-arity and have this form supported as well:

s.set_port(ps.get<std::string>("port", "irc", [](nlohmann::json&){
             throw std::runtime_error("invalid port number");
           });

In essence have get<...>(...) accept a single argument of which value to get, 2 arguments where the second argument can be one of 3 types, a default value of the same type that appears as the template (or coercable to it), is a function/lambda that takes no argument (generally used to return a 'complex' default value that could be costly to always generate otherwise), or a function/lambda that takes a json value pointer (which can be null if it did not exist in the structure, else it is the value that was not coercable to the given template type). Or it could take 3 arguments, where the first is the key to look up, the second is either a default value of the templated type or a function/lambda that takes no argument (used only if the value does not exist), and the 3rd being a function/lambda that takes a json value reference (not pointer, as this is only called if the value exists but is not coercable to the given template type). Maybe throw in some consts too.

@nlohmann
Copy link
Owner

Did you try the current callback function? Note there will soon also be a SAX interface, see #971.

@markand
Copy link
Author

markand commented Mar 26, 2018

I can't because the JSON document is already parsed when I have to destructure it. But it's a good idea too.

@nlohmann
Copy link
Owner

If you do not need to parse, then the title is misleading...

@nlohmann
Copy link
Owner

I am confused. Could you please elaborate in which sense you could not implement your usecase with user functions (i.e., the library's public API) or why an extension would be valuable also to other clients?

@nlohmann nlohmann added the state: needs more info the author of the issue needs to provide more details label Mar 27, 2018
@nlohmann
Copy link
Owner

@markand Could you elaborate?

@dvhwgumby
Copy link

@markand what would be wrong with simply doing s.set_host(validate_hostname(ps.get<std::string>("hostname")));?

You could simply put all the validation code, exception throwing etc in validate_hostname().

@nlohmann
Copy link
Owner

nlohmann commented Apr 4, 2018

@markand Can I close this issue?

@markand markand closed this as completed Apr 5, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
state: needs more info the author of the issue needs to provide more details
Projects
None yet
Development

No branches or pull requests

4 participants