Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit eb0dfa7

Browse files
committed
Add JsConfig.TryParseIntoBestFit
1 parent f332443 commit eb0dfa7

File tree

4 files changed

+93
-52
lines changed

4 files changed

+93
-52
lines changed

src/ServiceStack.Text/Common/DeserializeType.cs

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -192,50 +192,7 @@ public static object ParsePrimitive(StringSegment value)
192192
if (value.TryParseBoolean(out bool boolValue))
193193
return boolValue;
194194

195-
// Parse as decimal
196-
var acceptDecimal = JsConfig.ParsePrimitiveFloatingPointTypes.Has(ParseAsType.Decimal);
197-
var isDecimal = value.TryParseDecimal(out decimal decimalValue);
198-
199-
// Check if the number is an Primitive Integer type given that we have a decimal
200-
if (isDecimal && decimalValue == decimal.Truncate(decimalValue))
201-
{
202-
// Value is a whole number
203-
var parseAs = JsConfig.ParsePrimitiveIntegerTypes;
204-
if (parseAs.Has(ParseAsType.Byte) && decimalValue <= byte.MaxValue && decimalValue >= byte.MinValue) return (byte)decimalValue;
205-
if (parseAs.Has(ParseAsType.SByte) && decimalValue <= sbyte.MaxValue && decimalValue >= sbyte.MinValue) return (sbyte)decimalValue;
206-
if (parseAs.Has(ParseAsType.Int16) && decimalValue <= Int16.MaxValue && decimalValue >= Int16.MinValue) return (Int16)decimalValue;
207-
if (parseAs.Has(ParseAsType.UInt16) && decimalValue <= UInt16.MaxValue && decimalValue >= UInt16.MinValue) return (UInt16)decimalValue;
208-
if (parseAs.Has(ParseAsType.Int32) && decimalValue <= Int32.MaxValue && decimalValue >= Int32.MinValue) return (Int32)decimalValue;
209-
if (parseAs.Has(ParseAsType.UInt32) && decimalValue <= UInt32.MaxValue && decimalValue >= UInt32.MinValue) return (UInt32)decimalValue;
210-
if (parseAs.Has(ParseAsType.Int64) && decimalValue <= Int64.MaxValue && decimalValue >= Int64.MinValue) return (Int64)decimalValue;
211-
if (parseAs.Has(ParseAsType.UInt64) && decimalValue <= UInt64.MaxValue && decimalValue >= UInt64.MinValue) return (UInt64)decimalValue;
212-
return decimalValue;
213-
}
214-
215-
// Value is a floating point number
216-
217-
// Return a decimal if the user accepts a decimal
218-
if (isDecimal && acceptDecimal)
219-
return decimalValue;
220-
221-
var acceptFloat = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Single);
222-
var isFloat = value.TryParseFloat(out float floatValue);
223-
if (acceptFloat && isFloat)
224-
return floatValue;
225-
226-
var acceptDouble = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Double);
227-
var isDouble = value.TryParseDouble(out double doubleValue);
228-
if (acceptDouble && isDouble)
229-
return doubleValue;
230-
231-
if (isDecimal)
232-
return decimalValue;
233-
if (isFloat)
234-
return floatValue;
235-
if (isDouble)
236-
return doubleValue;
237-
238-
return null;
195+
return value.ParseNumber();
239196
}
240197

241198
internal static object ParsePrimitive(string value, char firstChar)
@@ -375,11 +332,79 @@ private static SetMemberDelegate GetSetFieldMethod(TypeConfig typeConfig, FieldI
375332
}
376333
}
377334

378-
internal static class DeserializeTypeExensions
335+
public static class DeserializeTypeExensions
379336
{
380337
public static bool Has(this ParseAsType flags, ParseAsType flag)
381338
{
382339
return (flag & flags) != 0;
383340
}
341+
342+
public static object ParseNumber(this StringSegment value)
343+
{
344+
if (value.Length == 1)
345+
{
346+
int singleDigit = value.GetChar(0);
347+
if (singleDigit >= 48 || singleDigit <= 57) // 0 - 9
348+
{
349+
var result = singleDigit - 48;
350+
if (JsConfig.TryParseIntoBestFit)
351+
return (byte) result;
352+
return result;
353+
}
354+
}
355+
356+
// Parse as decimal
357+
var acceptDecimal = JsConfig.ParsePrimitiveFloatingPointTypes.Has(ParseAsType.Decimal);
358+
var isDecimal = value.TryParseDecimal(out decimal decimalValue);
359+
360+
// Check if the number is an Primitive Integer type given that we have a decimal
361+
if (isDecimal && decimalValue == decimal.Truncate(decimalValue))
362+
{
363+
// Value is a whole number
364+
var parseAs = JsConfig.ParsePrimitiveIntegerTypes;
365+
if (parseAs.Has(ParseAsType.Byte) && decimalValue <= byte.MaxValue && decimalValue >= byte.MinValue)
366+
return (byte)decimalValue;
367+
if (parseAs.Has(ParseAsType.SByte) && decimalValue <= sbyte.MaxValue && decimalValue >= sbyte.MinValue)
368+
return (sbyte)decimalValue;
369+
if (parseAs.Has(ParseAsType.Int16) && decimalValue <= Int16.MaxValue && decimalValue >= Int16.MinValue)
370+
return (Int16)decimalValue;
371+
if (parseAs.Has(ParseAsType.UInt16) && decimalValue <= UInt16.MaxValue && decimalValue >= UInt16.MinValue)
372+
return (UInt16)decimalValue;
373+
if (parseAs.Has(ParseAsType.Int32) && decimalValue <= Int32.MaxValue && decimalValue >= Int32.MinValue)
374+
return (Int32)decimalValue;
375+
if (parseAs.Has(ParseAsType.UInt32) && decimalValue <= UInt32.MaxValue && decimalValue >= UInt32.MinValue)
376+
return (UInt32)decimalValue;
377+
if (parseAs.Has(ParseAsType.Int64) && decimalValue <= Int64.MaxValue && decimalValue >= Int64.MinValue)
378+
return (Int64)decimalValue;
379+
if (parseAs.Has(ParseAsType.UInt64) && decimalValue <= UInt64.MaxValue && decimalValue >= UInt64.MinValue)
380+
return (UInt64)decimalValue;
381+
return decimalValue;
382+
}
383+
384+
// Value is a floating point number
385+
386+
// Return a decimal if the user accepts a decimal
387+
if (isDecimal && acceptDecimal)
388+
return decimalValue;
389+
390+
var acceptFloat = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Single);
391+
var isFloat = value.TryParseFloat(out float floatValue);
392+
if (acceptFloat && isFloat)
393+
return floatValue;
394+
395+
var acceptDouble = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Double);
396+
var isDouble = value.TryParseDouble(out double doubleValue);
397+
if (acceptDouble && isDouble)
398+
return doubleValue;
399+
400+
if (isDecimal)
401+
return decimalValue;
402+
if (isFloat)
403+
return floatValue;
404+
if (isDouble)
405+
return doubleValue;
406+
407+
return null;
408+
}
384409
}
385410
}

src/ServiceStack.Text/JsConfig.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,21 @@ public static bool TryToParseNumericType
336336
}
337337
}
338338

339+
private static bool? sTryParseIntoBestFit;
340+
public static bool TryParseIntoBestFit
341+
{
342+
get
343+
{
344+
return (JsConfigScope.Current != null ? JsConfigScope.Current.TryParseIntoBestFit : null)
345+
?? sTryParseIntoBestFit
346+
?? false;
347+
}
348+
set
349+
{
350+
if (!sTryParseIntoBestFit.HasValue) sTryParseIntoBestFit = value;
351+
}
352+
}
353+
339354
private static ParseAsType? sParsePrimitiveFloatingPointTypes;
340355
public static ParseAsType ParsePrimitiveFloatingPointTypes
341356
{
@@ -963,6 +978,7 @@ public static void Reset()
963978
sModelFactory = ReflectionExtensions.GetConstructorMethodToCache;
964979
sTryToParsePrimitiveTypeValues = null;
965980
sTryToParseNumericType = null;
981+
sTryParseIntoBestFit = null;
966982
sConvertObjectTypesIntoStringDictionary = null;
967983
sExcludeDefaultValues = null;
968984
sIncludeNullValues = null;

src/ServiceStack.Text/JsConfigScope.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ public void Dispose()
4949

5050
public bool? ConvertObjectTypesIntoStringDictionary { get; set; }
5151
public bool? TryToParsePrimitiveTypeValues { get; set; }
52-
public bool? TryToParseNumericType { get; set; }
53-
public ParseAsType? ParsePrimitiveFloatingPointTypes { get; set; }
54-
public ParseAsType? ParsePrimitiveIntegerTypes { get; set; }
52+
public bool? TryToParseNumericType { get; set; }
53+
public bool? TryParseIntoBestFit { get; set; }
54+
public ParseAsType? ParsePrimitiveFloatingPointTypes { get; set; }
55+
public ParseAsType? ParsePrimitiveIntegerTypes { get; set; }
5556
public bool? UseSystemParseMethods { get; set; }
5657
public bool? ExcludeDefaultValues { get; set; }
5758
public bool? IncludeNullValues { get; set; }

tests/ServiceStack.Text.Tests/DictionaryTests.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,7 @@ public void deserizes_unsigned_types_into_to_best_fit_numeric()
373373
new NumericType(UInt64.MaxValue, typeof (UInt64)),
374374
};
375375

376-
JsConfig.TryToParsePrimitiveTypeValues = true;
377-
JsConfig.TryToParseNumericType = true;
378-
376+
JsConfig.TryToParsePrimitiveTypeValues = JsConfig.TryToParseNumericType = JsConfig.TryParseIntoBestFit = true;
379377

380378
foreach (var unsignedType in unsignedTypes)
381379
{
@@ -391,8 +389,9 @@ public void deserizes_unsigned_types_into_to_best_fit_numeric()
391389
Assert.That(deserializedDict["min"], Is.TypeOf<byte>());
392390
Assert.That(deserializedDict["max"], Is.TypeOf(unsignedType.Type));
393391
Assert.That(deserializedDict["max"], Is.EqualTo(unsignedType.Max));
394-
395392
}
393+
394+
JsConfig.Reset();
396395
}
397396

398397
[Test]

0 commit comments

Comments
 (0)