@@ -13,7 +13,7 @@ static class RuntimeOperators
13
13
static readonly LogEventPropertyValue ConstantTrue = new ScalarValue ( true ) ,
14
14
ConstantFalse = new ScalarValue ( false ) ;
15
15
16
- static LogEventPropertyValue ScalarBoolean ( bool value )
16
+ internal static LogEventPropertyValue ScalarBoolean ( bool value )
17
17
{
18
18
return value ? ConstantTrue : ConstantFalse ;
19
19
}
@@ -122,18 +122,21 @@ public static LogEventPropertyValue GreaterThanOrEqual(LogEventPropertyValue lef
122
122
123
123
public static LogEventPropertyValue Equal ( LogEventPropertyValue left , LogEventPropertyValue right )
124
124
{
125
- if ( Coerce . Numeric ( left , out var l ) &&
126
- Coerce . Numeric ( right , out var r ) )
127
- return ScalarBoolean ( l == r ) ;
125
+ // Undefined values propagate through comparisons
126
+ if ( left == null || right == null )
127
+ return null ;
128
128
129
129
return ScalarBoolean ( UnboxedEqualHelper ( left , right ) ) ;
130
130
}
131
131
132
132
static bool UnboxedEqualHelper ( LogEventPropertyValue left , LogEventPropertyValue right )
133
133
{
134
- // "undefined"
135
134
if ( left == null || right == null )
136
- return false ;
135
+ throw new ArgumentException ( "Undefined values should short-circuit." ) ;
136
+
137
+ if ( Coerce . Numeric ( left , out var l ) &&
138
+ Coerce . Numeric ( right , out var r ) )
139
+ return l == r ;
137
140
138
141
if ( left is ScalarValue sl &&
139
142
right is ScalarValue sr )
@@ -144,11 +147,17 @@ static bool UnboxedEqualHelper(LogEventPropertyValue left, LogEventPropertyValue
144
147
145
148
public static LogEventPropertyValue _Internal_In ( LogEventPropertyValue item , LogEventPropertyValue collection )
146
149
{
150
+ if ( item == null )
151
+ return null ;
152
+
147
153
if ( collection is SequenceValue arr )
148
154
{
149
155
for ( var i = 0 ; i < arr . Elements . Count ; ++ i )
150
- if ( UnboxedEqualHelper ( arr . Elements [ i ] , item ) )
156
+ {
157
+ var element = arr . Elements [ i ] ;
158
+ if ( element != null && UnboxedEqualHelper ( element , item ) )
151
159
return ConstantTrue ;
160
+ }
152
161
153
162
return ConstantFalse ;
154
163
}
@@ -167,6 +176,9 @@ public static LogEventPropertyValue _Internal_EqualIgnoreCase(LogEventPropertyVa
167
176
168
177
public static LogEventPropertyValue NotEqual ( LogEventPropertyValue left , LogEventPropertyValue right )
169
178
{
179
+ if ( left == null || right == null )
180
+ return null ;
181
+
170
182
return ScalarBoolean ( ! UnboxedEqualHelper ( left , right ) ) ;
171
183
}
172
184
@@ -184,6 +196,19 @@ public static LogEventPropertyValue Negate(LogEventPropertyValue operand)
184
196
return null ;
185
197
}
186
198
199
+ public static LogEventPropertyValue Round ( LogEventPropertyValue value , LogEventPropertyValue places )
200
+ {
201
+ if ( ! Coerce . Numeric ( value , out var v ) ||
202
+ ! Coerce . Numeric ( places , out var p ) ||
203
+ p < 0 ||
204
+ p > 32 ) // Check my memory, here :D
205
+ {
206
+ return null ;
207
+ }
208
+
209
+ return new ScalarValue ( Math . Round ( v , ( int ) p ) ) ;
210
+ }
211
+
187
212
public static LogEventPropertyValue Not ( LogEventPropertyValue operand )
188
213
{
189
214
if ( operand is null )
@@ -293,8 +318,7 @@ public static LogEventPropertyValue Has(LogEventPropertyValue value)
293
318
294
319
public static LogEventPropertyValue ElementAt ( LogEventPropertyValue items , LogEventPropertyValue index )
295
320
{
296
- if ( items is SequenceValue arr &&
297
- Coerce . Numeric ( index , out var ix ) )
321
+ if ( items is SequenceValue arr && Coerce . Numeric ( index , out var ix ) )
298
322
{
299
323
if ( ix != Math . Floor ( ix ) )
300
324
return null ;
@@ -306,22 +330,20 @@ public static LogEventPropertyValue ElementAt(LogEventPropertyValue items, LogEv
306
330
return arr . Elements . ElementAt ( idx ) ;
307
331
}
308
332
309
- if ( items is StructureValue st &&
310
- Coerce . String ( index , out var s ) )
333
+ if ( items is StructureValue st && Coerce . String ( index , out var s ) )
311
334
{
312
335
if ( ! LinqExpressionCompiler . TryGetStructurePropertyValue ( st , s , out var value ) )
313
336
return null ;
314
337
315
338
return value ;
316
339
}
317
340
318
- if ( items is DictionaryValue dict &&
319
- index is ScalarValue sv )
341
+ if ( items is DictionaryValue dict && index is ScalarValue sv )
320
342
{
321
- if ( ! dict . Elements . TryGetValue ( sv , out var value ) )
322
- return null ;
323
-
324
- return value ;
343
+ // The lack of eager numeric type coercion means that here, `sv` may logically equal one
344
+ // of the keys, but not be equal according to the dictionary's `IEqualityComparer`.
345
+ var entry = dict . Elements . FirstOrDefault ( kv => kv . Key != null && UnboxedEqualHelper ( kv . Key , sv ) ) ;
346
+ return entry . Value ; // KVP is a struct; default is a pair of nulls.
325
347
}
326
348
327
349
return null ;
0 commit comments