Added a no exception mode for the VKV serializers.

This commit is contained in:
That-One-Nerd 2023-05-16 16:10:32 -04:00
parent 82afefd3e7
commit 7cad137f39
3 changed files with 109 additions and 75 deletions

View File

@ -1,6 +1,4 @@
using Valve.Vkv.ObjectModels; namespace Valve.Vkv;
namespace Valve.Vkv;
public static class VkvConvert public static class VkvConvert
{ {
@ -21,9 +19,19 @@ public static class VkvConvert
#region DeserializeNode #region DeserializeNode
public static VkvNode? DeserializeNode(StreamReader reader) => public static VkvNode? DeserializeNode(StreamReader reader) =>
DeserializeNode(reader, VkvOptions.Default, out _, null); DeserializeNode(reader, VkvOptions.Default);
public static VkvNode? DeserializeNode(StreamReader reader, VkvOptions options) => public static VkvNode? DeserializeNode(StreamReader reader, VkvOptions options)
DeserializeNode(reader, options, out _, null); {
try
{
return DeserializeNode(reader, options, out _, null);
}
catch
{
if (!options.noExceptions) throw;
return null;
}
}
private static VkvNode? DeserializeNode(StreamReader reader, VkvOptions options, out string name, private static VkvNode? DeserializeNode(StreamReader reader, VkvOptions options, out string name,
string? first) string? first)
@ -114,11 +122,19 @@ public static class VkvConvert
public static T? FromNodeTree<T>(VkvNode? node, VkvOptions options) => (T?)FromNodeTree(typeof(T), node, options); public static T? FromNodeTree<T>(VkvNode? node, VkvOptions options) => (T?)FromNodeTree(typeof(T), node, options);
public static object? FromNodeTree(Type outputType, VkvNode? node, VkvOptions options) public static object? FromNodeTree(Type outputType, VkvNode? node, VkvOptions options)
{ {
if (node is null) return null; try
{
if (node is null) return null;
if (node is VkvSingleNode single) return FromSingleNode(outputType, single); if (node is VkvSingleNode single) return FromSingleNode(outputType, single);
else if (node is VkvTreeNode tree) return FromTreeNode(outputType, tree, options); else if (node is VkvTreeNode tree) return FromTreeNode(outputType, tree, options);
else throw new VkvSerializationException("Unknown VKV node type."); else throw new VkvSerializationException("Unknown VKV node type.");
}
catch
{
if (!options.noExceptions) throw;
return null;
}
} }
private static object? FromSingleNode(Type outputType, VkvSingleNode node) private static object? FromSingleNode(Type outputType, VkvSingleNode node)
@ -267,9 +283,19 @@ public static class VkvConvert
#region SerializeNode #region SerializeNode
public static void SerializeNode(StreamWriter writer, VkvNode? node, string name, public static void SerializeNode(StreamWriter writer, VkvNode? node, string name,
VkvOptions options) => SerializeNode(writer, node, name, options, 0); VkvOptions options)
{
try
{
SerializeNode(writer, node, name, options, 0);
}
catch
{
if (!options.noExceptions) throw;
}
}
public static void SerializeNode(StreamWriter writer, VkvNode? node, string name) => public static void SerializeNode(StreamWriter writer, VkvNode? node, string name) =>
SerializeNode(writer, node, name, VkvOptions.Default, 0); SerializeNode(writer, node, name, VkvOptions.Default);
private static void SerializeNode(StreamWriter writer, VkvNode? node, string name, private static void SerializeNode(StreamWriter writer, VkvNode? node, string name,
VkvOptions options, int indentLevel) VkvOptions options, int indentLevel)
@ -343,73 +369,81 @@ public static class VkvConvert
public static VkvNode? ToNodeTree(object? obj) => ToNodeTree(obj, VkvOptions.Default); public static VkvNode? ToNodeTree(object? obj) => ToNodeTree(obj, VkvOptions.Default);
public static VkvNode? ToNodeTree(object? obj, VkvOptions options) public static VkvNode? ToNodeTree(object? obj, VkvOptions options)
{ {
if (obj is null) return null; try
Type type = obj.GetType();
if (type.IsPrimitive || TypeParsers.CanParse(obj)) return new VkvSingleNode(obj);
else if (type.IsPointer) throw new("Cannot serialize a pointer.");
VkvTreeNode tree = new();
if (obj is IVkvConvertible vkv) return vkv.ToNodeTree();
else if (obj is IDictionary dictionary)
{ {
object[] keys = new object[dictionary.Count], if (obj is null) return null;
values = new object[dictionary.Count]; Type type = obj.GetType();
dictionary.Keys.CopyTo(keys, 0);
dictionary.Values.CopyTo(values, 0); if (type.IsPrimitive || TypeParsers.CanParse(obj)) return new VkvSingleNode(obj);
for (int i = 0; i < dictionary.Count; i++) else if (type.IsPointer) throw new("Cannot serialize a pointer.");
VkvTreeNode tree = new();
if (obj is IVkvConvertible vkv) return vkv.ToNodeTree();
else if (obj is IDictionary dictionary)
{ {
tree[SerializeObject(keys.GetValue(i))!] = ToNodeTree(values.GetValue(i), options); object[] keys = new object[dictionary.Count],
values = new object[dictionary.Count];
dictionary.Keys.CopyTo(keys, 0);
dictionary.Values.CopyTo(values, 0);
for (int i = 0; i < dictionary.Count; i++)
{
tree[SerializeObject(keys.GetValue(i))!] = ToNodeTree(values.GetValue(i), options);
}
return tree;
} }
else if (obj is ICollection enumerable)
{
int index = 0;
foreach (object item in enumerable)
{
tree[SerializeObject(index)!] = ToNodeTree(item, options);
index++;
}
return tree;
}
IEnumerable<FieldInfo> validFields = from field in type.GetFields()
let isPublic = field.IsPublic
let isStatic = field.IsStatic
let isIgnored = field.CustomAttributes.Any(x =>
x.AttributeType == typeof(VkvIgnoreAttribute))
let isConst = field.IsLiteral
where isPublic && !isStatic && !isIgnored && !isConst
select field;
IEnumerable<PropertyInfo> validProperties;
if (options.serializeProperties)
{
validProperties = from prop in type.GetProperties()
let canGet = prop.GetMethod is not null
let isPublic = canGet && prop.GetMethod!.IsPublic
let isStatic = canGet && prop.GetMethod!.IsStatic
let isIgnored = prop.CustomAttributes.Any(x =>
x.AttributeType == typeof(VkvIgnoreAttribute))
where canGet && isPublic && !isStatic && !isIgnored
select prop;
}
else validProperties = Array.Empty<PropertyInfo>();
foreach (FieldInfo field in validFields)
{
VkvKeyNameAttribute? namingAttribute = field.GetCustomAttribute<VkvKeyNameAttribute>();
tree[namingAttribute?.name ?? field.Name] = ToNodeTree(field.GetValue(obj), options);
}
foreach (PropertyInfo prop in validProperties)
{
VkvKeyNameAttribute? namingAttribute = prop.GetCustomAttribute<VkvKeyNameAttribute>();
tree[namingAttribute?.name ?? prop.Name] = ToNodeTree(prop.GetValue(obj), options);
}
return tree; return tree;
} }
else if (obj is ICollection enumerable) catch
{ {
int index = 0; if (!options.noExceptions) throw;
foreach (object item in enumerable) return null;
{
tree[SerializeObject(index)!] = ToNodeTree(item, options);
index++;
}
return tree;
} }
IEnumerable<FieldInfo> validFields = from field in type.GetFields()
let isPublic = field.IsPublic
let isStatic = field.IsStatic
let isIgnored = field.CustomAttributes.Any(x =>
x.AttributeType == typeof(VkvIgnoreAttribute))
let isConst = field.IsLiteral
where isPublic && !isStatic && !isIgnored && !isConst
select field;
IEnumerable<PropertyInfo> validProperties;
if (options.serializeProperties)
{
validProperties = from prop in type.GetProperties()
let canGet = prop.GetMethod is not null
let isPublic = canGet && prop.GetMethod!.IsPublic
let isStatic = canGet && prop.GetMethod!.IsStatic
let isIgnored = prop.CustomAttributes.Any(x =>
x.AttributeType == typeof(VkvIgnoreAttribute))
where canGet && isPublic && !isStatic && !isIgnored
select prop;
}
else validProperties = Array.Empty<PropertyInfo>();
foreach (FieldInfo field in validFields)
{
VkvKeyNameAttribute? namingAttribute = field.GetCustomAttribute<VkvKeyNameAttribute>();
tree[namingAttribute?.name ?? field.Name] = ToNodeTree(field.GetValue(obj), options);
}
foreach (PropertyInfo prop in validProperties)
{
VkvKeyNameAttribute? namingAttribute = prop.GetCustomAttribute<VkvKeyNameAttribute>();
tree[namingAttribute?.name ?? prop.Name] = ToNodeTree(prop.GetValue(obj), options);
}
return tree;
} }
#endregion #endregion
} }

View File

@ -6,6 +6,7 @@ public record class VkvOptions
public bool closeWhenFinished; public bool closeWhenFinished;
public int indentSize; public int indentSize;
public bool noExceptions;
public bool resetStreamPosition; public bool resetStreamPosition;
public bool serializeProperties; public bool serializeProperties;
public SpacingMode spacing; public SpacingMode spacing;
@ -16,6 +17,7 @@ public record class VkvOptions
{ {
closeWhenFinished = true; closeWhenFinished = true;
indentSize = 4; indentSize = 4;
noExceptions = false;
resetStreamPosition = false; resetStreamPosition = false;
serializeProperties = true; serializeProperties = true;
spacing = SpacingMode.DoubleTab; spacing = SpacingMode.DoubleTab;

View File

@ -1,6 +1,4 @@
using System.Reflection.PortableExecutable; namespace Valve.Vkv;
namespace Valve.Vkv;
public class VkvSerializer public class VkvSerializer
{ {