Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.1 release #4

Merged
merged 11 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .github/workflows/compare-to-meta.yaml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/dotnet-build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ on:

jobs:
build-and-test:
uses: Nexus-Mods/NexusMods.App.Meta/.github/workflows/dotnet-build-and-test.yaml@780d2001be902a9523de8331da2c77c687abbddb
uses: Nexus-Mods/NexusMods.App.Meta/.github/workflows/dotnet-build-and-test-with-osx.yaml@3524469f29382df1060da5818da299e77727f9ce
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Changelog

## 0.1 - 22/1/2025
* Initial release of Cascade
6 changes: 6 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<Project>
<ItemGroup>
<PackageVersion Include="JetBrains.Annotations" Version="2024.3.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.1" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NexusMods.Hashing.xxHash3" Version="3.0.3" />
<PackageVersion Include="NexusMods.MnemonicDB" Version="0.9.98" />
<PackageVersion Include="NexusMods.MnemonicDB.Abstractions" Version="0.9.98" />
<PackageVersion Include="NexusMods.MnemonicDB.SourceGenerator" Version="0.9.98" />
<PackageVersion Include="NexusMods.Paths" Version="0.15.0" />
<PackageVersion Include="TransparentValueObjects" Version="1.0.2" />
<PackageVersion Include="TUnit" Version="0.6.59" />
Expand Down
1 change: 1 addition & 0 deletions NexusMods.Cascade.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".solutionItems", ".solution
NuGet.Build.props = NuGet.Build.props
icon.png = icon.png
mkdocs.yml = mkdocs.yml
CHANGELOG.md = CHANGELOG.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0377EBE6-F147-4233-86AD-32C821B9567E}"
Expand Down
57 changes: 25 additions & 32 deletions src/NexusMods.Cascade/AStageDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,11 @@ namespace NexusMods.Cascade;

public abstract class AStageDefinition : IStageDefinition
{
public AStageDefinition(ReadOnlySpan<(Type Type, string Name)> inputs, ReadOnlySpan<(Type Type, string Name)> outputs, ReadOnlySpan<IOutputDefinition> upstreamInputs)
protected AStageDefinition(IInputDefinition[] inputs, IOutputDefinition[] outputs, ReadOnlySpan<UpstreamConnection> upstreamInputs)
{
Inputs = GC.AllocateUninitializedArray<IInputDefinition>(inputs.Length);
Inputs = inputs;
Outputs = outputs;
UpstreamInputs = upstreamInputs.ToArray();

for (var i = 0; i < inputs.Length; i++)
{
Inputs[i] = (IInputDefinition)typeof(Input<>).MakeGenericType(inputs[i].Type)
.GetConstructor([typeof(IStageDefinition), typeof(string), typeof(int)])?
.Invoke([this, inputs[i].Name, i])!;
}

Outputs = GC.AllocateUninitializedArray<IOutputDefinition>(outputs.Length);

for (var i = 0; i < outputs.Length; i++)
{
Outputs[i] = (IOutputDefinition)typeof(Output<>).MakeGenericType(outputs[i].Type)
.GetConstructor([typeof(IStageDefinition), typeof(string), typeof(int)])!
.Invoke([this, outputs[i].Name, i])!;
}

}

/// <inheritdoc />
Expand All @@ -35,7 +19,7 @@ public AStageDefinition(ReadOnlySpan<(Type Type, string Name)> inputs, ReadOnlyS
public IInputDefinition[] Inputs { get; }

/// <inheritdoc />
public IOutputDefinition[] UpstreamInputs { get; set; }
public UpstreamConnection[] UpstreamInputs { get; set; }

/// <inheritdoc />
public abstract IStage CreateInstance(IFlowImpl flow);
Expand All @@ -54,12 +38,11 @@ protected Stage(IFlowImpl flow, IStageDefinition definition)
Flow = flow;
Definition = definition;

OutputSets = GC.AllocateUninitializedArray<IOutputSet>(definition.Outputs.Length);
ChangeSets = GC.AllocateUninitializedArray<IChangeSet>(definition.Outputs.Length);

for (var i = 0; i < definition.Outputs.Length; i++)
{
var type = typeof(DeduppingOutputSet<>).MakeGenericType(definition.Outputs[i].Type);
OutputSets[i] = (IOutputSet)Activator.CreateInstance(type)!;
ChangeSets[i] = definition.Outputs[i].CreateChangeSet();
}
}

Expand All @@ -70,17 +53,17 @@ protected Stage(IFlowImpl flow, IStageDefinition definition)
public IFlowImpl Flow { get; }

/// <inheritdoc />
public IOutputSet[] OutputSets { get; }
public IChangeSet[] ChangeSets { get; }

/// <inheritdoc />
public abstract void AddData(IOutputSet outputSet, int inputIndex);
public abstract void AcceptChanges<T>(ChangeSet<T> outputSet, int inputIndex) where T : notnull;

/// <summary>
/// Resets all outputs
/// </summary>
public void ResetAllOutputs()
{
foreach (var outputSet in OutputSets)
foreach (var outputSet in ChangeSets)
outputSet.Reset();
}
}
Expand All @@ -90,7 +73,7 @@ public void ResetAllOutputs()
/// <summary>
/// A typed input definition
/// </summary>
public record Input<T> : IInputDefinition
public record InputDefinition<T> : IInputDefinition where T : notnull
{
/// <inheritdoc />
public string Name { get; }
Expand All @@ -101,12 +84,23 @@ public record Input<T> : IInputDefinition
/// <inheritdoc />
public int Index { get; }

/// <summary>
/// Flow data into the stage from a previous stage via this input
/// </summary>
public void AcceptChanges(IStage stage, IChangeSet changes)
{
if (changes is not ChangeSet<T> typedChanges)
throw new ArgumentException("Invalid change set type", nameof(changes));

stage.AcceptChanges(typedChanges, Index);
}

/// <summary>
/// The primary constructor
/// </summary>
/// <param name="name"></param>
/// <param name="index"></param>
internal Input(string name, int index)
internal InputDefinition(string name, int index)
{
Name = name;
Index = index;
Expand All @@ -117,7 +111,7 @@ internal Input(string name, int index)
/// A typed output definition
/// </summary>
/// <typeparam name="T"></typeparam>
public record Output<T> : IOutputDefinition<T>
public record OutputDefinition<T> : IOutputDefinition<T>
where T : notnull
{
/// <inheritdoc />
Expand All @@ -130,14 +124,13 @@ public record Output<T> : IOutputDefinition<T>
public int Index { get; }

/// <inheritdoc />
public IStageDefinition Stage { get; }
public IChangeSet CreateChangeSet() => new ChangeSet<T>();

/// <summary>
/// The primary constructor
/// </summary>
public Output(IStageDefinition stage, string name, int index)
public OutputDefinition(string name, int index)
{
Stage = stage;
Name = name;
Index = index;
}
Expand Down
19 changes: 13 additions & 6 deletions src/NexusMods.Cascade/AUnaryStageDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,29 @@

namespace NexusMods.Cascade;

public abstract class AUnaryStageDefinition<TIn, TOut>(IOutputDefinition upstream)
: AStageDefinition([(typeof(TIn), "input")], [(typeof(TOut), "output")], [upstream]), IQuery<TOut>
/// <summary>
/// An abstract definition of a stage that takes a single input and produces a single output
/// </summary>
public abstract class AUnaryStageDefinition<TIn, TOut>(UpstreamConnection upstream)
: AStageDefinition(Inputs, Outputs, [upstream]), IQuery<TOut>
where TIn : notnull
where TOut : notnull
{
private static readonly IInputDefinition[] Inputs = [new InputDefinition<TIn>("input", 0)];

Check warning on line 14 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (ubuntu-latest)

'AUnaryStageDefinition<TIn, TOut>.Inputs' hides inherited member 'AStageDefinition.Inputs'. Use the new keyword if hiding was intended.

Check warning on line 14 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (windows-latest)

'AUnaryStageDefinition<TIn, TOut>.Inputs' hides inherited member 'AStageDefinition.Inputs'. Use the new keyword if hiding was intended.

Check warning on line 14 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (macos-latest)

'AUnaryStageDefinition<TIn, TOut>.Inputs' hides inherited member 'AStageDefinition.Inputs'. Use the new keyword if hiding was intended.

Check warning on line 14 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (macos-13)

'AUnaryStageDefinition<TIn, TOut>.Inputs' hides inherited member 'AStageDefinition.Inputs'. Use the new keyword if hiding was intended.
private static readonly IOutputDefinition[] Outputs = [new OutputDefinition<TOut>("output", 0)];

Check warning on line 15 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (ubuntu-latest)

'AUnaryStageDefinition<TIn, TOut>.Outputs' hides inherited member 'AStageDefinition.Outputs'. Use the new keyword if hiding was intended.

Check warning on line 15 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (windows-latest)

'AUnaryStageDefinition<TIn, TOut>.Outputs' hides inherited member 'AStageDefinition.Outputs'. Use the new keyword if hiding was intended.

Check warning on line 15 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (macos-latest)

'AUnaryStageDefinition<TIn, TOut>.Outputs' hides inherited member 'AStageDefinition.Outputs'. Use the new keyword if hiding was intended.

Check warning on line 15 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (macos-13)

'AUnaryStageDefinition<TIn, TOut>.Outputs' hides inherited member 'AStageDefinition.Outputs'. Use the new keyword if hiding was intended.
public IOutputDefinition<TOut> Output => (IOutputDefinition<TOut>)Outputs[0];

public abstract class Stage(IFlowImpl flow, IStageDefinition definition) : AStageDefinition.Stage(flow, definition)

Check warning on line 18 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (ubuntu-latest)

'AUnaryStageDefinition<TIn, TOut>.Stage' hides inherited member 'AStageDefinition.Stage'. Use the new keyword if hiding was intended.

Check warning on line 18 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (windows-latest)

'AUnaryStageDefinition<TIn, TOut>.Stage' hides inherited member 'AStageDefinition.Stage'. Use the new keyword if hiding was intended.

Check warning on line 18 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (macos-latest)

'AUnaryStageDefinition<TIn, TOut>.Stage' hides inherited member 'AStageDefinition.Stage'. Use the new keyword if hiding was intended.

Check warning on line 18 in src/NexusMods.Cascade/AUnaryStageDefinition.cs

View workflow job for this annotation

GitHub Actions / build-and-test / Build and Test (macos-13)

'AUnaryStageDefinition<TIn, TOut>.Stage' hides inherited member 'AStageDefinition.Stage'. Use the new keyword if hiding was intended.
{
protected abstract void Process(IOutputSet<TIn> input, IOutputSet<TOut> output);
protected abstract void Process(ChangeSet<TIn> input, ChangeSet<TOut> output);

public override void AddData(IOutputSet outputSet, int inputIndex)
/// <inheritdoc />
public override void AcceptChanges<T>(ChangeSet<T> outputSet, int inputIndex)
{
Debug.Assert(inputIndex == 0);
Process((IOutputSet<TIn>)outputSet, (IOutputSet<TOut>)OutputSets[0]);
Debug.Assert(typeof(T) == typeof(TIn));
// This cast should be removed by the optimizer when T == TIn
Process((ChangeSet<TIn>)(IChangeSet)outputSet, (ChangeSet<TOut>)ChangeSets[0]);
}
}

}
13 changes: 3 additions & 10 deletions src/NexusMods.Cascade/Abstractions/FlowOps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,17 @@ internal FlowOps(FlowImpl impl)
/// are assumed to all be equal to the specified delta.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddData<T>(IInletDefinition<T> inletDefinition, int delta, params ReadOnlySpan<T> input) where T : notnull
=> _impl.AddData(inletDefinition, input, delta);
public void AddData<T>(IInletDefinition<T> inletDefinition, ReadOnlySpan<Change<T>> changes) where T : notnull
=> _impl.AddData(inletDefinition, changes);

/// <summary>
/// Add input data to an inlet stage, if the stage does not exist in the flow yet, it will be added. The deltas
/// are assumed to all be equal to the specified delta.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddData<T>(IInletDefinition<T> inletDefinition, ReadOnlySpan<T> input, int delta = 1) where T : notnull
public void AddData<T>(IInletDefinition<T> inletDefinition, int delta, params ReadOnlySpan<T> input) where T : notnull
=> _impl.AddData(inletDefinition, input, delta);

/// <summary>
/// Add pairs of data and deltas to the inlet stages, if the stage does not exist in the flow yet, it will be added.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddData<T>(IInletDefinition<T> inletDefinition, ReadOnlySpan<(T Value, int delta)> input) where T : notnull
=> _impl.AddData(inletDefinition, input);

/// <summary>
/// Gets all the results of a query, running the query if it has not been added to the stage, otherwise it
/// will return the cached results
Expand Down
28 changes: 28 additions & 0 deletions src/NexusMods.Cascade/Abstractions/IChangeSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;

namespace NexusMods.Cascade.Abstractions;


/// <summary>
/// An interface for temporary storage of output values from a stage
/// </summary>
public interface IChangeSet
{
/// <summary>
/// Clear the output set
/// </summary>
void Reset();
}

/// <summary>
/// A result set for a stage.
/// </summary>
public interface IChangeSet<T> : IChangeSet, IReadOnlyCollection<Change<T>>
where T : notnull
{
/// <summary>
/// Add a change to the output set
/// </summary>
/// <param name="change"></param>
void Add(Change<T> change);
}
4 changes: 2 additions & 2 deletions src/NexusMods.Cascade/Abstractions/IInlet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ public interface IInlet<T> : IInlet
public void Add(ReadOnlySpan<T> input, int delta = 1);

/// <summary>
/// Add new data to the inlet
/// Add new set of changes to the inlet.
/// </summary>
public void Add(ReadOnlySpan<(T Item, int delta)> input);
public void Add(ReadOnlySpan<Change<T>> input);
}

/// <summary>
Expand Down
7 changes: 2 additions & 5 deletions src/NexusMods.Cascade/Abstractions/IObservableResultSet.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
using System.Collections.Generic;
namespace NexusMods.Cascade.Abstractions;

namespace NexusMods.Cascade.Abstractions;

public interface IObservableResultSet<T> : IEnumerable<T>
where T : notnull
public interface IObservableResultSet<T>
{
}
27 changes: 0 additions & 27 deletions src/NexusMods.Cascade/Abstractions/IOutputSet.cs

This file was deleted.

6 changes: 6 additions & 0 deletions src/NexusMods.Cascade/Abstractions/IQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,10 @@ public interface IQuery<T> : IQuery
where T : notnull
{
public IOutputDefinition<T> Output { get; }

/// <summary>
/// Create a upstream connection to this query
/// </summary>
/// <returns></returns>
public UpstreamConnection ToUpstreamConnection() => new(this, Output);
}
4 changes: 2 additions & 2 deletions src/NexusMods.Cascade/Abstractions/IStage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ public interface IStage
/// <summary>
/// The output sets of this stage
/// </summary>
public IOutputSet[] OutputSets { get; }
public IChangeSet[] ChangeSets { get; }

/// <summary>
/// Flow data into the stage from a previous stage into the given input index
/// </summary>
public void AddData(IOutputSet outputSet, int inputIndex);
public void AcceptChanges<T>(ChangeSet<T> outputSet, int inputIndex) where T : notnull;

/// <summary>
/// Resets the temporary state of the outputs of the stage
Expand Down
18 changes: 15 additions & 3 deletions src/NexusMods.Cascade/Abstractions/IStageDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface IStageDefinition
/// <summary>
/// The upstream inputs that this stage requires
/// </summary>
public IOutputDefinition[] UpstreamInputs { get; }
public UpstreamConnection[] UpstreamInputs { get; }

/// <summary>
/// Creates a new instance of the stage that will be attached to the flow
Expand All @@ -45,6 +45,11 @@ public interface IInputDefinition
/// The index of the input
/// </summary>
public int Index { get; }

/// <summary>
/// Accept untyped changes into this input
/// </summary>
public void AcceptChanges(IStage stage, IChangeSet changes);
}

public interface IInputDefinition<T> : IInputDefinition
Expand All @@ -62,9 +67,16 @@ public interface IOutputDefinition
public int Index { get; }

/// <summary>
/// Gets the associated stage
/// Create a new ChangeSet for this output definition
/// </summary>
public IStageDefinition Stage { get; }
/// <returns></returns>
public IChangeSet CreateChangeSet();

public void AcceptChanges<T>(IStage stage, int inputIndex, ChangeSet<T> changes) where T : notnull
{
stage.Definition.Inputs[inputIndex].AcceptChanges(stage, changes);

}
}

public interface IOutputDefinition<T> : IOutputDefinition
Expand Down
8 changes: 8 additions & 0 deletions src/NexusMods.Cascade/Change.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace NexusMods.Cascade;

/// <summary>
/// A pairing of a Value with a change delta (positive or negative integer)
/// </summary>
/// <typeparam name="T"></typeparam>
public readonly record struct Change<T>(T Value, int Delta)
where T : notnull;
Loading
Loading