Skip to content

Commit 987ff2f

Browse files
committed
implement IParseable<MimeType> and ISpanParseable<MimeType>
1 parent cafe5bf commit 987ff2f

File tree

5 files changed

+197
-18
lines changed

5 files changed

+197
-18
lines changed

src/Smdn.Fundamental.MimeType/Smdn.Fundamental.MimeType.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ SPDX-License-Identifier: MIT
1818
<PackageTags>MIME;MIME-type</PackageTags>
1919
</PropertyGroup>
2020

21+
<!-- enable feature 'generic math' -->
22+
<Import Project="..\FeatureGenericMath.props" />
23+
2124
<ItemGroup>
2225
<ProjectReference VersionRange="[3.0.0,4.0.0)" Include="..\Smdn.Fundamental.Exception\Smdn.Fundamental.Exception.csproj" />
2326
<PackageReference Include="System.Memory" />

src/Smdn.Fundamental.MimeType/Smdn/MimeType.IParseable.cs

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ partial class MimeType
2020
#pragma warning restore IDE0040
2121
#if FEATURE_GENERIC_MATH
2222
:
23-
#if !OBSOLETE_MEMBER
24-
IParseable<MimeType>,
25-
#endif
2623
ISpanParseable<MimeType>
2724
#endif
2825
{
@@ -43,14 +40,57 @@ public static bool TryParse(
4340
[NotNullWhen(true)]
4441
#endif
4542
out MimeType? result
43+
)
44+
=> TryParse(s, provider: null, out result);
45+
46+
// IParseable<TSelf>.TryParse
47+
public static bool TryParse(
48+
string? s,
49+
IFormatProvider? provider,
50+
#if NULL_STATE_STATIC_ANALYSIS_ATTRIBUTES
51+
[NotNullWhen(true)]
52+
#endif
53+
out MimeType result
4654
)
4755
{
48-
result = null;
56+
result = null!;
4957

5058
if (s is null)
5159
return false;
52-
if (!TryParse(s.AsSpan(), nameof(s), onParseError: OnParseError.ReturnFalse, out var ret))
60+
61+
if (
62+
!TryParse(
63+
s.AsSpan(),
64+
nameof(s),
65+
onParseError: OnParseError.ReturnFalse,
66+
provider: provider,
67+
out var ret
68+
)
69+
) {
5370
return false;
71+
}
72+
73+
result = new(ret);
74+
75+
return true;
76+
}
77+
78+
// ISpanParseable<TSelf>.TryParse
79+
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out MimeType result)
80+
{
81+
result = null!;
82+
83+
if (
84+
!TryParse(
85+
s,
86+
nameof(s),
87+
onParseError: OnParseError.ReturnFalse,
88+
provider: provider,
89+
out var ret
90+
)
91+
) {
92+
return false;
93+
}
5494

5595
result = new(ret);
5696

@@ -63,19 +103,35 @@ out MimeType? result
63103
public static (string type, string subType) Parse(string s)
64104
=> MimeTypeStringExtensions.Split(s);
65105
#pragma warning restore SA1316
66-
#else
67-
public static MimeType Parse(string s)
106+
#endif
107+
108+
// IParseable<TSelf>.Parse
109+
public static MimeType Parse(string s, IFormatProvider? provider = null)
68110
{
69111
TryParse(
70112
s: (s ?? throw new ArgumentNullException(nameof(s))).AsSpan(),
71113
paramName: nameof(s),
72-
throwIfInvalid: OnParseError.ThrowFormatException,
114+
onParseError: OnParseError.ThrowFormatException,
115+
provider: provider,
116+
out var result
117+
);
118+
119+
return new(result.Type, result.SubType);
120+
}
121+
122+
// ISpanParseable<TSelf>.Parse
123+
public static MimeType Parse(ReadOnlySpan<char> s, IFormatProvider? provider = null)
124+
{
125+
TryParse(
126+
s: s,
127+
paramName: nameof(s),
128+
onParseError: OnParseError.ThrowFormatException,
129+
provider: provider,
73130
out var result
74131
);
75132

76133
return new(result.Type, result.SubType);
77134
}
78-
#endif
79135

80136
internal enum OnParseError {
81137
ThrowFormatException,
@@ -87,6 +143,9 @@ internal static bool TryParse(
87143
ReadOnlySpan<char> s,
88144
string paramName,
89145
OnParseError onParseError,
146+
#pragma warning disable IDE0060
147+
IFormatProvider? provider,
148+
#pragma warning restore IDE0060
90149
out (string Type, string SubType) result
91150
)
92151
{

src/Smdn.Fundamental.MimeType/Smdn/MimeTypeStringExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static bool TrySplit(
2121
s: mimeType.AsSpan(),
2222
paramName: nameof(mimeType),
2323
onParseError: MimeType.OnParseError.ReturnFalse,
24+
provider: null,
2425
out result
2526
);
2627
}
@@ -40,6 +41,7 @@ string paramName
4041
s: mimeType.AsSpan(),
4142
paramName: paramName,
4243
onParseError: MimeType.OnParseError.ThrowArgumentException,
44+
provider: null,
4345
out var result
4446
);
4547

tests/Smdn.Fundamental.MimeType/Smdn.Fundamental.MimeType.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ SPDX-License-Identifier: MIT
1111
<ItemGroup>
1212
<PackageReference Include="Smdn.Test.NUnit.Utils" />
1313
</ItemGroup>
14+
15+
<!-- enable feature 'generic math' -->
16+
<Import Project="..\..\src\FeatureGenericMath.props" />
1417
</Project>

tests/Smdn.Fundamental.MimeType/Smdn/MimeType.cs

Lines changed: 121 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -239,26 +239,138 @@ private static System.Collections.IEnumerable YieldParseInvalidFormatTestCases()
239239
yield return new object[] { "text/plain/foo", typeof(FormatException) };
240240
}
241241

242-
#if false
243242
[TestCaseSource(nameof(YieldParseValidTestCases))]
244243
public void TestParse(string s, MimeType expected)
245-
=> Assert.AreEqual((expected.Type, expected.SubType), MimeType.Parse(s));
246-
#endif
244+
=> Assert.AreEqual(expected, MimeType.Parse(s, provider: null));
245+
246+
[TestCaseSource(nameof(YieldParseValidTestCases))]
247+
public void TestParse_ReadOnlySpanOfChar(string s, MimeType expected)
248+
=> Assert.AreEqual(expected, MimeType.Parse(s.AsSpan(), provider: null));
247249

248250
[TestCaseSource(nameof(YieldParseValidTestCases))]
249251
public void TestTryParse(string s, MimeType expected)
250252
{
251-
Assert.IsTrue(MimeType.TryParse(s, out MimeType result));
253+
Assert.IsTrue(MimeType.TryParse(s, provider: null, out var result));
252254
Assert.AreEqual(expected, result);
253255
}
254256

255-
#if false
257+
[TestCaseSource(nameof(YieldParseValidTestCases))]
258+
public void TestTryParse_ReadOnlySpanOfChar(string s, MimeType expected)
259+
{
260+
Assert.IsTrue(MimeType.TryParse(s.AsSpan(), provider: null, out var result));
261+
Assert.AreEqual(expected, result);
262+
}
263+
264+
#if FEATURE_GENERIC_MATH
265+
[TestCaseSource(nameof(YieldParseValidTestCases))]
266+
public void IParseable_Parse(string s, MimeType expected)
267+
{
268+
Assert.AreEqual(expected, Parse<MimeType>(s));
269+
270+
static TSelf Parse<TSelf>(string s) where TSelf : IParseable<TSelf>
271+
=> TSelf.Parse(s, provider: null);
272+
}
273+
274+
[TestCaseSource(nameof(YieldParseValidTestCases))]
275+
public void ISpanParseable_Parse(string s, MimeType expected)
276+
{
277+
Assert.AreEqual(expected, Parse<MimeType>(s.AsSpan()));
278+
279+
static TSelf Parse<TSelf>(ReadOnlySpan<char> s) where TSelf : ISpanParseable<TSelf>
280+
=> TSelf.Parse(s, provider: null);
281+
}
282+
283+
[TestCaseSource(nameof(YieldParseValidTestCases))]
284+
public void IParseable_TryParse(string s, MimeType expected)
285+
{
286+
Assert.IsTrue(TryParse<MimeType>(s, out var result));
287+
Assert.AreEqual(expected, result);
288+
289+
static bool TryParse<TSelf>(string s, out TSelf result) where TSelf : IParseable<TSelf>
290+
=> TSelf.TryParse(s, provider: null, out result);
291+
}
292+
293+
[TestCaseSource(nameof(YieldParseValidTestCases))]
294+
public void ISpanParseable_TryParse(string s, MimeType expected)
295+
{
296+
Assert.IsTrue(TryParse<MimeType>(s.AsSpan(), out var result));
297+
Assert.AreEqual(expected, result);
298+
299+
static bool TryParse<TSelf>(ReadOnlySpan<char> s, out TSelf result) where TSelf : ISpanParseable<TSelf>
300+
=> TSelf.TryParse(s, provider: null, out result);
301+
}
302+
#endif
303+
256304
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
257305
public void TestParse_InvalidFormat(string s, Type expectedExceptionType)
258-
=> Assert.Throws(expectedExceptionType, () => MimeType.Parse(s));
259-
#endif
306+
=> Assert.Throws(expectedExceptionType, () => MimeType.Parse(s, provider: null));
307+
308+
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
309+
public void TestParse_ReadOnlySpanOfChar_InvalidFormat(string s, Type expectedExceptionType)
310+
{
311+
if (s is null)
312+
Assert.Pass();
313+
314+
Assert.Throws(expectedExceptionType, () => MimeType.Parse(s.AsSpan(), provider: null));
315+
}
260316

261317
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
262-
public void TestTryParse_InvalidFormat(string s, Type _)
263-
=> Assert.IsFalse(MimeType.TryParse(s, out MimeType _));
318+
public void TestTryParse_InvalidFormat(string s, Type discard)
319+
=> Assert.IsFalse(MimeType.TryParse(s, provider: null, out _));
320+
321+
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
322+
public void TestTryParse_ReadOnlySpanOfChar_InvalidFormat(string s, Type discard)
323+
{
324+
if (s is null)
325+
Assert.Pass();
326+
327+
Assert.IsFalse(MimeType.TryParse(s.AsSpan(), provider: null, out _));
328+
}
329+
330+
#if FEATURE_GENERIC_MATH
331+
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
332+
public void IParseable_Parse_InvalidFormat(string s, Type expectedExceptionType)
333+
{
334+
Assert.Throws(expectedExceptionType, () => Parse<MimeType>(s));
335+
336+
static TSelf Parse<TSelf>(string s) where TSelf : IParseable<TSelf>
337+
=> TSelf.Parse(s, provider: null);
338+
}
339+
340+
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
341+
public void ISpanParseable_Parse_InvalidFormat(string s, Type expectedExceptionType)
342+
{
343+
if (s is null)
344+
Assert.Pass();
345+
346+
Assert.Throws(expectedExceptionType, () => Parse<MimeType>(s.AsSpan()));
347+
348+
static TSelf Parse<TSelf>(ReadOnlySpan<char> s) where TSelf : ISpanParseable<TSelf>
349+
=> TSelf.Parse(s, provider: null);
350+
}
351+
352+
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
353+
public void IParseable_TryParse_InvalidFormat(string s, Type discard)
354+
{
355+
if (s is null)
356+
Assert.Pass();
357+
358+
Assert.IsFalse(TryParse<MimeType>(s, out _));
359+
360+
static bool TryParse<TSelf>(string s, out TSelf result) where TSelf : IParseable<TSelf>
361+
=> TSelf.TryParse(s, provider: null, out result);
362+
}
363+
364+
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
365+
public void ISpanParseable_TryParse_InvalidFormat(string s, Type discard)
366+
{
367+
if (s is null)
368+
Assert.Pass();
369+
370+
Assert.IsFalse(TryParse<MimeType>(s.AsSpan(), out _));
371+
372+
static bool TryParse<TSelf>(ReadOnlySpan<char> s, out TSelf result) where TSelf : ISpanParseable<TSelf>
373+
=> TSelf.TryParse(s, provider: null, out result);
374+
}
375+
#endif
264376
}

0 commit comments

Comments
 (0)