Skip to content

Commit

Permalink
optimize code
Browse files Browse the repository at this point in the history
  • Loading branch information
tinohager committed Jan 20, 2025
1 parent cb0bfda commit 83f4152
Showing 1 changed file with 22 additions and 16 deletions.
38 changes: 22 additions & 16 deletions src/Nager.EmailAuthentication/KeyValueParserBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,53 @@

namespace Nager.EmailAuthentication
{
/// <summary>
/// Base class for parsing key-value pairs into a strongly-typed object of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of the target object for parsed data. Must be a reference type with a parameterless constructor.</typeparam>
internal class KeyValueParserBase<T> where T : class, new()
{
private readonly Dictionary<string, MappingHandler<T>> _mappingHandlers;
private readonly IKeyValueParser _keyValueParser;
private readonly char _keyValueSeperator;
private readonly char _keyValueSeparator;

/// <summary>
/// Initializes a new instance of the <see cref="KeyValueParserBase{T}"/> class.
/// </summary>
/// <param name="mappingHandlers">A dictionary of handlers to map and validate key-value pairs to properties of <typeparamref name="T"/>.</param>
public KeyValueParserBase(
Dictionary<string, MappingHandler<T>> mappingHandlers)
{
this._mappingHandlers = mappingHandlers;

var tagDelimiter = ';';
this._keyValueSeperator = '=';
this._keyValueParser = new MemoryEfficientKeyValueParser(tagDelimiter, this._keyValueSeperator);
this._keyValueSeparator = '=';
this._keyValueParser = new MemoryEfficientKeyValueParser(tagDelimiter, this._keyValueSeparator);
}

/// <summary>
/// Attempts to parse raw key-value data into an object of type <typeparamref name="T"/>.
/// </summary>
/// <param name="rawData">The raw input string containing key-value pairs.</param>
/// <param name="dataFragment">The parsed object of type <typeparamref name="T"/> if parsing is successful; otherwise, null.</param>
/// <param name="parseErrors">An array of parsing errors or warnings, if any; otherwise, null.</param>
/// <returns>True if at least one key-value pair is successfully mapped; otherwise, false.</returns>
public bool TryParse(
string rawData,
out T? dataFragment,
out ParseError[]? parseErrors)
{
parseErrors = null;

if (!this._keyValueParser.TryParse(rawData, out var parseResult))
{
dataFragment = null;
return false;
}

if (parseResult == null)
if (!this._keyValueParser.TryParse(rawData, out var parseResult) || parseResult == null)
{
dataFragment = null;
return false;
}

var errors = new List<ParseError>();

// Detect duplicate keys
var duplicateConfigurations = parseResult.KeyValues
.GroupBy(o => o.Key)
.Where(g => g.Count() > 1);
Expand All @@ -54,7 +64,6 @@ public bool TryParse(
}

var tempDataFragment = new T();

var mappingFound = false;

foreach (var keyValue in parseResult.KeyValues)
Expand All @@ -69,27 +78,24 @@ public bool TryParse(
if (handler.Validate != null)
{
var mappingErrors = handler.Validate(new ValidateRequest { Field = keyValue.Key, Value = keyValue.Value });
if (mappingErrors != null && mappingErrors.Length > 0)
if (mappingErrors?.Length > 0)
{
errors.AddRange(mappingErrors);
}
}
handler.Map(tempDataFragment, keyValue.Value ?? "");

mappingFound = true;

continue;
}

errors.Add(new ParseError
{
ErrorMessage = $"Unrecognized Part {keyValue.Key}{this._keyValueSeperator}{keyValue.Value}",
ErrorMessage = $"Unrecognized part: {keyValue.Key}{this._keyValueSeparator}{keyValue.Value}",
Severity = ErrorSeverity.Warning
});
}

parseErrors = errors.Count == 0 ? null : [.. errors];

dataFragment = tempDataFragment;

return mappingFound;
Expand Down

0 comments on commit 83f4152

Please sign in to comment.