-
Notifications
You must be signed in to change notification settings - Fork 4
/
03a_KeyValuePair.cs
129 lines (101 loc) · 4.88 KB
/
03a_KeyValuePair.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Generic;
using System.Reflection;
using JetBrains.Annotations;
using Nemesis.TextParsers.Runtime;
using Nemesis.TextParsers.Settings;
using Nemesis.TextParsers.Utils;
namespace Nemesis.TextParsers.Parsers
{
[UsedImplicitly]
public sealed class KeyValuePairTransformerCreator : ICanCreateTransformer
{
private readonly TupleHelper _helper;
private readonly ITransformerStore _transformerStore;
public KeyValuePairTransformerCreator(ITransformerStore transformerStore, KeyValuePairSettings settings)
{
_transformerStore = transformerStore;
_helper = settings.ToTupleHelper();
}
public ITransformer<TPair> CreateTransformer<TPair>()
{
if (!TryGetElements(typeof(TPair), out var keyType, out var valueType))
throw new NotSupportedException(
$"Type {typeof(TPair).GetFriendlyName()} is not supported by {GetType().Name}");
var m = _createTransformerCoreMethod.MakeGenericMethod(keyType, valueType);
return (ITransformer<TPair>)m.Invoke(this, null);
}
private static readonly MethodInfo _createTransformerCoreMethod = Method.OfExpression<
Func<KeyValuePairTransformerCreator, ITransformer<KeyValuePair<int, int>>>
>(creator => creator.CreateTransformerCore<int, int>()).GetGenericMethodDefinition();
private ITransformer<KeyValuePair<TKey, TValue>> CreateTransformerCore<TKey, TValue>() =>
new KeyValuePairTransformer<TKey, TValue>(_helper,
_transformerStore.GetTransformer<TKey>(),
_transformerStore.GetTransformer<TValue>()
);
private sealed class KeyValuePairTransformer<TKey, TValue> : TransformerBase<KeyValuePair<TKey, TValue>>
{
private const string TYPE_NAME = "Key-value pair";
private readonly TupleHelper _helper;
private readonly ITransformer<TKey> _keyTransformer;
private readonly ITransformer<TValue> _valueTransformer;
public KeyValuePairTransformer(TupleHelper helper, ITransformer<TKey> keyTransformer,
ITransformer<TValue> valueTransformer)
{
_helper = helper;
_keyTransformer = keyTransformer;
_valueTransformer = valueTransformer;
}
protected override KeyValuePair<TKey, TValue> ParseCore(in ReadOnlySpan<char> input)
{
var enumerator = _helper.ParseStart(input, 2, TYPE_NAME);
var key = _helper.ParseElement(ref enumerator, _keyTransformer);
_helper.ParseNext(ref enumerator, 2, TYPE_NAME);
var value = _helper.ParseElement(ref enumerator, _valueTransformer);
_helper.ParseEnd(ref enumerator, 2, TYPE_NAME);
return new KeyValuePair<TKey, TValue>(key, value);
}
public override string Format(KeyValuePair<TKey, TValue> element)
{
Span<char> initialBuffer = stackalloc char[32];
var accumulator = new ValueSequenceBuilder<char>(initialBuffer);
try
{
_helper.StartFormat(ref accumulator);
_helper.FormatElement(_keyTransformer, element.Key, ref accumulator);
_helper.AddDelimiter(ref accumulator);
_helper.FormatElement(_valueTransformer, element.Value, ref accumulator);
_helper.EndFormat(ref accumulator);
return accumulator.AsSpan().ToString();
}
finally
{
accumulator.Dispose();
}
}
public override KeyValuePair<TKey, TValue> GetEmpty() => new(_keyTransformer.GetEmpty(), _valueTransformer.GetEmpty());
}
public bool CanHandle(Type type) =>
TryGetElements(type, out var keyType, out var valueType) &&
_transformerStore.IsSupportedForTransformation(keyType) &&
_transformerStore.IsSupportedForTransformation(valueType);
private static bool TryGetElements(Type type, out Type keyType, out Type valueType)
{
if (type.IsValueType && type.IsGenericType && !type.IsGenericTypeDefinition &&
TypeMeta.TryGetGenericRealization(type, typeof(KeyValuePair<,>), out var kvp))
{
keyType = kvp.GenericTypeArguments[0];
valueType = kvp.GenericTypeArguments[1];
return true;
}
else
{
keyType = valueType = null;
return false;
}
}
public sbyte Priority => 11;
public override string ToString() =>
$"Create transformer for KeyValuePair struct with settings:{_helper}";
}
}