This is an automated email from the ASF dual-hosted git repository.

pjfanning pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git


The following commit(s) were added to refs/heads/main by this push:
     new 7965d95b0d Make ByteString.copyToBuffer(buffer, offset) public, add 
scaladoc and test coverage (#2946)
7965d95b0d is described below

commit 7965d95b0d45e3559372a91a65f2ded17f250289
Author: PJ Fanning <[email protected]>
AuthorDate: Fri May 8 17:11:12 2026 +0100

    Make ByteString.copyToBuffer(buffer, offset) public, add scaladoc and test 
coverage (#2946)
    
    Agent-Logs-Url: 
https://github.com/pjfanning/incubator-pekko/sessions/09848a76-7cf9-49ad-b3a6-e466857fa140
    
    Co-authored-by: copilot-swe-agent[bot] 
<[email protected]>
    Co-authored-by: pjfanning <[email protected]>
---
 .../org/apache/pekko/util/ByteStringSpec.scala     | 61 ++++++++++++++++++++++
 .../scala/org/apache/pekko/util/ByteString.scala   | 21 +++++---
 2 files changed, 74 insertions(+), 8 deletions(-)

diff --git 
a/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala 
b/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala
index f4075ec5a5..c596dcad6e 100644
--- a/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala
+++ b/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala
@@ -2604,6 +2604,67 @@ class ByteStringSpec extends AnyWordSpec with Matchers 
with Checkers {
         ByteString.empty.copyToBuffer(ByteBuffer.allocate(10)) should ===(0)
       }
 
+      "copyToBuffer(buffer, offset) copies from the given offset for different 
ByteString types" in {
+        import java.nio.ByteBuffer
+
+        // ByteString1C — copy from offset 2
+        val bs1c = ByteString1C(Array[Byte](1, 2, 3, 4, 5))
+        val buf1 = ByteBuffer.allocate(5)
+        bs1c.copyToBuffer(buf1, 2) should ===(3)
+        buf1.flip()
+        val result1 = new Array[Byte](3)
+        buf1.get(result1)
+        result1.toSeq should ===(Seq[Byte](3, 4, 5))
+
+        // ByteString1C — offset beyond length copies nothing
+        val buf2 = ByteBuffer.allocate(5)
+        bs1c.copyToBuffer(buf2, 10) should ===(0)
+
+        // ByteString1C — offset 0 copies all
+        val buf3 = ByteBuffer.allocate(5)
+        bs1c.copyToBuffer(buf3, 0) should ===(5)
+
+        // ByteString1 — copy from offset 1 (internal startIndex + user offset)
+        val bs1 = ByteString1(Array[Byte](0, 10, 20, 30, 40, 50), 1, 4) // 
logical bytes [10, 20, 30, 40]
+        val buf4 = ByteBuffer.allocate(4)
+        bs1.copyToBuffer(buf4, 1) should ===(3)
+        buf4.flip()
+        val result4 = new Array[Byte](3)
+        buf4.get(result4)
+        result4.toSeq should ===(Seq[Byte](20, 30, 40))
+
+        // ByteString1 — offset 0 copies all logical bytes
+        val buf5 = ByteBuffer.allocate(4)
+        bs1.copyToBuffer(buf5, 0) should ===(4)
+        buf5.flip()
+        buf5.get() should ===(10.toByte)
+
+        // ByteStrings — copy from offset that skips first segment entirely
+        val bss = ByteStrings(ByteString1.fromString("abc"), 
ByteString1.fromString("def"))
+        val buf6 = ByteBuffer.allocate(10)
+        bss.copyToBuffer(buf6, 3) should ===(3)
+        buf6.flip()
+        val result6 = new Array[Byte](3)
+        buf6.get(result6)
+        result6.toSeq should ===(Seq[Byte]('d', 'e', 'f'))
+
+        // ByteStrings — copy from offset mid-first-segment
+        val buf7 = ByteBuffer.allocate(10)
+        bss.copyToBuffer(buf7, 1) should ===(5)
+        buf7.flip()
+        val result7 = new Array[Byte](5)
+        buf7.get(result7)
+        result7.toSeq should ===(Seq[Byte]('b', 'c', 'd', 'e', 'f'))
+
+        // ByteStrings — offset 0 copies all
+        val buf8 = ByteBuffer.allocate(6)
+        bss.copyToBuffer(buf8, 0) should ===(6)
+
+        // ByteString.empty — any offset copies nothing
+        ByteString.empty.copyToBuffer(ByteBuffer.allocate(10), 0) should ===(0)
+        ByteString.empty.copyToBuffer(ByteBuffer.allocate(10), 5) should ===(0)
+      }
+
       "copying chunks to an array" in {
         val iterator = (ByteString("123") ++ ByteString("456")).iterator
         val array = Array.ofDim[Byte](6)
diff --git a/actor/src/main/scala/org/apache/pekko/util/ByteString.scala 
b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
index 42aa48d941..0d4984a2fa 100644
--- a/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
+++ b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
@@ -433,8 +433,7 @@ object ByteString {
     override def copyToBuffer(buffer: ByteBuffer): Int =
       writeToBuffer(buffer, offset = 0)
 
-    /** INTERNAL API: Specialized for internal use, copying from an offset 
without slicing. */
-    private[pekko] override def copyToBuffer(buffer: ByteBuffer, offset: Int): 
Int =
+    override def copyToBuffer(buffer: ByteBuffer, offset: Int): Int =
       writeToBuffer(buffer, offset)
 
     /** INTERNAL API: Specialized for internal use, writing multiple 
ByteString1C into the same ByteBuffer. */
@@ -576,8 +575,7 @@ object ByteString {
     override def copyToBuffer(buffer: ByteBuffer): Int =
       writeToBuffer(buffer, offset = 0)
 
-    /** INTERNAL API: Specialized for internal use, copying from an offset 
without slicing. */
-    private[pekko] override def copyToBuffer(buffer: ByteBuffer, offset: Int): 
Int =
+    override def copyToBuffer(buffer: ByteBuffer, offset: Int): Int =
       writeToBuffer(buffer, offset)
 
     /** INTERNAL API: Specialized for internal use, writing multiple 
ByteString1C into the same ByteBuffer. */
@@ -993,8 +991,7 @@ object ByteString {
     override def copyToBuffer(buffer: ByteBuffer): Int =
       copyToBuffer(buffer, offset = 0)
 
-    /** INTERNAL API: Specialized for internal use, copying from an offset 
without slicing. */
-    private[pekko] override def copyToBuffer(buffer: ByteBuffer, offset: Int): 
Int = {
+    override def copyToBuffer(buffer: ByteBuffer, offset: Int): Int = {
       var remainingOffset = offset
       var written = 0
       var i = 0
@@ -1899,8 +1896,16 @@ sealed abstract class ByteString
    */
   def copyToBuffer(@nowarn("msg=never used") buffer: ByteBuffer): Int
 
-  /** INTERNAL API: Copy bytes to a ByteBuffer from a ByteString offset 
without allocating a slice. */
-  private[pekko] def copyToBuffer(buffer: ByteBuffer, offset: Int): Int =
+  /**
+   * Copy as many bytes as possible to a ByteBuffer, starting from a given 
offset within this ByteString
+   * and the buffer's current position. This method will not overflow the 
buffer.
+   *
+   * @param buffer a ByteBuffer to copy bytes to
+   * @param offset the offset within this ByteString to start copying from
+   * @return the number of bytes actually copied
+   * @since 2.0.0
+   */
+  def copyToBuffer(buffer: ByteBuffer, offset: Int): Int =
     if (offset <= 0) copyToBuffer(buffer)
     else drop(offset).copyToBuffer(buffer)
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to