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

Enforcing format of custom types for non-mandatory values #198

Open
tsilia opened this issue Aug 17, 2022 · 0 comments
Open

Enforcing format of custom types for non-mandatory values #198

tsilia opened this issue Aug 17, 2022 · 0 comments

Comments

@tsilia
Copy link

tsilia commented Aug 17, 2022

Hello. I've ran into an issue which seems to be caused by some minor design flaw.

Suppose I have a custom type that I'd like to deserialize from toml and which must be stored in a non-mandatory value (i.e., it can be omitted from toml file and be set to some default value):

struct Foo
{
    int a, b, c, d;
};

I'd like to be able to set the value to some default if it's not present in the toml file, and raise an exception if the value specified in the toml file has incorrect format.
Now, when I'm trying to parse the following toml file

[table]
foo = "4_:5:6:7"

with the following code, I won't get any exception, and the value that obviously has incorrect format (not matches regular expression), is getting silently replaced by a default one:

#include <iostream>
#include <regex>
#include <string>

#include <toml.hpp>

using std::cout, std::cerr, std::endl;

struct Foo
{
	int a, b, c, d;
};

namespace toml
{
	template <>
	struct from<Foo>
	{
		static Foo from_toml(const value &v)
		{
			Foo f{};
			std::smatch m;
			const std::regex r(R"((\d+):(\d+):(\d+))");
			const std::string s = v.as_string();
			if (!std::regex_match(s, m, r))
				throw toml::syntax_error("Incorrect format", v.location());
			f.a = std::stoi(m[1].str());
			f.b = std::stoi(m[2].str());
			f.c = std::stoi(m[3].str());
			return f;
		}
	};
}

int main(int, char **)
{
	Foo foo{};
	try
	{
		const auto v = toml::parse("test.toml");
		const auto t = toml::find(v, "table");
		// here I'd like to get default Foo{1,2,3} if the value is omitted from the toml file,
		//    and get an exception if the value is present and has incorrect format:
		foo = toml::find_or(t, "foo", Foo{1, 2, 3});
	}
	catch (const std::exception &ex)
	{
		cerr << "Exception occurred: " << ex.what() << endl;
	}
	cout << "foo: " << foo.a << " " << foo.b << " " << foo.c << endl;
	cout << "end of main" << endl;
}

Here's the output I get:

foo: 1 2 3
end of main

So, the library apparently uses catch(...) somewhere in the implementation of find_or which makes it impossible to enforce proper format for non-mandatory values via throwing an exception in from_toml. If you change toml::find_or to toml::find in the code above you'll get an exception, but I can't use toml::find in this particular case.
Is there any way to overcome this?
Perhaps, you could reconsider the design choice and, say, make a distinction between an omitted value and custom value that has incorrect format by introducing some special exception for those who need to implement their own from_toml.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant