Skip to content

Commit a1a4e07

Browse files
author
Michael Hallett
committed
Updated the SimpleJson package
1 parent cbee3c1 commit a1a4e07

File tree

4 files changed

+269
-161
lines changed

4 files changed

+269
-161
lines changed

RestSharp.Tests/SimpleJson.cs

Lines changed: 131 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// <website>https://github.com/facebook-csharp-sdk/simple-json</website>
1818
//-----------------------------------------------------------------------
1919

20-
// VERSION: 0.26.0
20+
// VERSION: 0.38.0
2121

2222
// NOTE: uncomment the following line to make SimpleJson class internal.
2323
//#define SIMPLE_JSON_INTERNAL
@@ -31,6 +31,9 @@
3131
// NOTE: uncomment the following line to enable DataContract support.
3232
//#define SIMPLE_JSON_DATACONTRACT
3333

34+
// NOTE: uncomment the following line to enable IReadOnlyCollection<T> and IReadOnlyList<T> support.
35+
//#define SIMPLE_JSON_READONLY_COLLECTIONS
36+
3437
// NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke().
3538
// define if you are using .net framework <= 3.0 or < WP7.5
3639
//#define SIMPLE_JSON_NO_LINQ_EXPRESSION
@@ -257,7 +260,7 @@ public void Clear()
257260
/// </summary>
258261
/// <param name="item">The item.</param>
259262
/// <returns>
260-
/// <c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
263+
/// <c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
261264
/// </returns>
262265
public bool Contains(KeyValuePair<string, object> item)
263266
{
@@ -294,7 +297,7 @@ public int Count
294297
/// Gets a value indicating whether this instance is read only.
295298
/// </summary>
296299
/// <value>
297-
/// <c>true</c> if this instance is read only; otherwise, <c>false</c>.
300+
/// <c>true</c> if this instance is read only; otherwise, <c>false</c>.
298301
/// </value>
299302
public bool IsReadOnly
300303
{
@@ -512,6 +515,22 @@ static class SimpleJson
512515
private const int TOKEN_NULL = 11;
513516
private const int BUILDER_CAPACITY = 2000;
514517

518+
private static readonly char[] EscapeTable;
519+
private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' };
520+
private static readonly string EscapeCharactersString = new string(EscapeCharacters);
521+
522+
static SimpleJson()
523+
{
524+
EscapeTable = new char[93];
525+
EscapeTable['"'] = '"';
526+
EscapeTable['\\'] = '\\';
527+
EscapeTable['\b'] = 'b';
528+
EscapeTable['\f'] = 'f';
529+
EscapeTable['\n'] = 'n';
530+
EscapeTable['\r'] = 'r';
531+
EscapeTable['\t'] = 't';
532+
}
533+
515534
/// <summary>
516535
/// Parses the string json into a value
517536
/// </summary>
@@ -1073,29 +1092,50 @@ static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnum
10731092

10741093
static bool SerializeString(string aString, StringBuilder builder)
10751094
{
1076-
builder.Append("\"");
1095+
// Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged)
1096+
if (aString.IndexOfAny(EscapeCharacters) == -1)
1097+
{
1098+
builder.Append('"');
1099+
builder.Append(aString);
1100+
builder.Append('"');
1101+
1102+
return true;
1103+
}
1104+
1105+
builder.Append('"');
1106+
int safeCharacterCount = 0;
10771107
char[] charArray = aString.ToCharArray();
1108+
10781109
for (int i = 0; i < charArray.Length; i++)
10791110
{
10801111
char c = charArray[i];
1081-
if (c == '"')
1082-
builder.Append("\\\"");
1083-
else if (c == '\\')
1084-
builder.Append("\\\\");
1085-
else if (c == '\b')
1086-
builder.Append("\\b");
1087-
else if (c == '\f')
1088-
builder.Append("\\f");
1089-
else if (c == '\n')
1090-
builder.Append("\\n");
1091-
else if (c == '\r')
1092-
builder.Append("\\r");
1093-
else if (c == '\t')
1094-
builder.Append("\\t");
1112+
1113+
// Non ascii characters are fine, buffer them up and send them to the builder
1114+
// in larger chunks if possible. The escape table is a 1:1 translation table
1115+
// with \0 [default(char)] denoting a safe character.
1116+
if (c >= EscapeTable.Length || EscapeTable[c] == default(char))
1117+
{
1118+
safeCharacterCount++;
1119+
}
10951120
else
1096-
builder.Append(c);
1121+
{
1122+
if (safeCharacterCount > 0)
1123+
{
1124+
builder.Append(charArray, i - safeCharacterCount, safeCharacterCount);
1125+
safeCharacterCount = 0;
1126+
}
1127+
1128+
builder.Append('\\');
1129+
builder.Append(EscapeTable[c]);
1130+
}
10971131
}
1098-
builder.Append("\"");
1132+
1133+
if (safeCharacterCount > 0)
1134+
{
1135+
builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount);
1136+
}
1137+
1138+
builder.Append('"');
10991139
return true;
11001140
}
11011141

@@ -1308,7 +1348,21 @@ public virtual object DeserializeObject(object value, Type type)
13081348
return DateTimeOffset.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
13091349
if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))
13101350
return new Guid(str);
1311-
return str;
1351+
if (type == typeof(Uri))
1352+
{
1353+
bool isValid = Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute);
1354+
1355+
Uri result;
1356+
if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result))
1357+
return result;
1358+
1359+
return null;
1360+
}
1361+
1362+
if (type == typeof(string))
1363+
return str;
1364+
1365+
return Convert.ChangeType(str, type, CultureInfo.InvariantCulture);
13121366
}
13131367
else
13141368
{
@@ -1395,9 +1449,8 @@ public virtual object DeserializeObject(object value, Type type)
13951449
}
13961450
else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type))
13971451
{
1398-
Type innerType = ReflectionUtils.GetGenericTypeArguments(type)[0];
1399-
Type genericType = typeof(List<>).MakeGenericType(innerType);
1400-
list = (IList)ConstructorCache[genericType](jsonObject.Count);
1452+
Type innerType = ReflectionUtils.GetGenericListElementType(type);
1453+
list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(jsonObject.Count);
14011454
foreach (object o in jsonObject)
14021455
list.Add(DeserializeObject(o, innerType));
14031456
}
@@ -1543,7 +1596,7 @@ private static bool CanAdd(MemberInfo info, out string jsonKey)
15431596
namespace Reflection
15441597
{
15451598
// This class is meant to be copied into other libraries. So we want to exclude it from Code Analysis rules
1546-
// that might be in place in the target project.
1599+
// that might be in place in the target project.
15471600
[GeneratedCode("reflection-utils", "1.0.0")]
15481601
#if SIMPLE_JSON_REFLECTION_UTILS_PUBLIC
15491602
public
@@ -1560,6 +1613,18 @@ class ReflectionUtils
15601613

15611614
public delegate TValue ThreadSafeDictionaryValueFactory<TKey, TValue>(TKey key);
15621615

1616+
#if SIMPLE_JSON_TYPEINFO
1617+
public static TypeInfo GetTypeInfo(Type type)
1618+
{
1619+
return type.GetTypeInfo();
1620+
}
1621+
#else
1622+
public static Type GetTypeInfo(Type type)
1623+
{
1624+
return type;
1625+
}
1626+
#endif
1627+
15631628
public static Attribute GetAttribute(MemberInfo info, Type type)
15641629
{
15651630
#if SIMPLE_JSON_TYPEINFO
@@ -1573,6 +1638,25 @@ public static Attribute GetAttribute(MemberInfo info, Type type)
15731638
#endif
15741639
}
15751640

1641+
public static Type GetGenericListElementType(Type type)
1642+
{
1643+
IEnumerable<Type> interfaces;
1644+
#if SIMPLE_JSON_TYPEINFO
1645+
interfaces = type.GetTypeInfo().ImplementedInterfaces;
1646+
#else
1647+
interfaces = type.GetInterfaces();
1648+
#endif
1649+
foreach (Type implementedInterface in interfaces)
1650+
{
1651+
if (IsTypeGeneric(implementedInterface) &&
1652+
implementedInterface.GetGenericTypeDefinition() == typeof (IList<>))
1653+
{
1654+
return GetGenericTypeArguments(implementedInterface)[0];
1655+
}
1656+
}
1657+
return GetGenericTypeArguments(type)[0];
1658+
}
1659+
15761660
public static Attribute GetAttribute(Type objectType, Type attributeType)
15771661
{
15781662

@@ -1596,57 +1680,52 @@ public static Type[] GetGenericTypeArguments(Type type)
15961680
#endif
15971681
}
15981682

1683+
public static bool IsTypeGeneric(Type type)
1684+
{
1685+
return GetTypeInfo(type).IsGenericType;
1686+
}
1687+
15991688
public static bool IsTypeGenericeCollectionInterface(Type type)
16001689
{
1601-
#if SIMPLE_JSON_TYPEINFO
1602-
if (!type.GetTypeInfo().IsGenericType)
1603-
#else
1604-
if (!type.IsGenericType)
1605-
#endif
1690+
if (!IsTypeGeneric(type))
16061691
return false;
16071692

16081693
Type genericDefinition = type.GetGenericTypeDefinition();
16091694

1610-
return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>));
1695+
return (genericDefinition == typeof(IList<>)
1696+
|| genericDefinition == typeof(ICollection<>)
1697+
|| genericDefinition == typeof(IEnumerable<>)
1698+
#if SIMPLE_JSON_READONLY_COLLECTIONS
1699+
|| genericDefinition == typeof(IReadOnlyCollection<>)
1700+
|| genericDefinition == typeof(IReadOnlyList<>)
1701+
#endif
1702+
);
16111703
}
16121704

16131705
public static bool IsAssignableFrom(Type type1, Type type2)
16141706
{
1615-
#if SIMPLE_JSON_TYPEINFO
1616-
return type1.GetTypeInfo().IsAssignableFrom(type2.GetTypeInfo());
1617-
#else
1618-
return type1.IsAssignableFrom(type2);
1619-
#endif
1707+
return GetTypeInfo(type1).IsAssignableFrom(GetTypeInfo(type2));
16201708
}
16211709

16221710
public static bool IsTypeDictionary(Type type)
16231711
{
16241712
#if SIMPLE_JSON_TYPEINFO
16251713
if (typeof(IDictionary<,>).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
16261714
return true;
1627-
1628-
if (!type.GetTypeInfo().IsGenericType)
1629-
return false;
16301715
#else
16311716
if (typeof(System.Collections.IDictionary).IsAssignableFrom(type))
16321717
return true;
1633-
1634-
if (!type.IsGenericType)
1635-
return false;
16361718
#endif
1719+
if (!GetTypeInfo(type).IsGenericType)
1720+
return false;
1721+
16371722
Type genericDefinition = type.GetGenericTypeDefinition();
16381723
return genericDefinition == typeof(IDictionary<,>);
16391724
}
16401725

16411726
public static bool IsNullableType(Type type)
16421727
{
1643-
return
1644-
#if SIMPLE_JSON_TYPEINFO
1645-
type.GetTypeInfo().IsGenericType
1646-
#else
1647-
type.IsGenericType
1648-
#endif
1649-
&& type.GetGenericTypeDefinition() == typeof(Nullable<>);
1728+
return GetTypeInfo(type).IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
16501729
}
16511730

16521731
public static object ToNullableType(object obj, Type nullableType)
@@ -1656,11 +1735,7 @@ public static object ToNullableType(object obj, Type nullableType)
16561735

16571736
public static bool IsValueType(Type type)
16581737
{
1659-
#if SIMPLE_JSON_TYPEINFO
1660-
return type.GetTypeInfo().IsValueType;
1661-
#else
1662-
return type.IsValueType;
1663-
#endif
1738+
return GetTypeInfo(type).IsValueType;
16641739
}
16651740

16661741
public static IEnumerable<ConstructorInfo> GetConstructors(Type type)
@@ -1704,7 +1779,7 @@ public static ConstructorInfo GetConstructorInfo(Type type, params Type[] argsTy
17041779
public static IEnumerable<PropertyInfo> GetProperties(Type type)
17051780
{
17061781
#if SIMPLE_JSON_TYPEINFO
1707-
return type.GetTypeInfo().DeclaredProperties;
1782+
return type.GetRuntimeProperties();
17081783
#else
17091784
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
17101785
#endif
@@ -1713,7 +1788,7 @@ public static IEnumerable<PropertyInfo> GetProperties(Type type)
17131788
public static IEnumerable<FieldInfo> GetFields(Type type)
17141789
{
17151790
#if SIMPLE_JSON_TYPEINFO
1716-
return type.GetTypeInfo().DeclaredFields;
1791+
return type.GetRuntimeFields();
17171792
#else
17181793
return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
17191794
#endif

RestSharp.Tests/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3-
<package id="SimpleJson" version="0.26.0" targetFramework="net35" />
3+
<package id="SimpleJson" version="0.38.0" targetFramework="net35" />
44
<package id="xunit" version="1.9.2" targetFramework="net35" />
55
<package id="xunit.extensions" version="1.9.2" targetFramework="net35" />
66
</packages>

0 commit comments

Comments
 (0)