-
Notifications
You must be signed in to change notification settings - Fork 1
/
FluentInterface.cs
128 lines (110 loc) · 5.09 KB
/
FluentInterface.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
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace ILGeneratorExtensions
{
/// <summary>
/// Contains extension methods that support fluent use of the ILGenerator API
/// </summary>
[PublicAPI]
public static partial class FluentInterface
{
private static readonly ConditionalWeakTable<ILGenerator, GeneratorData> GeneratorExtraData = new ConditionalWeakTable<ILGenerator, GeneratorData>();
/// <summary>
/// Mark the fluently-specified label
/// </summary>
/// <param name="generator"></param>
/// <param name="labelName">The name of the fluently-specified label</param>
[PublicAPI]
public static ILGenerator MarkLabel(this ILGenerator generator, string labelName)
{
var data = GeneratorExtraData.GetOrCreateValue(generator);
Label label;
if (!data.Labels.TryGetValue(labelName, out label))
{
throw new InvalidOperationException("No label with the name `" + labelName + "` declared");
}
generator.MarkLabel(label);
data.Labels.Remove(labelName);
return generator;
}
internal static Label GetOrCreateLabel(this ILGenerator generator, string labelName)
{
var data = GeneratorExtraData.GetOrCreateValue(generator);
Label label;
if (data.Labels.TryGetValue(labelName, out label))
{
return label;
}
else
{
label = generator.DefineLabel();
data.Labels.Add(labelName, label);
return label;
}
}
private static ILGenerator CreateLocal(this ILGenerator generator, string localName, Type localType, bool pinned)
{
var data = GeneratorExtraData.GetOrCreateValue(generator);
if (data.Locals.ContainsKey(localName))
{
throw new InvalidOperationException("Local with the name `" + localName + "` already declared");
}
var local = generator.DeclareLocal(localType, pinned);
data.Locals.Add(localName, local);
return generator;
}
/// <summary>
/// Fluently specify a new local with the given name and type
/// </summary>
/// <param name="generator"></param>
/// <param name="localName">The name of the fluently-specified local</param>
/// <param name="localType">The type of the fluently-specified local</param>
[PublicAPI]
public static ILGenerator CreateLocal(this ILGenerator generator, string localName, Type localType)
=> generator.CreateLocal(localName, localType, false);
/// <summary>
/// Fluently specify a new local with the given name and type
/// </summary>
/// <typeparam name="T">The type of the fluently-specified local</typeparam>
/// <param name="generator"></param>
/// <param name="localName">The name of the fluently-specified local</param>
[PublicAPI]
public static ILGenerator CreateLocal<T>(this ILGenerator generator, string localName)
=> generator.CreateLocal(localName, typeof (T));
/// <summary>
/// Fluently specify a new local with the given name and type whose contents are pinned in memory
/// </summary>
/// <param name="generator"></param>
/// <param name="localName">The name of the fluently-specified local</param>
/// <param name="localType">The type of the fluently-specified local</param>
[PublicAPI]
public static ILGenerator CreatePinnedLocal(this ILGenerator generator, string localName, Type localType)
=> generator.CreateLocal(localName, localType, true);
/// <summary>
/// Fluently specify a new local with the given name and type whose contents are pinned in memory
/// </summary>
/// <typeparam name="T">The type of the fluently-specified local</typeparam>
/// <param name="generator"></param>
/// <param name="localName">The name of the fluently-specified local</param>
[PublicAPI]
public static ILGenerator CreatePinnedLocal<T>(this ILGenerator generator, string localName)
=> generator.CreateLocal(localName, typeof(T), true);
internal static LocalBuilder GetLocal(this ILGenerator generator, string localName)
{
LocalBuilder local;
if (!GeneratorExtraData.GetOrCreateValue(generator).Locals.TryGetValue(localName, out local))
{
throw new InvalidOperationException("No local with the name `" + localName + "` declared");
}
return local;
}
private sealed class GeneratorData
{
public IDictionary<string, Label> Labels { get; } = new Dictionary<string, Label>();
public IDictionary<string, LocalBuilder> Locals { get; } = new Dictionary<string, LocalBuilder>();
}
}
}