From d530d39d7ed9b05e3e233adc62dceba2fd17e1fe Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Sun, 25 Oct 2020 16:58:42 +0200 Subject: Improved extension methods support on procedures. Drastically reduces procedure designer loading time. DataStore proto support fully working and tested. --- .../DataStore/RemoteDataStoreCollection.cs | 5 ++ .../DataStore/DefaultDataStoreService.cs | 11 ++++ .../Intellisense/KnownType.cs | 25 ++++++- .../Tango.Scripting.Editors/ScriptEditor.cs | 1 + .../Tango.Core/ExtensionMethods/TypeExtensions.cs | 76 +++++++++++++++++++--- .../Visual_Studio/Tango.Core/Tango.Core.csproj | 4 +- .../Tango.DataStore.Remote.csproj | 1 - .../Tango.DataStore/DataStoreHelper.cs | 35 ++-------- .../Tango.DataStore/DataStoreProtoObject.cs | 6 ++ .../Tango.DataStore/ExtensionMethods.cs | 16 +++++ .../Tango.DataStore/Tango.DataStore.csproj | 2 +- .../Tango.Emulations/Emulators/MachineEmulator.cs | 53 +++++++++++++++ .../ExtensionMethods/IMessageExtensions.cs | 27 ++++++++ Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj | 3 +- 14 files changed, 220 insertions(+), 45 deletions(-) create mode 100644 Software/Visual_Studio/Tango.DataStore/ExtensionMethods.cs create mode 100644 Software/Visual_Studio/Tango.PMR/ExtensionMethods/IMessageExtensions.cs (limited to 'Software/Visual_Studio') diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/DataStore/RemoteDataStoreCollection.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/DataStore/RemoteDataStoreCollection.cs index 4cf64a688..78e2bcfb1 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/DataStore/RemoteDataStoreCollection.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/DataStore/RemoteDataStoreCollection.cs @@ -136,6 +136,11 @@ namespace Tango.FSE.UI.DataStore public IDataStoreItem GetItem(string key, object defaultValue) { + if (defaultValue is IMessage defaultValueMessage) + { + defaultValue = DataStoreProtoObject.FromMessage(defaultValueMessage); + } + var result = _machineProvider.MachineOperator.SendGenericRequest(new RemoteDataStoreGetItemRequest() { Collection = Name, diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs index bf0eadae1..ddc0f6cdb 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs @@ -16,6 +16,7 @@ using Tango.PPC.Common.Connection; using Tango.PPC.Common.ExternalBridge; using Tango.Transport; using Tango.Core.ExtensionMethods; +using Newtonsoft.Json.Linq; namespace Tango.PPC.Common.DataStore { @@ -59,6 +60,11 @@ namespace Tango.PPC.Common.DataStore [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreGetRequest), RequestHandlerLoggingMode.LogRequestName)] public async Task OnRemoteDataStoreGetRequest(RemoteDataStoreGetRequest request, String token, ExternalBridgeReceiver receiver) { + if (request.DefaultValue is JObject obj) + { + request.DefaultValue = DataStoreProtoObject.FromJObject(obj); + } + var item = GetManager().GetCollection(request.Collection).GetItem(request.Key, request.DefaultValue); await receiver.SendGenericResponse(new RemoteDataStoreGetResponse() { @@ -70,6 +76,11 @@ namespace Tango.PPC.Common.DataStore [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreGetItemRequest), RequestHandlerLoggingMode.LogRequestName)] public async Task OnRemoteDataStoreGetItemRequest(RemoteDataStoreGetItemRequest request, String token, ExternalBridgeReceiver receiver) { + if (request.DefaultValue is JObject obj) + { + request.DefaultValue = DataStoreProtoObject.FromJObject(obj); + } + var item = GetManager().GetCollection(request.Collection).GetItem(request.Key, request.DefaultValue); await receiver.SendGenericResponse(new RemoteDataStoreGetItemResponse() { diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs index f55838db3..8010dc689 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections; using System.Collections.Generic; using System.Drawing; @@ -43,6 +44,13 @@ namespace Tango.Scripting.Editors.Intellisense } public List Fields { get; set; } + public static List ExtensionMethodsAssemblies { get; set; } + + static KnownType() + { + ExtensionMethodsAssemblies = new List(); + } + public KnownType(Type type) { Summary = "Loading documentation..."; @@ -131,11 +139,24 @@ namespace Tango.Scripting.Editors.Intellisense methods.AddRange(inter.GetRuntimeMethods().Where(x => x.IsPublic && !x.IsSpecialName).ToList()); } methods = methods.Distinct().ToList(); + + if (!methods.Exists(x => x.Name == "ToString")) + { + methods.Add(typeof(Object).GetMethod("ToString")); + } } //TODO: Separate extension methods! methods.AddRange(Type.GetExtensionMethods(Type.Assembly).ToList()); + if (Type.Namespace.StartsWith("Tango")) + { + foreach (var asm in ExtensionMethodsAssemblies.Where(x => x != Type.Assembly)) + { + methods.AddRange(Type.GetExtensionMethods(asm).ToList()); + } + } + if (typeof(IEnumerable).IsAssignableFrom(Type)) { var linqMethods = typeof(System.Linq.Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).ToList(); @@ -152,7 +173,7 @@ namespace Tango.Scripting.Editors.Intellisense m.Name = method.Name; m.ReturnType = method.ReturnType; m.ReturnTypeFriendlyName = method.ReturnType.GetFriendlyName(); - m.IsStatic = method.IsStatic; + m.IsStatic = method.IsStatic && !method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false); if (method.IsGenericMethod) { diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index 9ff78912f..e65ff671d 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -1808,6 +1808,7 @@ namespace Tango.Scripting.Editors _isLoadingTypes = true; var assemblies = ReferenceAssemblies.ToList(); + KnownType.ExtensionMethodsAssemblies = assemblies.ToList(); var usings = _current_usings.ToList(); Thread t = new Thread(() => diff --git a/Software/Visual_Studio/Tango.Core/ExtensionMethods/TypeExtensions.cs b/Software/Visual_Studio/Tango.Core/ExtensionMethods/TypeExtensions.cs index 66978ec19..44297b277 100644 --- a/Software/Visual_Studio/Tango.Core/ExtensionMethods/TypeExtensions.cs +++ b/Software/Visual_Studio/Tango.Core/ExtensionMethods/TypeExtensions.cs @@ -10,6 +10,19 @@ using System.Threading.Tasks; /// public static class TypeExtensions { + private class AssemblyExtensionMethods + { + public Assembly Assembly { get; set; } + public List Methods { get; set; } + + public AssemblyExtensionMethods() + { + Methods = new List(); + } + } + + private static List _extensionMethodsCache = new List(); + /// /// Gets all the extension methods registered in the specified assembly. /// @@ -18,14 +31,61 @@ public static class TypeExtensions /// public static IEnumerable GetExtensionMethods(this Type type, Assembly extensionsAssembly) { - var query = from t in extensionsAssembly.GetTypes() - where !t.IsGenericType && !t.IsNested - from m in t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) - where m.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false) - where m.GetParameters()[0].ParameterType == type - select m; - - return query; + if (type.Name == "CalculateRequest") + { + + } + + var asmMethods = _extensionMethodsCache.FirstOrDefault(x => x.Assembly == extensionsAssembly); + + if (asmMethods == null) + { + var query = from t in extensionsAssembly.GetTypes() + where !t.IsGenericType && !t.IsNested + from m in t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + where m.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false) + select m; + + asmMethods = new AssemblyExtensionMethods(); + asmMethods.Assembly = extensionsAssembly; + asmMethods.Methods = query.ToList(); + _extensionMethodsCache.Add(asmMethods); + } + + List methods = new List(); + + asmMethods.Methods.Where(x => x.GetParameters()[0].ParameterType.IsAssignableFrom(type)); + + foreach (var method in asmMethods.Methods) + { + var parameter = method.GetParameters()[0]; + + if (parameter.ParameterType.IsGenericParameter) + { + var constraints = parameter.ParameterType.GetGenericParameterConstraints().ToList(); + + if (constraints.Count > 0) + { + if (constraints[0].IsAssignableFrom(type)) + { + methods.Add(method); + } + else if (constraints[0].GetInterfaces().Any(x => x.IsAssignableFrom(type))) + { + methods.Add(method); + } + } + } + else + { + if (parameter.ParameterType.IsAssignableFrom(type)) + { + methods.Add(method); + } + } + } + + return methods; } /// diff --git a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj index 582fa9712..813a31443 100644 --- a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj +++ b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj @@ -155,7 +155,7 @@ - + @@ -220,7 +220,7 @@ - + diff --git a/Software/Visual_Studio/Tango.DataStore.Remote/Tango.DataStore.Remote.csproj b/Software/Visual_Studio/Tango.DataStore.Remote/Tango.DataStore.Remote.csproj index 2b05d6af3..4d0d04054 100644 --- a/Software/Visual_Studio/Tango.DataStore.Remote/Tango.DataStore.Remote.csproj +++ b/Software/Visual_Studio/Tango.DataStore.Remote/Tango.DataStore.Remote.csproj @@ -76,7 +76,6 @@ - diff --git a/Software/Visual_Studio/Tango.DataStore/DataStoreHelper.cs b/Software/Visual_Studio/Tango.DataStore/DataStoreHelper.cs index 3cf24bdd0..96a905120 100644 --- a/Software/Visual_Studio/Tango.DataStore/DataStoreHelper.cs +++ b/Software/Visual_Studio/Tango.DataStore/DataStoreHelper.cs @@ -35,7 +35,11 @@ namespace Tango.DataStore /// public static DataType GetDataType(Type type) { - if (type == typeof(Int32)) + if (type == typeof(int)) + { + return DataType.Int32; + } + else if (type == typeof(Int64)) { return DataType.Int32; } @@ -71,35 +75,6 @@ namespace Tango.DataStore throw new NotSupportedException($"The specified type '{type.Name}' is not supported by the data store."); } - /// - /// Gets the CLR type by specified data store data type. - /// - /// The type. - /// - /// The specified data type is not supported. - //public static Type GetType(DataType type) - //{ - // switch (type) - // { - // case DataType.Boolean: - // return typeof(bool); - // case DataType.Bytes: - // return typeof(byte[]); - // case DataType.Double: - // return typeof(double); - // case DataType.Float: - // return typeof(float); - // case DataType.Int32: - // return typeof(Int32); - // case DataType.String: - // return typeof(String); - // case DataType.Proto: - // return typeof(DataStoreProtoObject); - // } - - // throw new NotSupportedException("The specified data type is not supported."); - //} - /// /// Formats the data store item as a string. /// diff --git a/Software/Visual_Studio/Tango.DataStore/DataStoreProtoObject.cs b/Software/Visual_Studio/Tango.DataStore/DataStoreProtoObject.cs index ec4cf1057..6661c2017 100644 --- a/Software/Visual_Studio/Tango.DataStore/DataStoreProtoObject.cs +++ b/Software/Visual_Studio/Tango.DataStore/DataStoreProtoObject.cs @@ -1,5 +1,6 @@ using Google.Protobuf; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.IO; @@ -59,6 +60,11 @@ namespace Tango.DataStore return proto; } + public static DataStoreProtoObject FromJObject(JObject obj) + { + return (obj.ToObject()); + } + public static DataStoreProtoObject FromPMRDataStoreItem(DataStoreItem item) { DataStoreProtoObject proto = new DataStoreProtoObject(); diff --git a/Software/Visual_Studio/Tango.DataStore/ExtensionMethods.cs b/Software/Visual_Studio/Tango.DataStore/ExtensionMethods.cs new file mode 100644 index 000000000..acc381a61 --- /dev/null +++ b/Software/Visual_Studio/Tango.DataStore/ExtensionMethods.cs @@ -0,0 +1,16 @@ +using Google.Protobuf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.DataStore; + +public static class ExtensionMethods +{ + public static DataStoreProtoObject ToDataStoreProtoObject(IMessage message) + { + return DataStoreProtoObject.FromMessage(message); + } +} + diff --git a/Software/Visual_Studio/Tango.DataStore/Tango.DataStore.csproj b/Software/Visual_Studio/Tango.DataStore/Tango.DataStore.csproj index 8035af7b4..c12abe9e8 100644 --- a/Software/Visual_Studio/Tango.DataStore/Tango.DataStore.csproj +++ b/Software/Visual_Studio/Tango.DataStore/Tango.DataStore.csproj @@ -54,6 +54,7 @@ + @@ -61,7 +62,6 @@ - diff --git a/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs b/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs index e5296ab4c..6b49ca4eb 100644 --- a/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs +++ b/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs @@ -2060,6 +2060,59 @@ namespace Tango.Emulations.Emulators LogManager.Log(ex, "Failed."); } } + + { + try + { + LogManager.Log("Testing int default..."); + + var res = await Transporter.SendRequest(new GetDataStoreItemRequest() + { + Collection = "TEST", + Key = "intDefault", + DefaultItem = new PMR.DataStore.DataStoreItem() + { + DataType = DataType.Int32, + Int32Value = 10, + }, + }); + + LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed."); + LogManager.Log(res.ToJsonString()); + } + catch (Exception ex) + { + LogManager.Log(ex, "Failed."); + } + } + + { + try + { + LogManager.Log("Testing proto default..."); + + var res = await Transporter.SendRequest(new GetDataStoreItemRequest() + { + Collection = "TEST", + Key = "protoDefault", + DefaultItem = new PMR.DataStore.DataStoreItem() + { + DataType = DataType.Proto, + BytesValue = (new CalculateRequest() { A = 10, B = 15 }).ToByteString(), + ProtoType = MessageType.CalculateRequest, + }, + }); + + LogManager.Log(res.Container.Error != ErrorCode.None ? "Get Failed." : "Passed."); + + LogManager.Log(CalculateRequest.Parser.ParseFrom(res.Message.Item.BytesValue).ToJsonString()); + LogManager.Log(res.ToJsonString()); + } + catch (Exception ex) + { + LogManager.Log(ex, "Failed."); + } + } } #endregion diff --git a/Software/Visual_Studio/Tango.PMR/ExtensionMethods/IMessageExtensions.cs b/Software/Visual_Studio/Tango.PMR/ExtensionMethods/IMessageExtensions.cs new file mode 100644 index 000000000..84acb51d2 --- /dev/null +++ b/Software/Visual_Studio/Tango.PMR/ExtensionMethods/IMessageExtensions.cs @@ -0,0 +1,27 @@ +using Google.Protobuf; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +public static class IMessageExtensions +{ + /// + /// Serializes this PMR message to byte array. + /// + /// + /// The message. + /// + public static byte[] ToBytes(this T message) where T : IMessage + { + using (MemoryStream ms = new MemoryStream()) + { + message.WriteTo(ms); + return ms.ToArray(); + } + } +} + diff --git a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj index 7b3a7c397..bb44ef591 100644 --- a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj +++ b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj @@ -189,6 +189,7 @@ + @@ -482,7 +483,7 @@ - + \ No newline at end of file -- cgit v1.3.1