using System.Globalization; using NodePipeline.Abstractions; using NodePipeline.Abstractions.Exceptions.NodeFactory; using NodePipeline.Abstractions.Interfaces; using NodePipeline.Abstractions.Interfaces.Nodes; using NodePipeline.Configuration.Abstractions.Models.Execute; using NodePipeline.Engine.Abstractions; using NodePipeline.Engine.NodeFields; using NodePipeline.Engine.Utils; using NodePipeline.Engine.Abstractions.Validation; // ReSharper disable CheckNamespace // ReSharper disable ConvertTypeCheckPatternToNullCheck // ReSharper disable RedundantCast // ReSharper disable RedundantNameQualifier // ReSharper disable ReturnTypeCanBeNotNullable // ReSharper disable UnusedMember.Local // ReSharper disable UnusedParameter.Local #nullable enable namespace NodePipeline.Engine.Generated; public sealed class GeneratedNodeFactory : INodeFactory { public Dictionary> NodeFactories { get; set; } = new(); public IPipelineLocalizationProvider PipelineLocalizationProvider { get; set; } = new PipelineLocalizationProvider(); public INode CreateNode(string pipelineId, NodeConfig config) { INode? node; if (NodeFactories.TryGetValue(config.Type, out var f)) { node = f(); InitializeNodeFields(pipelineId, node, config.Id); return node; } switch (config.Type) { default: throw new NodeNotFoundException(pipelineId, config.Type, config.Id); } InitializeNodeFields(pipelineId, node, config.Id); return node ?? throw new NodeWasNotInitializedException(pipelineId, config.Type, config.Id); } private void InitializeNodeFields(string pipelineId, INode node, string nodeId) { switch (node) { default: throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId); } } public IEnumerable GetParameterCodes(string nodeType) { switch (nodeType) { default: throw new NodeTypeNotFoundException(nodeType); } } public object? ReadParameterValue(string pipelineId, string nodeId, string nodeType, string parameterName, string? valueString) { switch (nodeType) { default: throw new NodeTypeNotFoundException(nodeType); } } public Dictionary GetAllPorts(string pipelineId, HashSet nodeTypes, Dictionary> nodeList) { var result = new Dictionary(); foreach (var nodeType in nodeTypes) { if (!nodeList.TryGetValue(nodeType, out var ids)) continue; foreach (var nodeId in ids) { var ports = GetNodePorts(pipelineId, nodeType, nodeId); foreach (var kv in ports) result.Add(kv.Key, kv.Value); } } return result; } public IEnumerable GetNodeInputPorts(string pipelineId, string nodeType, string nodeId) { var ports = GetNodePorts(pipelineId, nodeType, nodeId); foreach (var kv in ports) if (kv.Key.Input) yield return kv.Value; } private Dictionary GetNodePorts(string pipelineId, string nodeType, string nodeId) { switch (nodeType) { default: throw new NodeNotFoundException(pipelineId, nodeType, nodeId); } } private IReadOnlyDictionary GetNodeOutputs(string pipelineId, string nodeId, INode node) { switch (node) { default: throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId); } } public void ConnectPorts(string pipelineId, TNode node, string nodeId, Dictionary inputs, IReadOnlyDictionary createdNodes) where TNode : INode { switch (node) { default: throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId); } } private PortConnectionInfo? TryConnectPorts(string pipelineId, string nodeId, string nodeType, INodeField? nodeInput, string nodeInputName, Dictionary inputs, string inputKey, IReadOnlyDictionary createdNodes, bool isRequired = false) where T : notnull { if (!inputs.TryGetValue(inputKey, out var connection)) return !isRequired ? null : throw new InputPortHasNoRequiredConnectionException(pipelineId, inputKey, nodeId, nodeType); var fromNodeId = connection.NodeId; var fromPortName = connection.OutputName; if (nodeInput == null) throw new InputPortNotFoundException(pipelineId, inputKey, nodeId, nodeType); if (!createdNodes.TryGetValue(fromNodeId, out var fromNode)) throw new OutputPortNodeNotFoundException(pipelineId, fromNodeId, nodeId); var outputs = GetNodeOutputs(pipelineId, fromNodeId, fromNode); var outputFieldKey = NodeFieldCodeGenerator.GenerateFieldCode(fromNodeId, fromPortName, FieldDirection.Output); if (!outputs.TryGetValue(outputFieldKey, out var outputFieldObj)) throw new OutputPortNotFoundException(pipelineId, fromPortName, fromNodeId, nodeId); var fromNodeType = GetNodeType(pipelineId, fromNodeId, fromNode); if (outputFieldObj is INodeField outStrict && nodeInput is INodeField inStrict) { PortConnector.ConnectStatic(outStrict, inStrict); return new PortConnectionInfo(true, outputFieldObj, fromPortName, fromNodeType, fromNodeId); } return new PortConnectionInfo(false, outputFieldObj, fromPortName, fromNodeType, fromNodeId); } private void ConnectPortsStruct(string pipelineId, string nodeId,string nodeType, INodeField? nodeInput, string nodeInputName, Dictionary inputs, string inputKey, IReadOnlyDictionary createdNodes, bool disallowNullableOutput = false, bool isRequired = false) where T : struct { var portConnectionInfo = TryConnectPorts(pipelineId, nodeId, nodeType, nodeInput, nodeInputName, inputs, inputKey, createdNodes, isRequired); if (portConnectionInfo is null || portConnectionInfo.Connected) return; if (typeof(T).IsValueType && portConnectionInfo.OutputFieldObj is INodeField outputField) { PortConnector.ConnectRuntimeFromNullableStruct(outputField, nodeInput!, nodeId, inputKey, portConnectionInfo.FromNodeId, portConnectionInfo.FromPortName); return; } if (portConnectionInfo.OutputFieldObj is INodeField outNullable && nodeInput is INodeField inNullable) { PortConnector.ConnectRuntimeBothNullable(outNullable, inNullable); return; } if (portConnectionInfo.OutputFieldObj is INodeField outNToStrict && nodeInput != null) { if (disallowNullableOutput) { throw new NonNullableInputRestrictsConnectionToNullableOutputException(pipelineId, nodeId, nodeType, inputKey, portConnectionInfo.FromPortName, portConnectionInfo.FromNodeId); } PortConnector.ConnectRuntimeFromNullableStruct(outNToStrict, nodeInput, currentNodeId: nodeId, inputPortName: inputKey, sourceNodeId: portConnectionInfo.FromNodeId, outputPortName: portConnectionInfo.FromPortName); return; } if (portConnectionInfo.OutputFieldObj is INodeField outStrictToN && nodeInput is INodeField inNullable2) { PortConnector.ConnectRuntimeToNullableStruct(outStrictToN, inNullable2); return; } throw new PortsTypeMismatchException(pipelineId, inputKey, nodeType, nodeId, portConnectionInfo.FromPortName, portConnectionInfo.FromNodeType, portConnectionInfo.FromNodeId); } private void ConnectPortsClass(string pipelineId, string nodeId,string nodeType, INodeField? nodeInput, string nodeInputName, Dictionary inputs, string inputKey, IReadOnlyDictionary createdNodes, bool disallowNullableOutput = false, bool isRequired = false) where T : class { var portConnectionInfo = TryConnectPorts(pipelineId, nodeId, nodeType, nodeInput, nodeInputName, inputs, inputKey, createdNodes, isRequired); if (portConnectionInfo is null || portConnectionInfo.Connected) return; if (!typeof(T).IsValueType && portConnectionInfo.OutputFieldObj is INodeField outputField) { PortConnector.ConnectRuntimeFromNullableClass(outputField, nodeInput!, nodeId, inputKey, portConnectionInfo.FromNodeId, portConnectionInfo.FromPortName); return; } if (portConnectionInfo.OutputFieldObj is INodeField outNullable && nodeInput is INodeField inNullable) { PortConnector.ConnectRuntimeBothNullable(outNullable, (INodeField)inNullable); return; } if (portConnectionInfo.OutputFieldObj is INodeField outNToStrict && nodeInput != null) { if (disallowNullableOutput) { throw new NonNullableInputRestrictsConnectionToNullableOutputException(pipelineId, nodeId, nodeType, inputKey, portConnectionInfo.FromPortName, portConnectionInfo.FromNodeId); } PortConnector.ConnectRuntimeFromNullableClass(outNToStrict, nodeInput, currentNodeId: nodeId, inputPortName: inputKey, sourceNodeId: portConnectionInfo.FromNodeId, outputPortName: portConnectionInfo.FromPortName); return; } if (portConnectionInfo.OutputFieldObj is INodeField outStrictToN && nodeInput is INodeField inNullable2) { PortConnector.ConnectRuntimeToNullableClass(outStrictToN, (INodeField)inNullable2); return; } throw new PortsTypeMismatchException(pipelineId, inputKey, nodeType, nodeId, portConnectionInfo.FromPortName, portConnectionInfo.FromNodeType, portConnectionInfo.FromNodeId); } private static T? ParseParameter(string? valueString) { var type = typeof(T); if (type == typeof(string)) return valueString is not null ? (T)(object)valueString : default; if (string.IsNullOrEmpty(valueString)) return default; if (type == typeof(int)) return (T)(object)int.Parse(valueString); if (type == typeof(double)) return (T)(object)double.Parse(valueString, CultureInfo.InvariantCulture); if (type == typeof(bool)) return (T)(object)bool.Parse(valueString); throw new NotSupportedException(type.Name); } public object GetParameterDefaultValue(string nodeType, string parameterName) { switch (nodeType) { default: throw new NodeParameterNotFoundException(parameterName, nodeType); } } private static T? GetDefaultValue() { var type = typeof(T); if (type == typeof(string)) return (T)(object)string.Empty; if (type == typeof(int)) return (T)(object)0; if (type == typeof(double)) return (T)(object)0d; if (type == typeof(decimal)) return (T)(object)0m; if (type == typeof(bool)) return (T)(object)false; if (type == typeof(Guid)) return (T)(object)Guid.Empty; if (type.IsEnum) return default; throw new NotSupportedException(type.Name); } public void SetNodeParametersValues(string pipelineId, TNode node, string nodeId, Dictionary parameters) where TNode : INode { switch (node) { default: throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId); } } private static string GetNodeType(string pipelineId, string nodeId, INode node) { switch (node) { default: throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId); } } private record PortConnectionInfo(bool Connected, object? OutputFieldObj, string FromPortName, string FromNodeType, string FromNodeId); } #nullable restore