Skip to content

Commit 23e73af

Browse files
added CopyTo & TryGetValue for DurableOrderedSet + extra tests for DurableStack
1 parent 6de9c62 commit 23e73af

File tree

4 files changed

+154
-3
lines changed

4 files changed

+154
-3
lines changed

DurableStateMachines.Tests/DurableOrderedSetTests.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public interface IDurableOrderedSetGrain : IGrainWithStringKey
1414
Task Clear();
1515
Task<List<string>> GetAll();
1616
Task<string[]> GetOrderedItemsAsArray();
17+
Task<(bool Found, string? ActualValue)> TryGetValue(string value);
18+
Task<string[]> CopyToArray(int arraySize, int arrayIndex);
1719
}
1820

1921
public class DurableOrderedSetGrain([FromKeyedServices("ordered_set")]
@@ -55,6 +57,20 @@ public async Task Clear()
5557

5658
public Task<List<string>> GetAll() => Task.FromResult(state.ToList());
5759
public Task<string[]> GetOrderedItemsAsArray() => Task.FromResult(state.OrderedItems.ToArray());
60+
61+
public Task<(bool Found, string? ActualValue)> TryGetValue(string value)
62+
{
63+
var found = state.TryGetValue(value, out var actualValue);
64+
return Task.FromResult((found, actualValue));
65+
}
66+
67+
public Task<string[]> CopyToArray(int arraySize, int arrayIndex)
68+
{
69+
var array = new string[arraySize];
70+
state.CopyTo(array, arrayIndex);
71+
72+
return Task.FromResult(array);
73+
}
5874
}
5975

6076
private IDurableOrderedSetGrain GetGrain(string key) => fixture.Cluster.Client.GetGrain<IDurableOrderedSetGrain>(key);
@@ -124,6 +140,54 @@ public async Task OrderedItems()
124140
Assert.Empty(await grain.GetOrderedItemsAsArray());
125141
}
126142

143+
[Fact]
144+
public async Task TryGetValue()
145+
{
146+
var grain = GetGrain("try-get-value");
147+
148+
var (foundEmpty, valueEmpty) = await grain.TryGetValue("anything");
149+
Assert.False(foundEmpty);
150+
Assert.Null(valueEmpty);
151+
152+
await grain.Add("one");
153+
await grain.Add("two");
154+
155+
var (foundExisting, valueExisting) = await grain.TryGetValue("one");
156+
Assert.True(foundExisting);
157+
Assert.Equal("one", valueExisting);
158+
159+
var (foundMissing, valueMissing) = await grain.TryGetValue("three");
160+
Assert.False(foundMissing);
161+
Assert.Null(valueMissing);
162+
}
163+
164+
[Fact]
165+
public async Task CopyTo()
166+
{
167+
var grain = GetGrain("copy-to");
168+
var items = new[] { "a", "b", "c" };
169+
foreach (var item in items)
170+
{
171+
await grain.Add(item);
172+
}
173+
174+
var destination1 = await grain.CopyToArray(3, 0);
175+
Assert.Equal(items, destination1);
176+
177+
var destination2 = await grain.CopyToArray(5, 0);
178+
Assert.Equal(new[] { "a", "b", "c", null, null }, destination2);
179+
180+
var destination3 = await grain.CopyToArray(5, 2);
181+
Assert.Equal(new[] { null, null, "a", "b", "c" }, destination3);
182+
183+
await Assert.ThrowsAsync<ArgumentException>(() => grain.CopyToArray(2, 0));
184+
await Assert.ThrowsAsync<ArgumentException>(() => grain.CopyToArray(4, 2));
185+
186+
await grain.Clear();
187+
var destination4 = await grain.CopyToArray(5, 0);
188+
Assert.Equal(new string[5], destination4);
189+
}
190+
127191
[Fact]
128192
public async Task Persistence()
129193
{

DurableStateMachines.Tests/DurableStackTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public interface IDurableStackGrain : IGrainWithStringKey
1515
Task<int> GetCount();
1616
Task Clear();
1717
Task<List<string>> GetAll();
18+
Task<bool> Contains(string value);
19+
Task<string[]> CopyToArray(int arraySize, int arrayIndex);
1820
}
1921

2022
public class DurableStackGrain([FromKeyedServices("stack")]
@@ -61,6 +63,16 @@ public async Task Clear()
6163
}
6264

6365
public Task<List<string>> GetAll() => Task.FromResult(state.ToList());
66+
67+
public Task<bool> Contains(string value) => Task.FromResult(state.Contains(value));
68+
69+
public Task<string[]> CopyToArray(int arraySize, int arrayIndex)
70+
{
71+
var array = new string[arraySize];
72+
state.CopyTo(array, arrayIndex);
73+
74+
return Task.FromResult(array);
75+
}
6476
}
6577

6678
private IDurableStackGrain GetGrain(string key) => fixture.Cluster.Client.GetGrain<IDurableStackGrain>(key);
@@ -117,6 +129,55 @@ public async Task BasicOperations()
117129
Assert.Null(emptyTryPop.Item);
118130
}
119131

132+
[Fact]
133+
public async Task Contains()
134+
{
135+
var grain = GetGrain("contains");
136+
137+
Assert.False(await grain.Contains("anything"));
138+
139+
await grain.Push("one");
140+
await grain.Push("two");
141+
await grain.Push("three");
142+
143+
Assert.True(await grain.Contains("one"));
144+
Assert.True(await grain.Contains("two"));
145+
Assert.True(await grain.Contains("three"));
146+
Assert.False(await grain.Contains("four"));
147+
148+
await grain.Pop();
149+
Assert.False(await grain.Contains("three"));
150+
Assert.True(await grain.Contains("two"));
151+
}
152+
153+
[Fact]
154+
public async Task CopyTo()
155+
{
156+
var grain = GetGrain("copy-to");
157+
158+
await grain.Push("c");
159+
await grain.Push("b");
160+
await grain.Push("a");
161+
162+
var expectedItems = new[] { "a", "b", "c" };
163+
164+
var destination1 = await grain.CopyToArray(3, 0);
165+
Assert.Equal(expectedItems, destination1);
166+
167+
var destination2 = await grain.CopyToArray(5, 0);
168+
Assert.Equal(new[] { "a", "b", "c", null, null }, destination2);
169+
170+
var destination3 = await grain.CopyToArray(5, 2);
171+
Assert.Equal(new[] { null, null, "a", "b", "c" }, destination3);
172+
173+
await Assert.ThrowsAsync<ArgumentException>(() => grain.CopyToArray(2, 0));
174+
await Assert.ThrowsAsync<ArgumentException>(() => grain.CopyToArray(4, 2));
175+
176+
await grain.Clear();
177+
var destination4 = await grain.CopyToArray(5, 0);
178+
Assert.Equal(new string[5], destination4);
179+
}
180+
120181
[Fact]
121182
public async Task Persistence()
122183
{

DurableStateMachines/DurableOrderedSet.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using Microsoft.Extensions.DependencyInjection;
2-
using Newtonsoft.Json.Linq;
32
using System.Buffers;
43
using System.Collections;
54
using System.Diagnostics;
5+
using System.Diagnostics.CodeAnalysis;
66
using System.Runtime.CompilerServices;
77
using System.Runtime.InteropServices;
88

@@ -41,6 +41,28 @@ public interface IDurableOrderedSet<T> : IEnumerable<T>, IReadOnlyCollection<T>
4141
/// <returns><c>true</c> if the element was successfully found and removed; otherwise, <c>false</c>.</returns>
4242
bool Remove(T item);
4343

44+
/// <summary>
45+
/// Searches the set for a given value and returns the equal value it finds, if any.
46+
/// </summary>
47+
/// <param name="equalValue">The value to search for.</param>
48+
/// <param name="actualValue">The value from the set that the search found, or the default value of <typeparamref name="T"/> when the search yielded no match.</param>
49+
/// <returns>A value indicating whether the search was successful.</returns>
50+
/// <remarks>
51+
/// This can be useful when you want to reuse a previously stored reference instead of
52+
/// a newly constructed one (so that more sharing of references can occur) or to look up
53+
/// a value that has more complete data than the value you currently have, although their
54+
/// comparer functions indicate they are equal.
55+
/// </remarks>
56+
bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue);
57+
58+
/// <summary>
59+
/// Copies the set to an existing array, starting at the specified array index.
60+
/// The elements copied preserve their original insertion order.
61+
/// </summary>
62+
/// <param name="array">The destination array.</param>
63+
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
64+
void CopyTo(T[] array, int arrayIndex);
65+
4466
/// <summary>
4567
/// Removes all elements from the set.
4668
/// </summary>
@@ -88,6 +110,10 @@ public int Count
88110
public ReadOnlySpan<T> OrderedItems => CollectionsMarshal.AsSpan(_list);
89111

90112
public bool Contains(T item) => _set.Contains(item);
113+
public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue) => _set.TryGetValue(equalValue, out actualValue);
114+
115+
// We use the list's CopyTo in order to preserve the order when the elements are copied to the destination array.
116+
public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
91117

92118
public bool Add(T item)
93119
{

DurableStateMachines/DurableStack.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ public interface IDurableStack<T> : IEnumerable<T>, IReadOnlyCollection<T>
2626
bool Contains(T item);
2727

2828
/// <summary>
29-
/// Copies the stack to an existing one-dimensional array, starting at the specified array index.
29+
/// Copies the stack to an existing array, starting at the specified array index.
3030
/// The elements are copied from top to bottom.
3131
/// </summary>
32-
/// <param name="array">The destination one-dimensional array.</param>
32+
/// <param name="array">The destination array.</param>
3333
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
3434
void CopyTo(T[] array, int arrayIndex);
3535

0 commit comments

Comments
 (0)