Last active
November 17, 2022 23:42
-
-
Save MichalBrylka/faf99aed6a2c307a5cb9f763bed5e241 to your computer and use it in GitHub Desktop.
Static Interface Members
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var parsedLines = Lines<CommaSeparatedWords>.Parse(""" | |
Ala,has,a,cat | |
Cat,has,Ala | |
"""); | |
var parsedNumbers = CsvFile<int>.Parse(""" | |
11 | |
22 | |
33 | |
"""); | |
var parsedStructs = CsvFile<CsvLine<int, float, char>>.Parse(""" | |
11,1.1,A | |
22,2.2,B | |
33,3.3,C | |
"""); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net7.0</TargetFramework> | |
<ImplicitUsings>enable</ImplicitUsings> | |
<Nullable>enable</Nullable> | |
<LangVersion>11.0</LangVersion> | |
</PropertyGroup> | |
<ItemGroup> | |
<Using Include="System.Diagnostics" /> | |
<Using Include="System.Diagnostics.CodeAnalysis" /> | |
<Using Include="System.Globalization" /> | |
<Using Include="System.Numerics" /> | |
<Using Include="System.Runtime.CompilerServices" /> | |
</ItemGroup> | |
<ItemGroup> | |
<PackageReference Include="Nemesis.TextParsers" /> | |
</ItemGroup> | |
</Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using Nemesis.TextParsers; | |
namespace Demo; | |
public interface IMyParsable<TSelf> | |
where TSelf : IMyParsable<TSelf>? | |
{ | |
static abstract TSelf Parse(ReadOnlySpan<char> s, IFormatProvider? provider); | |
static TSelf InvariantParse(ReadOnlySpan<char> s) => | |
TSelf.Parse(s, CultureInfo.InvariantCulture); | |
static virtual TSelf Parse(string s, IFormatProvider? provider) => | |
TSelf.Parse(s.AsSpan(), provider); | |
static virtual bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out TSelf result) | |
{ | |
result = default; | |
if (s == null) return false; | |
try | |
{ | |
result = TSelf.Parse(s.AsSpan(), provider); | |
return true; | |
} | |
catch (Exception) | |
{ | |
return false; | |
} | |
} | |
static virtual bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, [MaybeNullWhen(false)] out TSelf result) | |
{ | |
try | |
{ | |
result = TSelf.Parse(s, provider); | |
return true; | |
} | |
catch (Exception) | |
{ | |
result = default; | |
return false; | |
} | |
} | |
} | |
record Lines<T>(IReadOnlyList<T> Values) : IEnumerable<T>, IMyParsable<Lines<T>> | |
where T : IMyParsable<T> | |
{ | |
public static Lines<T> Parse(ReadOnlySpan<char> s, IFormatProvider? provider = null) | |
{ | |
var splitText = s.EnumerateLines(); | |
var lines = new List<T>(); | |
foreach (var line in splitText) | |
lines.Add(T.Parse(line, provider)); | |
//this also works in this context | |
//var canParse = T.TryParse("", provider, out var result); | |
return new(lines); | |
} | |
public override string ToString() => string.Join(Environment.NewLine, Values); | |
public IEnumerator<T> GetEnumerator() => Values.GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => Values.GetEnumerator(); | |
} | |
record CommaSeparatedWords(IReadOnlyList<string> Words) : IMyParsable<CommaSeparatedWords>, IEnumerable<string> | |
{ | |
public static CommaSeparatedWords Parse(ReadOnlySpan<char> s, IFormatProvider? provider) | |
{ | |
var words = new List<string>(); | |
foreach (var word in s.Split(',')) | |
words.Add(word.ToString()); | |
return new(words); | |
} | |
public override string ToString() => string.Join(",", Words); | |
public IEnumerator<string> GetEnumerator() => Words.GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => Words.GetEnumerator(); | |
} | |
record CsvFile<T>(IReadOnlyList<T> Lines) : ISpanParsable<CsvFile<T>> | |
where T : ISpanParsable<T> | |
{ | |
public static CsvFile<T> Parse(ReadOnlySpan<char> s, IFormatProvider? provider = null) | |
{ | |
var splitText = s.EnumerateLines(); | |
var lines = new List<T>(); | |
foreach (var line in splitText) | |
lines.Add(T.Parse(line, provider)); | |
return new(lines); | |
} | |
public static CsvFile<T> Parse(string s, IFormatProvider? provider = null) => | |
Parse(s.AsSpan(), provider); | |
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, [MaybeNullWhen(false)] out CsvFile<T> result) | |
{ | |
try | |
{ | |
result = Parse(s, provider); | |
return true; | |
} | |
catch (Exception) | |
{ | |
result = default; | |
return false; | |
} | |
} | |
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out CsvFile<T> result) | |
{ | |
result = default; | |
if (s == null) return false; | |
try | |
{ | |
result = Parse(s.AsSpan(), provider); | |
return true; | |
} | |
catch (Exception) | |
{ | |
return false; | |
} | |
} | |
} | |
readonly record struct CsvLine<T1, T2, T3>(T1 Item1, T2 Item2, T3 Item3) : ISpanParsable<CsvLine<T1, T2, T3>> | |
where T1 : ISpanParsable<T1> | |
where T2 : ISpanParsable<T2> | |
where T3 : ISpanParsable<T3> | |
{ | |
public static CsvLine<T1, T2, T3> Parse(ReadOnlySpan<char> s, IFormatProvider? provider = null) | |
{ | |
var enumerator = s.Split(',').GetEnumerator(); | |
if (!enumerator.MoveNext()) throw new("No element at 1st position"); | |
var t1 = T1.Parse(enumerator.Current, CultureInfo.InvariantCulture); | |
if (!enumerator.MoveNext()) throw new("No element at 2nd position"); | |
var t2 = T2.Parse(enumerator.Current, CultureInfo.InvariantCulture); | |
if (!enumerator.MoveNext()) throw new("No element at 3rd position"); | |
var t3 = T3.Parse(enumerator.Current, CultureInfo.InvariantCulture); | |
return new(t1, t2, t3); | |
} | |
public static CsvLine<T1, T2, T3> Parse(string s, IFormatProvider? provider) => | |
Parse(s.AsSpan(), provider); | |
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, [MaybeNullWhen(false)] out CsvLine<T1, T2, T3> result) | |
{ | |
try | |
{ | |
result = Parse(s, provider); | |
return true; | |
} | |
catch (Exception) | |
{ | |
result = default; | |
return false; | |
} | |
} | |
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out CsvLine<T1, T2, T3> result) | |
{ | |
result = default; | |
if (s == null) return false; | |
try | |
{ | |
result = Parse(s.AsSpan(), provider); | |
return true; | |
} | |
catch (Exception) | |
{ | |
return false; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment