44using System ;
55using System . Collections . Generic ;
66using System . Globalization ;
7+ using System . Linq ;
78using System . Net ;
9+ using System . Runtime . CompilerServices ;
810using SixLabors . ImageSharp . Web . Commands . Converters ;
911
1012namespace SixLabors . ImageSharp . Web . Commands
@@ -14,44 +16,18 @@ namespace SixLabors.ImageSharp.Web.Commands
1416 /// </summary>
1517 public sealed class CommandParser
1618 {
17- /// <summary>
18- /// A new instance of the <see cref="CommandParser"/> class with lazy initialization.
19- /// </summary>
20- private static readonly Lazy < CommandParser > Lazy = new Lazy < CommandParser > ( ( ) => new CommandParser ( ) ) ;
19+ private readonly ICommandConverter [ ] converters ;
2120
2221 /// <summary>
23- /// Prevents a default instance of the <see cref="CommandParser"/> class from being created .
22+ /// Initializes a new instance of the <see cref="CommandParser"/> class.
2423 /// </summary>
25- private CommandParser ( )
24+ /// <param name="converters">The collection of command converters.</param>
25+ public CommandParser ( IEnumerable < ICommandConverter > converters )
2626 {
27- this . AddSimpleConverters ( ) ;
28- this . AddListConverters ( ) ;
29- this . AddArrayConverters ( ) ;
30- this . AddColorConverters ( ) ;
27+ Guard . NotNull ( converters , nameof ( converters ) ) ;
28+ this . converters = converters . ToArray ( ) ;
3129 }
3230
33- /// <summary>
34- /// Gets the current <see cref="CommandParser"/> instance.
35- /// </summary>
36- public static CommandParser Instance => Lazy . Value ;
37-
38- /// <summary>
39- /// Adds a command converter to the parser.
40- /// </summary>
41- /// <param name="type">The <see cref="Type"/> to add a converter for. </param>
42- /// <param name="converterType">The type of <see cref="CommandConverter"/> to add.</param>
43- public void AddConverter ( Type type , Type converterType ) => CommandDescriptor . AddConverter ( type , converterType ) ;
44-
45- /// <summary>
46- /// Parses the given string value converting it to the given using the invariant culture.
47- /// </summary>
48- /// <param name="value">The string value to parse.</param>
49- /// <typeparam name="T">
50- /// The <see cref="Type"/> to convert the string to.
51- /// </typeparam>
52- /// <returns>The converted instance or the default.</returns>
53- public T ParseValue < T > ( string value ) => this . ParseValue < T > ( value , CultureInfo . InvariantCulture ) ;
54-
5531 /// <summary>
5632 /// Parses the given string value converting it to the given type.
5733 /// </summary>
@@ -61,99 +37,38 @@ private CommandParser()
6137 /// The <see cref="Type"/> to convert the string to.
6238 /// </typeparam>
6339 /// <returns>The converted instance or the default.</returns>
40+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
6441 public T ParseValue < T > ( string value , CultureInfo culture )
65- {
66- culture ??= CultureInfo . InvariantCulture ;
67-
68- Type type = typeof ( T ) ;
69- ICommandConverter converter = CommandDescriptor . GetConverter ( type ) ;
70- try
71- {
72- return ( T ) converter . ConvertFrom ( culture , WebUtility . UrlDecode ( value ) , type ) ;
73- }
74- catch
75- {
76- return default ;
77- }
78- }
79-
80- /// <summary>
81- /// Add the generic converters.
82- /// </summary>
83- private void AddSimpleConverters ( )
84- {
85- this . AddConverter ( TypeConstants . Sbyte , typeof ( IntegralNumberConverter < sbyte > ) ) ;
86- this . AddConverter ( TypeConstants . Byte , typeof ( IntegralNumberConverter < byte > ) ) ;
87-
88- this . AddConverter ( TypeConstants . Short , typeof ( IntegralNumberConverter < short > ) ) ;
89- this . AddConverter ( TypeConstants . UShort , typeof ( IntegralNumberConverter < ushort > ) ) ;
90-
91- this . AddConverter ( TypeConstants . Int , typeof ( IntegralNumberConverter < int > ) ) ;
92- this . AddConverter ( TypeConstants . UInt , typeof ( IntegralNumberConverter < uint > ) ) ;
93-
94- this . AddConverter ( TypeConstants . Long , typeof ( IntegralNumberConverter < long > ) ) ;
95- this . AddConverter ( TypeConstants . ULong , typeof ( IntegralNumberConverter < ulong > ) ) ;
96-
97- this . AddConverter ( typeof ( decimal ) , typeof ( SimpleCommandConverter < decimal > ) ) ;
98- this . AddConverter ( typeof ( float ) , typeof ( SimpleCommandConverter < float > ) ) ;
99-
100- this . AddConverter ( typeof ( double ) , typeof ( SimpleCommandConverter < double > ) ) ;
101- this . AddConverter ( typeof ( string ) , typeof ( SimpleCommandConverter < string > ) ) ;
102-
103- this . AddConverter ( typeof ( bool ) , typeof ( SimpleCommandConverter < bool > ) ) ;
104- }
105-
106- /// <summary>
107- /// Adds a selection of default list type converters.
108- /// </summary>
109- private void AddListConverters ( )
110- {
111- this . AddConverter ( typeof ( List < sbyte > ) , typeof ( ListConverter < sbyte > ) ) ;
112- this . AddConverter ( typeof ( List < byte > ) , typeof ( ListConverter < byte > ) ) ;
113-
114- this . AddConverter ( typeof ( List < short > ) , typeof ( ListConverter < short > ) ) ;
115- this . AddConverter ( typeof ( List < ushort > ) , typeof ( ListConverter < ushort > ) ) ;
116-
117- this . AddConverter ( typeof ( List < int > ) , typeof ( ListConverter < int > ) ) ;
118- this . AddConverter ( typeof ( List < uint > ) , typeof ( ListConverter < uint > ) ) ;
119-
120- this . AddConverter ( typeof ( List < long > ) , typeof ( ListConverter < long > ) ) ;
121- this . AddConverter ( typeof ( List < ulong > ) , typeof ( ListConverter < ulong > ) ) ;
122-
123- this . AddConverter ( typeof ( List < decimal > ) , typeof ( ListConverter < decimal > ) ) ;
124- this . AddConverter ( typeof ( List < float > ) , typeof ( ListConverter < float > ) ) ;
125- this . AddConverter ( typeof ( List < double > ) , typeof ( ListConverter < double > ) ) ;
126-
127- this . AddConverter ( typeof ( List < string > ) , typeof ( ListConverter < string > ) ) ;
128- }
42+ => ( T ) this . ParseValue ( typeof ( T ) , value , culture ) ;
12943
13044 /// <summary>
131- /// Adds a selection of default array type converters .
45+ /// Parses the given string value converting it to the given type .
13246 /// </summary>
133- private void AddArrayConverters ( )
47+ /// <param name="type"> The type to convert the string to.</param>
48+ /// <param name="value">The string value to parse.</param>
49+ /// <param name="culture">The <see cref="CultureInfo"/> to use as the current culture.</param>
50+ /// <returns>The converted instance or the default value.</returns>
51+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
52+ public object ParseValue ( Type type , string value , CultureInfo culture )
13453 {
135- this . AddConverter ( typeof ( sbyte [ ] ) , typeof ( ArrayConverter < sbyte > ) ) ;
136- this . AddConverter ( typeof ( byte [ ] ) , typeof ( ArrayConverter < byte > ) ) ;
137-
138- this . AddConverter ( typeof ( short [ ] ) , typeof ( ArrayConverter < short > ) ) ;
139- this . AddConverter ( typeof ( ushort [ ] ) , typeof ( ArrayConverter < ushort > ) ) ;
54+ DebugGuard . NotNull ( type , nameof ( type ) ) ;
55+ DebugGuard . NotNull ( culture , nameof ( culture ) ) ;
14056
141- this . AddConverter ( typeof ( int [ ] ) , typeof ( ArrayConverter < int > ) ) ;
142- this . AddConverter ( typeof ( uint [ ] ) , typeof ( ArrayConverter < uint > ) ) ;
57+ // This allows us to reuse the same converter for infinite enum types.
58+ Type matchType = type . IsEnum ? typeof ( Enum ) : type ;
14359
144- this . AddConverter ( typeof ( long [ ] ) , typeof ( ArrayConverter < long > ) ) ;
145- this . AddConverter ( typeof ( ulong [ ] ) , typeof ( ArrayConverter < ulong > ) ) ;
60+ ICommandConverter converter = Array . Find ( this . converters , x => x . Type . Equals ( matchType ) ) ;
14661
147- this . AddConverter ( typeof ( decimal [ ] ) , typeof ( ArrayConverter < decimal > ) ) ;
148- this . AddConverter ( typeof ( float [ ] ) , typeof ( ArrayConverter < float > ) ) ;
149- this . AddConverter ( typeof ( double [ ] ) , typeof ( ArrayConverter < double > ) ) ;
62+ if ( converter is null )
63+ {
64+ ThrowNotSupported ( type ) ;
65+ }
15066
151- this . AddConverter ( typeof ( string [ ] ) , typeof ( ArrayConverter < string > ) ) ;
67+ return converter . ConvertFrom ( this , culture , WebUtility . UrlDecode ( value ) , type ) ;
15268 }
15369
154- /// <summary>
155- /// Adds the default color converters.
156- /// </summary>
157- private void AddColorConverters ( ) => this . AddConverter ( TypeConstants . Color , typeof ( ColorConverter ) ) ;
70+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
71+ private static void ThrowNotSupported ( Type type )
72+ => throw new NotSupportedException ( $ "Cannot convert to { type . FullName } .") ;
15873 }
15974}
0 commit comments