Skip to content

Commit 78ba6bf

Browse files
committed
Release 5.17.2
1 parent 703ce02 commit 78ba6bf

File tree

125 files changed

+782
-540
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+782
-540
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
11
Release Notes
22
====
33

4+
# 01-03-2025
5+
<a href="https://www.nuget.org/packages/dotnext/5.17.2">DotNext 5.17.2</a>
6+
* Improved AOT compatibility
7+
* Fixed nullability attributes
8+
9+
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.17.2">DotNext.Metaprogramming 5.17.2</a>
10+
* Fixed nullability attributes
11+
12+
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.17.2">DotNext.Unsafe 5.17.2</a>
13+
* Fixed nullability attributes
14+
15+
<a href="https://www.nuget.org/packages/dotnext.threading/5.17.2">DotNext.Threading 5.17.2</a>
16+
* Fixed nullability attributes
17+
18+
<a href="https://www.nuget.org/packages/dotnext.io/5.17.2">DotNext.IO 5.17.2</a>
19+
* Fixed nullability attributes
20+
21+
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.17.2">DotNext.Net.Cluster 5.17.2</a>
22+
* Fixed nullability attributes
23+
24+
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.17.2">DotNext.AspNetCore.Cluster 5.17.2</a>
25+
* Fixed nullability attributes
26+
427
# 12-30-2024
528
<a href="https://www.nuget.org/packages/dotnext.io/5.17.1">DotNext.IO 5.17.1</a>
629
* Fixed `EndOfStreamException` caused by async read from `PoolingBufferedStream`

README.md

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -44,42 +44,29 @@ All these things are implemented in 100% managed code on top of existing .NET AP
4444
* [NuGet Packages](https://www.nuget.org/profiles/rvsakno)
4545

4646
# What's new
47-
Release Date: 12-29-2024
48-
49-
This release is aimed to improve AOT compatibility. All the examples in the repo are now AOT compatible.
50-
<a href="https://www.nuget.org/packages/dotnext/5.17.0">DotNext 5.17.0</a>
51-
* Fixed AOT compatibility in `TaskType` class
52-
* Added [ISpanFormattable](https://learn.microsoft.com/en-us/dotnet/api/system.ispanformattable) and [IParsable&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.iparsable-1) interfaces to `HttpEndPoint`
53-
* Introduced `TryEncodeAsUtf8` extension method for `SpanWriter<T>`
54-
* Added more factory methods to `DotNext.Buffers.Memory` class to create [ReadOnlySequence&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.readonlysequence-1)
55-
* `Intrinsics.KeepAlive` is introduced for value types
56-
* Added `Synchronization.Wait()` synchronous methods for blocking wait of [value tasks](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask) without wait handles
57-
58-
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.17.0">DotNext.Metaprogramming 5.17.0</a>
59-
* Updated dependencies
60-
61-
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.17.0">DotNext.Unsafe 5.17.0</a>
62-
* Improved AOT support
63-
* Fixed finalizer for unmanaged memory manager that allows to release the allocated unmanaged memory automatically by GC to avoid memory leak
64-
* Updated dependencies
65-
66-
<a href="https://www.nuget.org/packages/dotnext.threading/5.17.0">DotNext.Threading 5.17.0</a>
67-
* Improved AOT support
68-
69-
<a href="https://www.nuget.org/packages/dotnext.io/5.17.1">DotNext.IO 5.17.1</a>
70-
* Reduced memory consumption for applications that use `FileReader` and `FileWriter` classes. These classes are now implemented by using lazy buffer pattern. It means that the different instances can reuse the same buffer taken from the pool
71-
* Fixed [255](https://github.com/dotnet/dotNext/issues/255)
72-
* `PoolingBufferedStream` is introduced to replace classic [BufferedStream](https://learn.microsoft.com/en-us/dotnet/api/system.io.bufferedstream). This class supports memory pooling and implements lazy buffer pattern
73-
74-
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.17.0">DotNext.Net.Cluster 5.17.0</a>
75-
* Improved AOT support
76-
77-
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.17.0">DotNext.AspNetCore.Cluster 5.17.0</a>
78-
* Improved AOT support
79-
* Fixed [254](https://github.com/dotnet/dotNext/issues/254)
80-
81-
<a href="https://www.nuget.org/packages/dotnext.maintenanceservices/0.5.0">DotNext.MaintenanceServices 0.5.0</a>
82-
* Improved AOT support
47+
Release Date: 01-03-2025
48+
49+
<a href="https://www.nuget.org/packages/dotnext/5.17.2">DotNext 5.17.2</a>
50+
* Improved AOT compatibility
51+
* Fixed nullability attributes
52+
53+
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.17.2">DotNext.Metaprogramming 5.17.2</a>
54+
* Fixed nullability attributes
55+
56+
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.17.2">DotNext.Unsafe 5.17.2</a>
57+
* Fixed nullability attributes
58+
59+
<a href="https://www.nuget.org/packages/dotnext.threading/5.17.2">DotNext.Threading 5.17.2</a>
60+
* Fixed nullability attributes
61+
62+
<a href="https://www.nuget.org/packages/dotnext.io/5.17.2">DotNext.IO 5.17.2</a>
63+
* Fixed nullability attributes
64+
65+
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.17.2">DotNext.Net.Cluster 5.17.2</a>
66+
* Fixed nullability attributes
67+
68+
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.17.2">DotNext.AspNetCore.Cluster 5.17.2</a>
69+
* Fixed nullability attributes
8370

8471
Changelog for previous versions located [here](./CHANGELOG.md).
8572

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
namespace DotNext.Runtime;
2+
3+
[TestClass]
4+
public class BoxedValueTests
5+
{
6+
[TestMethod]
7+
public void BoxUnbox()
8+
{
9+
var obj = (BoxedValue<int>)42;
10+
Assert.AreEqual(42.GetHashCode(), obj.GetHashCode());
11+
Assert.AreEqual(42, obj.Unbox());
12+
Assert.AreEqual(42, obj);
13+
Assert.AreEqual(typeof(int), obj.GetType());
14+
}
15+
16+
[TestMethod]
17+
public void Unwrap()
18+
{
19+
object? obj = null;
20+
Assert.IsNull(BoxedValue<int>.GetTypedReference(obj));
21+
22+
obj = 42;
23+
Assert.AreEqual(42, BoxedValue<int>.GetTypedReference(obj));
24+
25+
obj = string.Empty;
26+
Assert.ThrowsException<ArgumentException>(() => BoxedValue<int>.GetTypedReference(obj));
27+
}
28+
29+
[TestMethod]
30+
public void ToUntypedReference()
31+
{
32+
ValueType obj = BoxedValue<int>.Box(42);
33+
Assert.AreEqual(42, obj);
34+
}
35+
36+
private struct MutableStruct
37+
{
38+
public int Value;
39+
}
40+
41+
[TestMethod]
42+
public void BitwiseCopyImmutable()
43+
{
44+
var boxed1 = (BoxedValue<int>)42;
45+
var boxed2 = boxed1.Copy();
46+
Assert.AreNotSame(boxed1, boxed2);
47+
Assert.AreEqual(42, boxed1);
48+
Assert.AreEqual(42, boxed2);
49+
}
50+
51+
[TestMethod]
52+
public void BitwiseCopyMutable()
53+
{
54+
var boxed1 = (BoxedValue<MutableStruct>)new MutableStruct();
55+
var boxed2 = boxed1.Copy();
56+
Assert.AreNotSame(boxed1, boxed2);
57+
58+
boxed1.Unbox().Value = 42;
59+
boxed2.Unbox().Value = 43;
60+
61+
Assert.AreNotEqual(boxed1.Unbox().Value, boxed2.Unbox().Value);
62+
}
63+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
using System.Runtime.CompilerServices;
2+
using System.Runtime.InteropServices;
3+
4+
namespace DotNext.Runtime;
5+
6+
[TestClass]
7+
public class ValueReferenceTests
8+
{
9+
[TestMethod]
10+
public void MutableFieldRef()
11+
{
12+
var obj = new MyClass { AnotherField = string.Empty };
13+
var reference = new ValueReference<int>(obj, ref obj.Field);
14+
15+
obj.Field = 20;
16+
Assert.AreEqual(obj.Field, reference.Value);
17+
18+
reference.Value = 42;
19+
Assert.AreEqual(obj.Field, reference.Value);
20+
Assert.IsTrue(string.IsNullOrEmpty(obj.AnotherField));
21+
}
22+
23+
[TestMethod]
24+
public void ImmutableFieldRef()
25+
{
26+
var obj = new MyClass { AnotherField = string.Empty };
27+
var reference = new ReadOnlyValueReference<int>(obj, in obj.Field);
28+
29+
obj.Field = 20;
30+
Assert.AreEqual(obj.Field, reference.Value);
31+
32+
Assert.AreEqual(obj.Field, reference.Value);
33+
Assert.IsTrue(string.IsNullOrEmpty(obj.AnotherField));
34+
}
35+
36+
[TestMethod]
37+
public void MutableToImmutableRef()
38+
{
39+
var obj = new MyClass { AnotherField = string.Empty };
40+
var reference = new ValueReference<int>(obj, ref obj.Field);
41+
ReadOnlyValueReference<int> roReference = reference;
42+
43+
obj.Field = 20;
44+
Assert.AreEqual(roReference.Value, reference.Value);
45+
46+
reference.Value = 42;
47+
Assert.AreEqual(roReference.Value, reference.Value);
48+
}
49+
50+
[TestMethod]
51+
public void MutableRefEquality()
52+
{
53+
var obj = new MyClass { AnotherField = string.Empty };
54+
var reference1 = new ValueReference<int>(obj, ref obj.Field);
55+
var reference2 = new ValueReference<int>(obj, ref obj.Field);
56+
57+
Assert.AreEqual(reference1, reference2);
58+
}
59+
60+
[TestMethod]
61+
public void ImmutableRefEquality()
62+
{
63+
var obj = new MyClass { AnotherField = string.Empty };
64+
var reference1 = new ReadOnlyValueReference<int>(obj, in obj.Field);
65+
var reference2 = new ReadOnlyValueReference<int>(obj, in obj.Field);
66+
67+
Assert.AreEqual(reference1, reference2);
68+
}
69+
70+
[TestMethod]
71+
public void ReferenceToArray()
72+
{
73+
var array = new string[1];
74+
var reference = new ValueReference<string>(array, 0)
75+
{
76+
Value = "Hello, world!"
77+
};
78+
79+
Assert.AreSame(array[0], reference.Value);
80+
Assert.AreSame(array[0], reference.ToString());
81+
}
82+
83+
[TestMethod]
84+
public void MutableEmptyRef()
85+
{
86+
var reference = default(ValueReference<string>);
87+
Assert.IsTrue(reference.IsEmpty);
88+
Assert.IsNull(reference.ToString());
89+
90+
Span<string> span = reference;
91+
Assert.IsTrue(span.IsEmpty);
92+
93+
Assert.ThrowsException<NullReferenceException>((Func<string>)reference);
94+
Assert.ThrowsException<NullReferenceException>(((Action<string>)reference).Bind(string.Empty));
95+
}
96+
97+
[TestMethod]
98+
public void ImmutableEmptyRef()
99+
{
100+
var reference = default(ReadOnlyValueReference<string>);
101+
Assert.IsTrue(reference.IsEmpty);
102+
Assert.IsNull(reference.ToString());
103+
104+
ReadOnlySpan<string> span = reference;
105+
Assert.IsTrue(span.IsEmpty);
106+
107+
Assert.ThrowsException<NullReferenceException>((Func<string>)reference);
108+
}
109+
110+
[TestMethod]
111+
public void AnonymousValue()
112+
{
113+
var reference = new ValueReference<int>(42);
114+
Assert.AreEqual(42, reference.Value);
115+
116+
((Action<int>)reference).Invoke(52);
117+
Assert.AreEqual(52, ToFunc<ValueReference<int>, int>(reference).Invoke());
118+
119+
ReadOnlyValueReference<int> roRef = reference;
120+
Assert.AreEqual(52, roRef.Value);
121+
Assert.AreEqual(52, ToFunc<ReadOnlyValueReference<int>, int>(reference).Invoke());
122+
}
123+
124+
private static Func<T> ToFunc<TSupplier, T>(TSupplier supplier)
125+
where TSupplier : ISupplier<T>
126+
=> supplier.ToDelegate();
127+
128+
[TestMethod]
129+
public void IncorrectReference()
130+
{
131+
byte[] empty = [];
132+
Assert.ThrowsException<ArgumentOutOfRangeException>(() => new ValueReference<byte>(empty, ref MemoryMarshal.GetArrayDataReference(empty)));
133+
Assert.ThrowsException<ArgumentOutOfRangeException>(() => new ReadOnlyValueReference<byte>(empty, ref MemoryMarshal.GetArrayDataReference(empty)));
134+
}
135+
136+
[TestMethod]
137+
public void ReferenceSize()
138+
{
139+
Assert.AreEqual(Unsafe.SizeOf<ValueReference<float>>(), nint.Size + nint.Size);
140+
}
141+
142+
[TestMethod]
143+
public void BoxedValueInterop()
144+
{
145+
var boxedInt = BoxedValue<int>.Box(42);
146+
ValueReference<int> reference = boxedInt;
147+
148+
boxedInt.Unbox() = 56;
149+
Assert.AreEqual(boxedInt, reference.Value);
150+
}
151+
152+
[TestMethod]
153+
public void ArrayCovariance()
154+
{
155+
string[] array = ["a", "b"];
156+
Assert.ThrowsException<ArrayTypeMismatchException>(() => new ValueReference<object>(array, 0));
157+
158+
var roRef = new ReadOnlyValueReference<object>(array, 1);
159+
Assert.AreEqual("b", roRef.Value);
160+
}
161+
162+
[TestMethod]
163+
public void SpanInterop()
164+
{
165+
var reference = new ValueReference<int>(42);
166+
Span<int> span = reference;
167+
Assert.AreEqual(1, span.Length);
168+
169+
Assert.IsTrue(Unsafe.AreSame(in reference.Value, in span[0]));
170+
}
171+
172+
[TestMethod]
173+
public void ReadOnlySpanInterop()
174+
{
175+
ReadOnlyValueReference<int> reference = new ValueReference<int>(42);
176+
ReadOnlySpan<int> span = reference;
177+
Assert.AreEqual(1, span.Length);
178+
179+
Assert.IsTrue(Unsafe.AreSame(in reference.Value, in span[0]));
180+
}
181+
182+
private record MyClass
183+
{
184+
internal int Field;
185+
internal string? AnotherField;
186+
}
187+
}

src/DotNext.Benchmarks/Net/Cluster/Consensus/Raft/PersistentStateBenchmark.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public async ValueTask<long> ReadAsync<TEntryImpl, TList>(TList entries, long? s
4545
where TList : notnull, IReadOnlyList<TEntryImpl>
4646
{
4747
var result = 0L;
48-
foreach (var entry in entries)
48+
for (var i = 0; i < entries.Count; i++)
4949
{
50-
using var buffer = await entry.ToMemoryAsync();
50+
using var buffer = await entries[i].ToMemoryAsync(token: token);
5151
result += buffer.Length;
5252
}
5353

src/DotNext.IO/Buffers/BufferWriter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public static int Write(this ref BufferWriterSlim<byte> writer, scoped ReadOnlyS
196196
}
197197

198198
private static bool TryFormat<T>(IBufferWriter<byte> writer, T value, Span<char> buffer, in EncodingContext context, LengthFormat? lengthFormat, ReadOnlySpan<char> format, IFormatProvider? provider, out long bytesWritten)
199-
where T : notnull, ISpanFormattable
199+
where T : ISpanFormattable
200200
{
201201
if (!value.TryFormat(buffer, out var charsWritten, format, provider))
202202
{
@@ -228,7 +228,7 @@ private static bool TryFormat<T>(IBufferWriter<byte> writer, T value, Span<char>
228228
/// <returns>The number of written bytes.</returns>
229229
[SkipLocalsInit]
230230
public static long Format<T>(this IBufferWriter<byte> writer, T value, in EncodingContext context, LengthFormat? lengthFormat, ReadOnlySpan<char> format = default, IFormatProvider? provider = null, MemoryAllocator<char>? allocator = null)
231-
where T : notnull, ISpanFormattable
231+
where T : ISpanFormattable
232232
{
233233
// attempt to allocate char buffer on the stack
234234
Span<char> charBuffer = stackalloc char[SpanOwner<char>.StackallocThreshold];
@@ -259,7 +259,7 @@ public static long Format<T>(this IBufferWriter<byte> writer, T value, in Encodi
259259
/// <returns>The number of written bytes.</returns>
260260
/// <exception cref="InsufficientMemoryException"><paramref name="writer"/> has not enough free space to place UTF-8 bytes.</exception>
261261
public static int Format<T>(this IBufferWriter<byte> writer, T value, LengthFormat? lengthFormat, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
262-
where T : notnull, IUtf8SpanFormattable
262+
where T : IUtf8SpanFormattable
263263
{
264264
var expectedLengthSize = lengthFormat switch
265265
{

0 commit comments

Comments
 (0)