7
7
8
8
namespace DotNext . Runtime ;
9
9
10
+ using Runtime . CompilerServices ;
11
+
10
12
/// <summary>
11
13
/// Represents a mutable reference to the field.
12
14
/// </summary>
@@ -17,7 +19,9 @@ namespace DotNext.Runtime;
17
19
[ EditorBrowsable ( EditorBrowsableState . Advanced ) ]
18
20
public readonly struct ValueReference < T > ( object owner , ref T fieldRef ) :
19
21
IEquatable < ValueReference < T > > ,
20
- IEqualityOperators < ValueReference < T > , ValueReference < T > , bool >
22
+ IEqualityOperators < ValueReference < T > , ValueReference < T > , bool > ,
23
+ ISupplier < T > ,
24
+ IConsumer < T >
21
25
{
22
26
private readonly nint offset = RawData . GetOffset ( owner , in fieldRef ) ;
23
27
@@ -76,8 +80,47 @@ public ValueReference(ref T staticFieldRef)
76
80
/// </summary>
77
81
public ref T Value => ref RawData . GetObjectData < T > ( owner , offset ) ;
78
82
83
+ /// <inheritdoc cref="IConsumer{T}.Invoke(T)"/>
84
+ void IConsumer < T > . Invoke ( T value ) => Value = value ;
85
+
86
+ /// <inheritdoc cref="IFunctional{T}.ToDelegate()"/>
87
+ Action < T > IFunctional < Action < T > > . ToDelegate ( ) => ToAction ( ) ;
88
+
89
+ /// <inheritdoc cref="ISupplier{T}.Invoke()"/>
90
+ T ISupplier < T > . Invoke ( ) => Value ;
91
+
92
+ /// <inheritdoc cref="IFunctional{T}.ToDelegate()"/>
93
+ Func < T > IFunctional < Func < T > > . ToDelegate ( ) => ToFunc ( ) ;
94
+
79
95
private bool SameObject ( object ? other ) => ReferenceEquals ( owner , other ) ;
80
96
97
+ private Func < T > ToFunc ( )
98
+ => Intrinsics . ChangeType < ValueReference < T > , ReadOnlyValueReference < T > > ( in this ) . ToFunc ( ) ;
99
+
100
+ private Action < T > ToAction ( )
101
+ {
102
+ Action < T > result ;
103
+
104
+ if ( IsEmpty )
105
+ {
106
+ result = ThrowNullReferenceException ;
107
+ }
108
+ else if ( ReferenceEquals ( owner , Sentinel . Instance ) )
109
+ {
110
+ result = new StaticFieldAccessor < T > ( offset ) . SetValue ;
111
+ }
112
+ else
113
+ {
114
+ IConsumer < T > consumer = this ;
115
+ result = consumer . Invoke ;
116
+ }
117
+
118
+ return result ;
119
+
120
+ [ DoesNotReturn ]
121
+ static void ThrowNullReferenceException ( T value ) => throw new NullReferenceException ( ) ;
122
+ }
123
+
81
124
/// <inheritdoc/>
82
125
public override string ? ToString ( )
83
126
=> owner is not null ? RawData . GetObjectData < T > ( owner , offset ) ? . ToString ( ) : null ;
@@ -126,6 +169,22 @@ public static implicit operator ReadOnlyValueReference<T>(ValueReference<T> refe
126
169
/// <returns>The span that contains <see cref="Value"/>; or empty span if <paramref name="reference"/> is empty.</returns>
127
170
public static implicit operator Span < T > ( ValueReference < T > reference )
128
171
=> reference . IsEmpty ? new ( ) : new ( ref reference . Value ) ;
172
+
173
+ /// <summary>
174
+ /// Returns a setter for the memory location.
175
+ /// </summary>
176
+ /// <param name="reference">A reference to a value.</param>
177
+ /// <returns>A setter for the memory location.</returns>
178
+ public static explicit operator Action < T > ( ValueReference < T > reference )
179
+ => reference . ToAction ( ) ;
180
+
181
+ /// <summary>
182
+ /// Returns a getter for the memory location.
183
+ /// </summary>
184
+ /// <param name="reference">A reference to a value.</param>
185
+ /// <returns>A getter for the memory location.</returns>
186
+ public static explicit operator Func < T > ( ValueReference < T > reference )
187
+ => reference . ToFunc ( ) ;
129
188
}
130
189
131
190
/// <summary>
@@ -138,7 +197,8 @@ public static implicit operator Span<T>(ValueReference<T> reference)
138
197
[ EditorBrowsable ( EditorBrowsableState . Advanced ) ]
139
198
public readonly struct ReadOnlyValueReference < T > ( object owner , ref readonly T fieldRef ) :
140
199
IEquatable < ReadOnlyValueReference < T > > ,
141
- IEqualityOperators < ReadOnlyValueReference < T > , ReadOnlyValueReference < T > , bool >
200
+ IEqualityOperators < ReadOnlyValueReference < T > , ReadOnlyValueReference < T > , bool > ,
201
+ ISupplier < T >
142
202
{
143
203
private readonly nint offset = RawData . GetOffset ( owner , in fieldRef ) ;
144
204
@@ -179,6 +239,36 @@ public ReadOnlyValueReference(ref readonly T staticFieldRef)
179
239
/// </summary>
180
240
public ref readonly T Value => ref RawData . GetObjectData < T > ( owner , offset ) ;
181
241
242
+ /// <inheritdoc cref="ISupplier{T}.Invoke()"/>
243
+ T ISupplier < T > . Invoke ( ) => Value ;
244
+
245
+ /// <inheritdoc cref="IFunctional{T}.ToDelegate()"/>
246
+ Func < T > IFunctional < Func < T > > . ToDelegate ( ) => ToFunc ( ) ;
247
+
248
+ internal Func < T > ToFunc ( )
249
+ {
250
+ Func < T > result ;
251
+ if ( IsEmpty )
252
+ {
253
+ result = ThrowNullReferenceException ;
254
+ }
255
+ else if ( ReferenceEquals ( owner , Sentinel . Instance ) )
256
+ {
257
+ result = new StaticFieldAccessor < T > ( offset ) . GetValue ;
258
+ }
259
+ else
260
+ {
261
+ ISupplier < T > supplier = this ;
262
+ result = supplier . Invoke ;
263
+ }
264
+
265
+ return result ;
266
+
267
+ [ DoesNotReturn ]
268
+ static T ThrowNullReferenceException ( )
269
+ => throw new NullReferenceException ( ) ;
270
+ }
271
+
182
272
private bool SameObject ( object ? other ) => ReferenceEquals ( owner , other ) ;
183
273
184
274
/// <inheritdoc/>
@@ -221,6 +311,14 @@ public bool Equals(ReadOnlyValueReference<T> reference)
221
311
/// <returns>The span that contains <see cref="Value"/>; or empty span if <paramref name="reference"/> is empty.</returns>
222
312
public static implicit operator ReadOnlySpan < T > ( ReadOnlyValueReference < T > reference )
223
313
=> reference . IsEmpty ? new ( ) : new ( in reference . Value ) ;
314
+
315
+ /// <summary>
316
+ /// Returns a getter for the memory location.
317
+ /// </summary>
318
+ /// <param name="reference">A reference to a value.</param>
319
+ /// <returns>A getter for the memory location.</returns>
320
+ public static explicit operator Func < T > ( ReadOnlyValueReference < T > reference )
321
+ => reference . ToFunc ( ) ;
224
322
}
225
323
226
324
[ SuppressMessage ( "Performance" , "CA1812" , Justification = "Used for reinterpret cast" ) ]
@@ -259,4 +357,11 @@ internal static ref T GetObjectData<T>(object owner, nint offset)
259
357
ref var rawData = ref Unsafe . As < RawData > ( owner ) . data ;
260
358
return ref Unsafe . As < byte , T > ( ref Unsafe . Add ( ref rawData , offset ) ) ;
261
359
}
360
+ }
361
+
362
+ file sealed class StaticFieldAccessor < T > ( nint offset )
363
+ {
364
+ public T GetValue ( ) => RawData . GetObjectData < T > ( Sentinel . Instance , offset ) ;
365
+
366
+ public void SetValue ( T value ) => RawData . GetObjectData < T > ( Sentinel . Instance , offset ) = value ;
262
367
}
0 commit comments