Skip to content

Commit

Permalink
Add non-throwing variants of parse() and ()
Browse files Browse the repository at this point in the history
  • Loading branch information
nordlow committed Aug 15, 2018
1 parent bb769cf commit 31b89a8
Showing 1 changed file with 82 additions and 19 deletions.
101 changes: 82 additions & 19 deletions std/conv.d
Original file line number Diff line number Diff line change
Expand Up @@ -2636,6 +2636,83 @@ do
assert(parse!uint(str) == 0);
}

struct Expected(Result, Error)
{
this(Result result) @trusted
{
this.result = result;
this._hasResult = true;
}
static typeof(this) asError(Error error) @trusted
{
typeof(this) that = void;
that.error = error;
that._hasResult = false;
return that;
}

~this() @trusted
{
if (_hasResult)
{
destroy(error);
}
else
{
destroy(result);
}
}

@property hasResult() const { return _hasResult; }

union
{
Result result;
Error error;
}
bool _hasResult; // TODO don't waste bool here
}

Expected!(Target, string) tryParse(Target, Source)(ref Source s)
if (isSomeString!Source && !is(Source == enum) &&
is(Target == enum))
{
import std.algorithm.searching : startsWith;
Target result;
size_t longest_match = 0;

foreach (i, e; EnumMembers!Target)
{
auto ident = __traits(allMembers, Target)[i];
if (longest_match < ident.length && s.startsWith(ident))
{
result = e;
longest_match = ident.length ;
}
}

if (longest_match > 0)
{
s = s[longest_match .. $];
return typeof(return)(result);
}

return typeof(return).asError(Target.stringof ~ " does not have a member named '"
~ to!string(s) ~ "'");
}

///
@safe unittest
{
enum EnumType : bool { a = true, b = false, c = a }

auto str = "a";
auto expected = tryParse!EnumType(str);
// TODO: find a simpler and robuster syntax for this:
assert(expected.hasResult &&
expected.result == EnumType.a);
}

/**
* Takes a string representing an `enum` type and returns that type.
*
Expand All @@ -2654,29 +2731,15 @@ Target parse(Target, Source)(ref Source s)
if (isSomeString!Source && !is(Source == enum) &&
is(Target == enum))
{
import std.algorithm.searching : startsWith;
Target result;
size_t longest_match = 0;

foreach (i, e; EnumMembers!Target)
auto expected = tryParse!(Target, Source)(s);
if (expected.hasResult)
{
auto ident = __traits(allMembers, Target)[i];
if (longest_match < ident.length && s.startsWith(ident))
{
result = e;
longest_match = ident.length ;
}
return expected.result;
}

if (longest_match > 0)
else
{
s = s[longest_match .. $];
return result ;
throw new ConvException(expected.error);
}

throw new ConvException(
Target.stringof ~ " does not have a member named '"
~ to!string(s) ~ "'");
}

///
Expand Down

0 comments on commit 31b89a8

Please sign in to comment.