Skip to content

Commit

Permalink
return most specific collection type (#3855)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamgfraser committed Jun 29, 2020
1 parent 7ea7a87 commit 069d7b8
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 25 deletions.
8 changes: 8 additions & 0 deletions core-tests/shared/src/test/scala/zio/ChunkSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ object ChunkSpec extends ZIOBaseSpec {
val expected = (as ++ bs).length
assert(actual)(equalTo(expected))
}
},
zio.test.test("returns most specific type") {
val seq = (zio.Chunk("foo"): Seq[String]) :+ "post1"
assert(seq)(isSubtype[Chunk[String]](equalTo(Chunk("foo", "post1"))))
}
),
suite("prepend")(
Expand Down Expand Up @@ -149,6 +153,10 @@ object ChunkSpec extends ZIOBaseSpec {
val expected = (as ++ bs).length
assert(actual)(equalTo(expected))
}
},
zio.test.test("returns most specific type") {
val seq = "pre1" +: (zio.Chunk("foo"): Seq[String])
assert(seq)(isSubtype[Chunk[String]](equalTo(Chunk("pre1", "foo"))))
}
),
testM("apply") {
Expand Down
24 changes: 24 additions & 0 deletions core/shared/src/main/scala-2.11-2.12/ChunkFactory.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2017-2020 John A. De Goes and the ZIO Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package zio

import scala.collection.generic.IndexedSeqFactory

private[zio] trait ChunkFactory extends IndexedSeqFactory[Chunk] {
def newBuilder[A]: ChunkBuilder[A] =
ChunkBuilder.make()
}
48 changes: 26 additions & 22 deletions core/shared/src/main/scala-2.11-2.12/ChunkLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package zio

import scala.collection.GenTraversableOnce
import scala.collection.IndexedSeqLike
import scala.collection.generic.CanBuildFrom
import scala.collection.generic.{ CanBuildFrom, GenericCompanion, GenericTraversableTemplate }
import scala.collection.immutable.IndexedSeq
import scala.reflect.ClassTag

Expand All @@ -36,28 +36,28 @@ import scala.reflect.ClassTag
* extends `IndexedSeq` to provide interoperability with Scala's collection
* library but users should avoid these methods whenever possible.
*/
private[zio] trait ChunkLike[+A] extends IndexedSeq[A] with IndexedSeqLike[A, Chunk[A]] { self: Chunk[A] =>
private[zio] trait ChunkLike[+A]
extends IndexedSeq[A]
with IndexedSeqLike[A, Chunk[A]]
with GenericTraversableTemplate[A, Chunk] { self: Chunk[A] =>

override final def :+[A1 >: A, That](a1: A1)(implicit bf: CanBuildFrom[Chunk[A], A1, That]): That =
bf match {
case _: ChunkCanBuildFrom[A1] => append(a1)
case _ => super.:+(a1)
}
if (isChunkCanBuildFrom[A, A1, That](bf)) append(a1).asInstanceOf[That]
else super.+:(a1)

override final def +:[A1 >: A, That](a1: A1)(implicit bf: CanBuildFrom[Chunk[A], A1, That]): That =
bf match {
case _: ChunkCanBuildFrom[A1] => prepend(a1)
case _ => super.:+(a1)
}
if (isChunkCanBuildFrom[A, A1, That](bf)) prepend(a1).asInstanceOf[That]
else super.:+(a1)

/**
* Returns a filtered, mapped subset of the elements of this chunk.
*/
override final def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Chunk[A], B, That]): That =
bf match {
case _: ChunkCanBuildFrom[_] => collectChunk(pf)
case _ => super.collect(pf)
}
if (isChunkCanBuildFrom[A, B, That](bf)) collectChunk(pf).asInstanceOf[That]
else super.collect(pf)

override def companion: GenericCompanion[Chunk] =
Chunk

/**
* Returns the concatenation of mapping every element into a new chunk using
Expand All @@ -66,10 +66,8 @@ private[zio] trait ChunkLike[+A] extends IndexedSeq[A] with IndexedSeqLike[A, Ch
override final def flatMap[B, That](
f: A => GenTraversableOnce[B]
)(implicit bf: CanBuildFrom[Chunk[A], B, That]): That =
bf match {
case _: ChunkCanBuildFrom[_] => flatMapChunk(f)
case _ => super.flatMap(f)
}
if (isChunkCanBuildFrom[A, B, That](bf)) flatMapChunk(f).asInstanceOf[That]
else super.flatMap(f)

/**
* Returns the first index for which the given predicate is satisfied.
Expand All @@ -81,10 +79,8 @@ private[zio] trait ChunkLike[+A] extends IndexedSeq[A] with IndexedSeqLike[A, Ch
* Returns a chunk with the elements mapped by the specified function.
*/
override final def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Chunk[A], B, That]): That =
bf match {
case _: ChunkCanBuildFrom[_] => mapChunk(f)
case _ => super.map(f)
}
if (isChunkCanBuildFrom[A, B, That](bf)) mapChunk(f).asInstanceOf[That]
else super.map(f)

/**
* Generates a readable string representation of this chunk using the
Expand Down Expand Up @@ -201,6 +197,14 @@ private[zio] trait ChunkLike[+A] extends IndexedSeq[A] with IndexedSeqLike[A, Ch
*/
override protected[this] def newBuilder: ChunkBuilder[A] =
ChunkBuilder.make()

/**
* Returns whether the specified `CanBuildFrom` is a `ChunkCanBuildFrom` or
* a `CanBuildFrom` of one of the supertypes of `Chunk`.
*/
@inline
private[this] def isChunkCanBuildFrom[A, B, That](bf: CanBuildFrom[Chunk[A], B, That]): Boolean =
bf.isInstanceOf[ChunkCanBuildFrom[_]] || (bf eq IndexedSeq.ReusableCBF) || (bf eq collection.immutable.Seq.ReusableCBF) || (bf eq collection.Seq.ReusableCBF)
}

object ChunkLike {
Expand Down
22 changes: 22 additions & 0 deletions core/shared/src/main/scala-2.13+/ChunkFactory.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2017-2020 John A. De Goes and the ZIO Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package zio

private[zio] trait ChunkFactory {
def apply[A](as: A*): Chunk[A]
def fill[A](n: Int)(elem: => A): Chunk[A]
}
6 changes: 3 additions & 3 deletions core/shared/src/main/scala/zio/Chunk.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ sealed trait Chunk[+A] extends ChunkLike[A] { self =>
}
}

object Chunk {
object Chunk extends ChunkFactory {

/**
* Returns the empty chunk.
Expand All @@ -1078,7 +1078,7 @@ object Chunk {
/**
* Returns a chunk from a number of values.
*/
def apply[A](as: A*): Chunk[A] =
override def apply[A](as: A*): Chunk[A] =
fromIterable(as)

/**
Expand Down Expand Up @@ -1192,7 +1192,7 @@ object Chunk {
fromArray(it.toArray)
}

def fill[A](n: Int)(elem: => A): Chunk[A] =
override def fill[A](n: Int)(elem: => A): Chunk[A] =
if (n <= 0) Chunk.empty
else {
val builder = ChunkBuilder.make[A]()
Expand Down

0 comments on commit 069d7b8

Please sign in to comment.