diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Core.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Core.verified.txt index 74f1fb4220f..ad78c48cd97 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Core.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Core.verified.txt @@ -3305,8 +3305,16 @@ namespace Akka.IO public static Akka.IO.ByteString CopyFrom(byte[] array) { } public static Akka.IO.ByteString CopyFrom(System.ArraySegment buffer) { } public static Akka.IO.ByteString CopyFrom(byte[] array, int offset, int count) { } + public static Akka.IO.ByteString CopyFrom(System.Memory memory) { } + public static Akka.IO.ByteString CopyFrom(System.Memory memory, int offset, int count) { } + public static Akka.IO.ByteString CopyFrom(System.Span span) { } + public static Akka.IO.ByteString CopyFrom(System.Span span, int offset, int count) { } public static Akka.IO.ByteString CopyFrom(System.Collections.Generic.IEnumerable> buffers) { } public int CopyTo(byte[] buffer, int index, int count) { } + public int CopyTo(ref System.Memory buffer) { } + public int CopyTo(ref System.Memory buffer, int index, int count) { } + public int CopyTo(ref System.Span buffer) { } + public int CopyTo(ref System.Span buffer, int index, int count) { } public override bool Equals(object obj) { } public bool Equals(Akka.IO.ByteString other) { } public static Akka.IO.ByteString FromBytes(byte[] array) { } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt index 312e7e27bf7..3a08021452e 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt @@ -3312,8 +3312,16 @@ namespace Akka.IO public static Akka.IO.ByteString CopyFrom(byte[] array) { } public static Akka.IO.ByteString CopyFrom(System.ArraySegment buffer) { } public static Akka.IO.ByteString CopyFrom(byte[] array, int offset, int count) { } + public static Akka.IO.ByteString CopyFrom(System.Memory memory) { } + public static Akka.IO.ByteString CopyFrom(System.Memory memory, int offset, int count) { } + public static Akka.IO.ByteString CopyFrom(System.Span span) { } + public static Akka.IO.ByteString CopyFrom(System.Span span, int offset, int count) { } public static Akka.IO.ByteString CopyFrom(System.Collections.Generic.IEnumerable> buffers) { } public int CopyTo(byte[] buffer, int index, int count) { } + public int CopyTo(ref System.Memory buffer) { } + public int CopyTo(ref System.Memory buffer, int index, int count) { } + public int CopyTo(ref System.Span buffer) { } + public int CopyTo(ref System.Span buffer, int index, int count) { } public override bool Equals(object obj) { } public bool Equals(Akka.IO.ByteString other) { } public static Akka.IO.ByteString FromBytes(byte[] array) { } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt index 74f1fb4220f..ad78c48cd97 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt @@ -3305,8 +3305,16 @@ namespace Akka.IO public static Akka.IO.ByteString CopyFrom(byte[] array) { } public static Akka.IO.ByteString CopyFrom(System.ArraySegment buffer) { } public static Akka.IO.ByteString CopyFrom(byte[] array, int offset, int count) { } + public static Akka.IO.ByteString CopyFrom(System.Memory memory) { } + public static Akka.IO.ByteString CopyFrom(System.Memory memory, int offset, int count) { } + public static Akka.IO.ByteString CopyFrom(System.Span span) { } + public static Akka.IO.ByteString CopyFrom(System.Span span, int offset, int count) { } public static Akka.IO.ByteString CopyFrom(System.Collections.Generic.IEnumerable> buffers) { } public int CopyTo(byte[] buffer, int index, int count) { } + public int CopyTo(ref System.Memory buffer) { } + public int CopyTo(ref System.Memory buffer, int index, int count) { } + public int CopyTo(ref System.Span buffer) { } + public int CopyTo(ref System.Span buffer, int index, int count) { } public override bool Equals(object obj) { } public bool Equals(Akka.IO.ByteString other) { } public static Akka.IO.ByteString FromBytes(byte[] array) { } diff --git a/src/core/Akka.Tests/Util/ByteStringSpec.cs b/src/core/Akka.Tests/Util/ByteStringSpec.cs index d470b8c538e..37fe0543385 100644 --- a/src/core/Akka.Tests/Util/ByteStringSpec.cs +++ b/src/core/Akka.Tests/Util/ByteStringSpec.cs @@ -5,7 +5,6 @@ // //----------------------------------------------------------------------- -using System; using System.Linq; using System.Text; using Akka.IO; @@ -188,5 +187,27 @@ public void A_sliced_ByteString_must_return_correct_string_for_ToString() Assert.Equal(expectedLeft, actualLeft); Assert.Equal(expectedRight, actualRight); } + +#if !NETFRAMEWORK + [Fact(DisplayName = "A sliced byte string using Range must return the correct string for ToString")] + public void A_sliced_ByteString_using_Range_must_return_correct_string_for_ToString() + { + const string expected = "ABCDEF"; + Encoding encoding = Encoding.ASCII; + + int halfExpected = expected.Length / 2; + + string expectedLeft = expected.Substring(startIndex: 0, length: halfExpected); + string expectedRight = expected.Substring(startIndex: halfExpected, length: halfExpected); + + ByteString data = ByteString.FromString(expected, encoding); + + string actualLeft = data[..halfExpected].ToString(encoding); + string actualRight = data[halfExpected..].ToString(encoding); + + Assert.Equal(expectedLeft, actualLeft); + Assert.Equal(expectedRight, actualRight); + } +#endif } } diff --git a/src/core/Akka/Util/ByteString.cs b/src/core/Akka/Util/ByteString.cs index bc7c8933cf5..50aee01ceb1 100644 --- a/src/core/Akka/Util/ByteString.cs +++ b/src/core/Akka/Util/ByteString.cs @@ -76,6 +76,62 @@ public static ByteString CopyFrom(byte[] array, int offset, int count) return new ByteString(copy, 0, copy.Length); } + /// + /// Creates a new by copying a . + /// + /// The to copy + /// The new + public static ByteString CopyFrom(Memory memory) + => CopyFrom(memory, 0, memory.Length); + + /// + /// Creates a new by copying a . + /// + /// The to copy + /// Index in provided , at which copy should start. + /// Number of bytes to copy. + /// The new + public static ByteString CopyFrom(Memory memory, int offset, int count) + { + if (count == 0) return Empty; + + if (offset < 0 || offset >= memory.Length) throw new ArgumentOutOfRangeException(nameof(offset), $"Provided offset of [{offset}] is outside bounds of an array [{memory.Length}]"); + if (count > memory.Length - offset) throw new ArgumentException($"Provided length [{count}] of array to copy doesn't fit array length [{memory.Length}] within given offset [{offset}]", nameof(count)); + + var copy = new byte[count]; + memory.Slice(offset, count).CopyTo(copy); + + return new ByteString(copy, 0, copy.Length); + } + + /// + /// Creates a new by copying a . + /// + /// The to copy + /// The new + public static ByteString CopyFrom(Span span) + => CopyFrom(span, 0, span.Length); + + /// + /// Creates a new by copying a . + /// + /// The to copy + /// Index in provided , at which copy should start. + /// Number of bytes to copy. + /// The new + public static ByteString CopyFrom(Span span, int offset, int count) + { + if (count == 0) return Empty; + + if (offset < 0 || offset >= span.Length) throw new ArgumentOutOfRangeException(nameof(offset), $"Provided offset of [{offset}] is outside bounds of an array [{span.Length}]"); + if (count > span.Length - offset) throw new ArgumentException($"Provided length [{count}] of array to copy doesn't fit array length [{span.Length}] within given offset [{offset}]", nameof(count)); + + var copy = new byte[count]; + span.Slice(offset, count).CopyTo(copy); + + return new ByteString(copy, 0, copy.Length); + } + /// /// Creates a new by copying segments of bytes. /// @@ -502,6 +558,82 @@ public int CopyTo(byte[] buffer, int index, int count) return 0; } + /// + /// Copies content of a current into a provided + /// + /// + /// The number of bytes copied + public int CopyTo(ref Memory buffer) + => CopyTo(ref buffer, 0, buffer.Length); + + /// + /// Copies content of a current into a provided + /// starting from in that + /// buffer and copying a number of bytes. + /// + /// The number of bytes copied + public int CopyTo(ref Memory buffer, int index, int count) + { + if (index < 0 || index >= buffer.Length) throw new ArgumentOutOfRangeException(nameof(index), "Provided index is outside the bounds of the buffer to copy to."); + if (count > buffer.Length - index) throw new ArgumentException("Provided number of bytes to copy won't fit into provided buffer", nameof(count)); + + count = Math.Min(count, _count); + var remaining = count; + var position = index; + foreach (var b in _buffers) + { + var toCopy = Math.Min(b.Count, remaining); + + var bufferSpan = buffer.Span.Slice(position, toCopy); + b.AsSpan().CopyTo(bufferSpan); + + position += toCopy; + remaining -= toCopy; + + if (remaining == 0) return count; + } + + return 0; + } + + /// + /// Copies content of a current into a provided + /// . + /// + /// The number of bytes copied + public int CopyTo(ref Span buffer) + => CopyTo(ref buffer, 0, buffer.Length); + + /// + /// Copies content of a current into a provided + /// starting from in that + /// buffer and copying a number of bytes. + /// + /// The number of bytes copied + public int CopyTo(ref Span buffer, int index, int count) + { + if (index < 0 || index >= buffer.Length) throw new ArgumentOutOfRangeException(nameof(index), "Provided index is outside the bounds of the buffer to copy to."); + if (count > buffer.Length - index) throw new ArgumentException("Provided number of bytes to copy won't fit into provided buffer", nameof(count)); + + count = Math.Min(count, _count); + var remaining = count; + var position = index; + foreach (var b in _buffers) + { + var toCopy = Math.Min(b.Count, remaining); + + var bufferSpan = buffer.Slice(position, toCopy); + b.AsSpan().CopyTo(bufferSpan); + + position += toCopy; + remaining -= toCopy; + + if (remaining == 0) return count; + } + + return 0; + } + /// /// Copies content of the current to a provided /// writeable .