Skip to content

Commit

Permalink
OutputCompletionSource
Browse files Browse the repository at this point in the history
  • Loading branch information
Frassle committed Nov 19, 2024
1 parent e105d32 commit b647f31
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Improvements-385.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
component: sdk
kind: Improvements
body: Add `DeferredOutput` for resolving some output/input cycles
time: 2024-11-19T08:28:36.110409Z
custom:
PR: "385"
32 changes: 32 additions & 0 deletions sdk/Pulumi.Tests/Core/OutputTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,38 @@ public Task FormatBraceSyntax() => RunInNormal(async () =>
Assert.False(data.IsSecret);
Assert.Equal("{ pip pip", data.Value);
});


[Fact]
public Task DeferredOutput()
=> RunInNormal(async () =>
{
var defO = new DeferredOutput<int>();
var o1 = CreateOutput(0, isKnown: true);
Assert.False(defO.Output.DataTask.IsCompleted);
defO.Resolve(o1);
var data = await defO.Output.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.Equal(0, data.Value);
});

[Fact]
public Task DeferredOutputOnlySetOnce()
=> RunInNormal(async () =>
{
var defO = new DeferredOutput<int>();
var o1 = CreateOutput(0, isKnown: true);
defO.Resolve(o1);
var o2 = CreateOutput(1, isKnown: true);
Assert.Throws<System.InvalidOperationException>(() => defO.Resolve(o2));
var data = await defO.Output.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.Equal(0, data.Value);
});
}
}
}
50 changes: 50 additions & 0 deletions sdk/Pulumi/Core/Output.cs
Original file line number Diff line number Diff line change
Expand Up @@ -707,4 +707,54 @@ public override string ToString()
return message;
}
}

/// <summary>
/// Represents the producer side of an <see cref="Output{T}"/> value, providing access to the consumer side through
/// the Output property.
/// </summary>
public sealed class DeferredOutput<T>
{
private int _set = 0;
private readonly TaskCompletionSource<OutputData<T>> _tcs = new TaskCompletionSource<OutputData<T>>();

/// <summary>
/// The <see cref="Output{T}"/> that represents the consumer side of this <see cref="DeferredOutput{T}"/>.
/// </summary>
public Output<T> Output { get; }

public DeferredOutput()
{
Output = new Output<T>(_tcs.Task);
}

/// <summary>
/// Resolves the value of the <see cref="Output{T}"/> represented by this <see
/// cref="DeferredOutput{T}"/> to the same eventually resolved result as the provided <see
/// cref="Output{T}"/>.
/// </summary>
public void Resolve(Output<T> output)
{
// Multithread safe check to ensure the DeferredOutput can only be set once.
if (System.Threading.Interlocked.Exchange(ref _set, 1) == 1)
{
throw new InvalidOperationException("DeferredOutput can only be resolved once.");
}

output.DataTask.ContinueWith(t =>
{
if (t.IsFaulted)
{
_tcs.SetException(t.Exception!);
}
else if (t.IsCanceled)
{
_tcs.SetCanceled();
}
else
{
_tcs.SetResult(t.Result);
}
});
}
}
}
18 changes: 18 additions & 0 deletions sdk/Pulumi/Pulumi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,24 @@
then).
</summary>
</member>
<member name="T:Pulumi.DeferredOutput`1">
<summary>
Represents the producer side of an <see cref="T:Pulumi.Output`1"/> value, providing access to the consumer side through
the Output property.
</summary>
</member>
<member name="P:Pulumi.DeferredOutput`1.Output">
<summary>
The <see cref="T:Pulumi.Output`1"/> that represents the consumer side of this <see cref="T:Pulumi.DeferredOutput`1"/>.
</summary>
</member>
<member name="M:Pulumi.DeferredOutput`1.Resolve(Pulumi.Output{`0})">
<summary>
Resolves the value of the <see cref="T:Pulumi.Output`1"/> represented by this <see
cref="T:Pulumi.DeferredOutput`1"/> to the same eventually resolved result as the provided <see
cref="T:Pulumi.Output`1"/>.
</summary>
</member>
<member name="T:Pulumi.OutputExtensions">
<summary>
Extension methods for <see cref="T:Pulumi.Output`1"/>.
Expand Down

0 comments on commit b647f31

Please sign in to comment.