Skip to content

Commit

Permalink
Work on Parse DataTree to known Objects
Browse files Browse the repository at this point in the history
  • Loading branch information
patrick-dmxc committed Nov 1, 2024
1 parent e636b05 commit 820675a
Show file tree
Hide file tree
Showing 18 changed files with 486 additions and 65 deletions.
122 changes: 122 additions & 0 deletions RDMSharp/Metadata/DataTreeBranch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using RDMSharp.Metadata.JSON;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace RDMSharp.Metadata
{
public readonly struct DataTreeBranch : IEquatable<DataTreeBranch>
{
public static readonly DataTreeBranch Empty = new DataTreeBranch();
public static readonly DataTreeBranch Unset = new DataTreeBranch(true);

public readonly DataTree[] Children;
public readonly bool IsEmpty;
public readonly bool IsUnset;

public readonly object ParsedObject;
public DataTreeBranch()
{
IsEmpty = true;
}
private DataTreeBranch(bool isUnset)
{
IsUnset = true;
}
public DataTreeBranch(params DataTree[] children)
{
if (children.Length == 0)
IsEmpty = true;

Children = children;
}
public DataTreeBranch(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, params DataTree[] children): this(children)
{
if (define == null)
throw new ArgumentNullException();

ParsedObject = this.getParsedObject(define, commandType);
}

private object getParsedObject(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType)
{
if (IsEmpty || IsUnset)
return null;

var definedDataTreeObjectType = MetadataFactory.GetDefinedDataTreeObjectType(define, commandType);
if (definedDataTreeObjectType != null)
{
if (definedDataTreeObjectType.IsEnum)
return Enum.ToObject(definedDataTreeObjectType, Children.Single().Value);

ConstructorInfo[] constructors = definedDataTreeObjectType.GetConstructors();

foreach (var constructor in constructors)
{
if (constructor.GetCustomAttribute<DataTreeObjectConstructorAttribute>() is DataTreeObjectConstructorAttribute cAttribute)
{
var parameters = new List<object>();
foreach (var param in constructor.GetParameters())
if (param.GetCustomAttribute<DataTreeObjectParameterAttribute>() is DataTreeObjectParameterAttribute pAttribute)
{
if (Children.FirstOrDefault(c => string.Equals(c.Name, pAttribute.Name)) is DataTree child)
parameters.Add(child.Value);
else
throw new ArgumentException($"No matching Value found for '{pAttribute.Name}'");
}

var instance = constructor.Invoke(parameters.ToArray());
return instance;
}
}
}

if (Children.Length == 1)
{
DataTree dataTree = Children[0];

if (dataTree.Value != null)
return dataTree.Value;

if (dataTree.Children.GroupBy(c => c.Name).Count() == 1)
{
var list = dataTree.Children.Select(c => c.Value).ToList();
Type targetType = list.First().GetType();
var array = Array.CreateInstance(targetType, list.Count);
for (int i = 0; i < list.Count; i++)
array.SetValue(Convert.ChangeType(list[i], targetType), i);

return array;
}
}

throw new NotImplementedException();
}

public override bool Equals(object obj)
{
return obj is DataTreeBranch branch && Equals(branch);
}

public bool Equals(DataTreeBranch other)
{
return EqualityComparer<DataTree[]>.Default.Equals(Children, other.Children);
}

public override int GetHashCode()
{
return HashCode.Combine(Children);
}

public static bool operator ==(DataTreeBranch left, DataTreeBranch right)
{
return left.Equals(right);
}

public static bool operator !=(DataTreeBranch left, DataTreeBranch right)
{
return !(left == right);
}
}
}
17 changes: 17 additions & 0 deletions RDMSharp/Metadata/DataTreeObjectAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using RDMSharp.Metadata.JSON;
using System;

namespace RDMSharp.Metadata;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = true)]
public class DataTreeObjectAttribute : Attribute
{
public readonly ERDM_Parameter Parameter;
public readonly Command.ECommandDublicte Command;

public DataTreeObjectAttribute(ERDM_Parameter parameter, Command.ECommandDublicte command)
{
Parameter = parameter;
Command = command;
}
}
11 changes: 11 additions & 0 deletions RDMSharp/Metadata/DataTreeObjectConstructorAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace RDMSharp.Metadata;

[AttributeUsage(AttributeTargets.Constructor)]
public class DataTreeObjectConstructorAttribute : Attribute
{
public DataTreeObjectConstructorAttribute()
{
}
}
14 changes: 14 additions & 0 deletions RDMSharp/Metadata/DataTreeObjectParameterAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace RDMSharp.Metadata;

[AttributeUsage(AttributeTargets.Parameter)]
public class DataTreeObjectParameterAttribute : Attribute
{
public readonly string Name;

public DataTreeObjectParameterAttribute(string name)
{
Name = name;
}
}
2 changes: 0 additions & 2 deletions RDMSharp/Metadata/JSON/OneOfTypes/ReferenceType.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using RDMSharp.RDM;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Xml.Linq;

namespace RDMSharp.Metadata.JSON.OneOfTypes
{
Expand Down
54 changes: 43 additions & 11 deletions RDMSharp/Metadata/MetadataFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Nodes;
Expand All @@ -20,6 +21,7 @@ public static class MetadataFactory
private static List<MetadataVersion> metadataVersionList;
private static Dictionary<MetadataVersion,List<MetadataJSONObjectDefine>> metadataVersionDefinesBagDictionary;
private static ConcurrentDictionary<ParameterBag, MetadataJSONObjectDefine> parameterBagDefineCache;

public static IReadOnlyCollection<MetadataVersion> MetadataVersionList
{
get
Expand Down Expand Up @@ -138,7 +140,7 @@ private static MetadataJSONObjectDefine getDefine(ParameterBag parameter)
throw new DefineNotFoundException($"{parameter}");
}

internal static byte[] ParsePayloadToData(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, object payload)
internal static byte[] ParsePayloadToData(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, DataTreeBranch payload)
{
define.GetCommand(commandType, out Command? _command);
if (_command is not Command command)
Expand All @@ -147,10 +149,10 @@ internal static byte[] ParsePayloadToData(MetadataJSONObjectDefine define, Comma
if (command.GetIsEmpty())
return new byte[0];

if (payload is DataTree dataTree && command.SingleField.HasValue)
if (payload.Children.SingleOrDefault() is DataTree dataTree && command.SingleField.HasValue)
return command.SingleField.Value.ParsePayloadToData(dataTree);

if (payload is DataTree[] dataTreeArray && command.ListOfFields.Length != 0)
if (payload.Children is DataTree[] dataTreeArray && command.ListOfFields.Length != 0)
{
if (dataTreeArray.Length != command.ListOfFields.Length)
throw new IndexOutOfRangeException();
Expand All @@ -162,43 +164,73 @@ internal static byte[] ParsePayloadToData(MetadataJSONObjectDefine define, Comma

throw new ArithmeticException();
}
internal static object ParseDataToPayload(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, byte[] data)
internal static DataTreeBranch ParseDataToPayload(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType, byte[] data)
{
define.GetCommand(commandType, out Command? _command);
if (_command is not Command command)
throw new InvalidOperationException();

if (command.GetIsEmpty())
return null;
return DataTreeBranch.Empty;

if (command.SingleField.HasValue)
return command.SingleField.Value.ParseDataToPayload(ref data);
return new DataTreeBranch(define, commandType, command.SingleField.Value.ParseDataToPayload(ref data));

if (command.ListOfFields.Length != 0)
{
List<DataTree> tree = new List<DataTree>();
for (int i = 0; i < command.ListOfFields.Length; i++)
tree.Add(command.ListOfFields[i].ParseDataToPayload(ref data));
return tree.ToArray();
return new DataTreeBranch(define, commandType, tree.ToArray());
}

throw new ArithmeticException();
}
internal static byte[] GetRequestMessageData(ParameterBag parameter, object payloadData)
internal static byte[] GetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData)
{
return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.GetRequest, payloadData);
}
internal static byte[] GetResponseMessageData(ParameterBag parameter, object payloadData)
internal static byte[] GetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData)
{
return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.GetResponse, payloadData);
}
internal static byte[] SetRequestMessageData(ParameterBag parameter, object payloadData)
internal static byte[] SetRequestMessageData(ParameterBag parameter, DataTreeBranch payloadData)
{
return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.SetRequest, payloadData);
}
internal static byte[] SetResponseMessageData(ParameterBag parameter, object payloadData)
internal static byte[] SetResponseMessageData(ParameterBag parameter, DataTreeBranch payloadData)
{
return ParsePayloadToData(GetDefine(parameter), Command.ECommandDublicte.SetResponse, payloadData);
}

private static List<Type> definedDataTreeObjects;
public static IReadOnlyCollection<Type> DefinedDataTreeObjects
{
get
{
fillDefinedDataTreeObjects();
return definedDataTreeObjects;
}
}

private static void fillDefinedDataTreeObjects()
{
if (definedDataTreeObjects != null)
return;

definedDataTreeObjects = new List<Type>();

definedDataTreeObjects.AddRange(Tools.FindClassesWithAttribute<DataTreeObjectAttribute>());
}

public static Type GetDefinedDataTreeObjectType(MetadataJSONObjectDefine define, Command.ECommandDublicte commandType)
{
return DefinedDataTreeObjects.Where(t =>
{
if (t.GetCustomAttributes<DataTreeObjectAttribute>().Any(attribute => (ushort)attribute.Parameter == define.PID && attribute.Command == commandType))
return true;
return false;
}).FirstOrDefault();
}
}
}
7 changes: 6 additions & 1 deletion RDMSharp/RDM/Enum/ERDM_DisplayInvert.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
namespace RDMSharp
using RDMSharp.Metadata;
using RDMSharp.Metadata.JSON;

namespace RDMSharp
{
[DataTreeObject(ERDM_Parameter.DISPLAY_INVERT, Command.ECommandDublicte.GetResponse)]
[DataTreeObject(ERDM_Parameter.DISPLAY_INVERT, Command.ECommandDublicte.SetRequest)]
public enum ERDM_DisplayInvert : byte
{
OFF = 0x00,
Expand Down
6 changes: 5 additions & 1 deletion RDMSharp/RDM/Enum/ERDM_Status.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace RDMSharp
using RDMSharp.Metadata;
using RDMSharp.Metadata.JSON;

namespace RDMSharp
{
[DataTreeObject(ERDM_Parameter.STATUS_MESSAGES, Command.ECommandDublicte.GetRequest)]
public enum ERDM_Status : byte
{
NONE = 0x00,
Expand Down
14 changes: 9 additions & 5 deletions RDMSharp/RDM/PayloadObject/RDMDMXPersonality.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
using System;
using RDMSharp.Metadata;
using RDMSharp.Metadata.JSON;
using System;
using System.Collections.Generic;

namespace RDMSharp
{
{
[DataTreeObject(ERDM_Parameter.DMX_PERSONALITY, Command.ECommandDublicte.GetResponse)]
public class RDMDMXPersonality : AbstractRDMPayloadObjectOneOf
{
{
[DataTreeObjectConstructor]
public RDMDMXPersonality(
byte currentPersonality = 1,
byte ofPersonalities = 0)
[DataTreeObjectParameter("personality")] byte currentPersonality = 1,
[DataTreeObjectParameter("personality_count")] byte ofPersonalities = 0)
{
this.CurrentPersonality = currentPersonality;
this.OfPersonalities = ofPersonalities;
Expand Down
16 changes: 10 additions & 6 deletions RDMSharp/RDM/PayloadObject/RDMDMXPersonalityDescription.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
using System.Collections.Generic;
using RDMSharp.Metadata;
using RDMSharp.Metadata.JSON;
using System.Collections.Generic;

namespace RDMSharp
{
{
[DataTreeObject(ERDM_Parameter.DMX_PERSONALITY_DESCRIPTION, Command.ECommandDublicte.GetResponse)]
public class RDMDMXPersonalityDescription : AbstractRDMPayloadObject, IRDMPayloadObjectIndex
{
{
[DataTreeObjectConstructor]
public RDMDMXPersonalityDescription(
byte personalityId = 1,
ushort slots = 0,
string description = "")
[DataTreeObjectParameter("personality")] byte personalityId = 1,
[DataTreeObjectParameter("dmx_slots_required")] ushort slots = 0,
[DataTreeObjectParameter("description")] string description = "")
{
this.PersonalityId = personalityId;
this.Slots = slots;
Expand Down
Loading

0 comments on commit 820675a

Please sign in to comment.