Code/Core/Node.Interfaces.cs
namespace Nodebox;

public partial class Node {
    public interface INode {
        public IReadOnlyList<Pin> InputPins { get; }
        public IReadOnlyList<Pin> OutputPins { get; }
        public IReadOnlyList<IReadOnlySet<Wire>> InputWires { get; }
        public IReadOnlyList<IReadOnlySet<Wire>> OutputWires { get; }
        public IReadOnlyList<Pin> GetPins(Flow flow);
        public Pin GetPin(Flow flow, PinIndex index);
        public void AddPin(Flow flow, Pin pin, PinIndex? index = null);
        public void RemovePin(Flow flow, PinIndex? index = null);
        public void ReplacePin(Flow flow, PinIndex index, Pin pin);
    }

    public interface IVariadicInput<T> : INode {
        public virtual int MinInputs => 2;
        public virtual int MaxInputs => 16;
        public virtual bool CanGrowInputs() => InputPins.Count < MaxInputs;
        public virtual void GrowInputs() {
            if (!CanGrowInputs()) { return; }
            AddPin(Flow.Input, Pin.New<T>());
        }

        public virtual bool CanShrinkInputs() => InputPins.Count > MinInputs;
        public virtual void ShrinkInputs() {
            if (!CanShrinkInputs()) { return; }
            RemovePin(Flow.Input);
        }
    }

    public interface IVariadicOutput<T> : INode {
        public virtual int MinOutputs => 2;
        public virtual int MaxOutputs => 16;
        public virtual bool CanGrowOutputs() => OutputPins.Count < MaxOutputs;
        public virtual void GrowOutputs() {
            if (!CanGrowOutputs()) { return; }
            AddPin(Flow.Output, Pin.New<T>());
        }

        public virtual bool CanShrinkOutputs() => OutputPins.Count > MinOutputs;
        public virtual void ShrinkOutputs() {
            if (!CanShrinkOutputs()) { return; }
            RemovePin(Flow.Output);
        }
    }
}

public static class VariadicExtensions {
    extension<T>(Node.IVariadicInput<T> node) {
        public void GrowInputs() => node.GrowInputs();
        public void ShrinkInputs() => node.ShrinkInputs();
    }

    extension<T>(Node.IVariadicOutput<T> node) {
        public void GrowOutputs() => node.GrowOutputs();
        public void ShrinkOutputs() => node.ShrinkOutputs();
    }
}