Skip to content

Commit 2ffa4d7

Browse files
committed
Automatic widening of numeric types for primitive Streams
The widening conversions follow the usual pattern. Float becomes Double, Byte/Char/Short become Int. Boolean and Unit are not widened. For Arrays, where the actual data is unboxed, widening is implemented through custom Stepper implementations, so you can get e.g. a native IntStepper for an Array[Byte]. The StreamConverters hierarchy is modified to prefer these widened primitive steppers, so that, for example, the `seqStream` extension method on an Array[Byte] returns an IntStream. Other collection types with a boxed representation also get the same widening conversions (so you can still benefit from the better performance of unboxed streams) but there are no implicitly available widening steppers. Only the Stream extension methods fall back to applying a widening stepper in order to produce a widening primitive stream. Widening narrow numeric types for streams is consistent with the Streams API in the JDK. For example, `CharSequence.chars` returns an `IntStream` instead of a `Stream[Character]`.
1 parent b175a03 commit 2ffa4d7

File tree

5 files changed

+181
-30
lines changed

5 files changed

+181
-30
lines changed

src/main/scala/scala/compat/java8/StreamConverters.scala

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ trait PrimitiveStreamUnboxer[A, S] {
1414
def apply(boxed: Stream[A]): S
1515
}
1616

17-
trait Priority3StreamConverters {
17+
trait Priority4StreamConverters {
18+
// Fallback converters for AnySteppers that cannot be unboxed and widened to primitive streams
1819
implicit class EnrichAnySteppableWithParStream[A, CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[A] with EfficientSubstep])
1920
extends MakesParallelStream[A, Stream[A]] {
2021
def parStream: Stream[A] = StreamSupport.stream(steppize(cc).stepper.anticipateParallelism, true)
@@ -25,7 +26,6 @@ trait Priority3StreamConverters {
2526
implicit class EnrichAnyValueSteppableWithParValueStream[V, CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[V] with EfficientSubstep]) {
2627
def parValueStream: Stream[V] = StreamSupport.stream(steppize(cc).valueStepper.anticipateParallelism, true)
2728
}
28-
// Note--conversion is only to make sure implicit conversion priority is lower than alternatives.
2929
implicit class EnrichScalaCollectionWithSeqStream[A, CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[A]])
3030
extends MakesSequentialStream[A, Stream[A]] {
3131
def seqStream: Stream[A] = StreamSupport.stream(steppize(cc).stepper, false)
@@ -38,6 +38,90 @@ trait Priority3StreamConverters {
3838
}
3939
}
4040

41+
trait Priority3StreamConverters extends Priority4StreamConverters {
42+
// Prefer to unbox and widen small primitive types over keeping them boxed
43+
implicit class EnrichBoxedFloatSteppableWithParStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Float] with EfficientSubstep])
44+
extends MakesParallelStream[java.lang.Double, DoubleStream] {
45+
def parStream: DoubleStream = StreamSupport.doubleStream(new Stepper.WideningFloatStepper(steppize(cc).stepper.anticipateParallelism), true)
46+
}
47+
implicit class EnrichBoxedFloatKeySteppableWithParKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Float] with EfficientSubstep]) {
48+
def parKeyStream: DoubleStream = StreamSupport.doubleStream(new Stepper.WideningFloatStepper(steppize(cc).keyStepper.anticipateParallelism), true)
49+
}
50+
implicit class EnrichBoxedFloatValueSteppableWithParValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Float] with EfficientSubstep]) {
51+
def parValueStream: DoubleStream = StreamSupport.doubleStream(new Stepper.WideningFloatStepper(steppize(cc).valueStepper.anticipateParallelism), true)
52+
}
53+
implicit class EnrichBoxedByteSteppableWithParStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Byte] with EfficientSubstep])
54+
extends MakesParallelStream[java.lang.Integer, IntStream] {
55+
def parStream: IntStream = StreamSupport.intStream(new Stepper.WideningByteStepper(steppize(cc).stepper.anticipateParallelism), true)
56+
}
57+
implicit class EnrichBoxedByteKeySteppableWithParKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Byte] with EfficientSubstep]) {
58+
def parKeyStream: IntStream = StreamSupport.intStream(new Stepper.WideningByteStepper(steppize(cc).keyStepper.anticipateParallelism), true)
59+
}
60+
implicit class EnrichBoxedByteValueSteppableWithParValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Byte] with EfficientSubstep]) {
61+
def parValueStream: IntStream = StreamSupport.intStream(new Stepper.WideningByteStepper(steppize(cc).valueStepper.anticipateParallelism), true)
62+
}
63+
implicit class EnrichBoxedShortSteppableWithParStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Short] with EfficientSubstep])
64+
extends MakesParallelStream[java.lang.Integer, IntStream] {
65+
def parStream: IntStream = StreamSupport.intStream(new Stepper.WideningShortStepper(steppize(cc).stepper.anticipateParallelism), true)
66+
}
67+
implicit class EnrichBoxedShortKeySteppableWithParKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Short] with EfficientSubstep]) {
68+
def parKeyStream: IntStream = StreamSupport.intStream(new Stepper.WideningShortStepper(steppize(cc).keyStepper.anticipateParallelism), true)
69+
}
70+
implicit class EnrichBoxedShortValueSteppableWithParValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Short] with EfficientSubstep]) {
71+
def parValueStream: IntStream = StreamSupport.intStream(new Stepper.WideningShortStepper(steppize(cc).valueStepper.anticipateParallelism), true)
72+
}
73+
implicit class EnrichBoxedCharSteppableWithParStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Char] with EfficientSubstep])
74+
extends MakesParallelStream[java.lang.Integer, IntStream] {
75+
def parStream: IntStream = StreamSupport.intStream(new Stepper.WideningCharStepper(steppize(cc).stepper.anticipateParallelism), true)
76+
}
77+
implicit class EnrichBoxedCharKeySteppableWithParKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Char] with EfficientSubstep]) {
78+
def parKeyStream: IntStream = StreamSupport.intStream(new Stepper.WideningCharStepper(steppize(cc).keyStepper.anticipateParallelism), true)
79+
}
80+
implicit class EnrichBoxedCharValueSteppableWithParValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Char] with EfficientSubstep]) {
81+
def parValueStream: IntStream = StreamSupport.intStream(new Stepper.WideningCharStepper(steppize(cc).valueStepper.anticipateParallelism), true)
82+
}
83+
implicit class EnrichBoxedFloatSteppableWithSeqStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Float]])
84+
extends MakesSequentialStream[java.lang.Double, DoubleStream] {
85+
def seqStream: DoubleStream = StreamSupport.doubleStream(new Stepper.WideningFloatStepper(steppize(cc).stepper), false)
86+
}
87+
implicit class EnrichBoxedFloatKeySteppableWithSeqKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Float]]) {
88+
def seqKeyStream: DoubleStream = StreamSupport.doubleStream(new Stepper.WideningFloatStepper(steppize(cc).keyStepper), false)
89+
}
90+
implicit class EnrichBoxedFloatValueSteppableWithSeqValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Float]]) {
91+
def seqValueStream: DoubleStream = StreamSupport.doubleStream(new Stepper.WideningFloatStepper(steppize(cc).valueStepper), false)
92+
}
93+
implicit class EnrichBoxedByteSteppableWithSeqStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Byte]])
94+
extends MakesSequentialStream[java.lang.Integer, IntStream] {
95+
def seqStream: IntStream = StreamSupport.intStream(new Stepper.WideningByteStepper(steppize(cc).stepper), false)
96+
}
97+
implicit class EnrichBoxedByteKeySteppableWithSeqKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Byte]]) {
98+
def seqKeyStream: IntStream = StreamSupport.intStream(new Stepper.WideningByteStepper(steppize(cc).keyStepper), false)
99+
}
100+
implicit class EnrichBoxedByteValueSteppableWithSeqValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Byte]]) {
101+
def seqValueStream: IntStream = StreamSupport.intStream(new Stepper.WideningByteStepper(steppize(cc).valueStepper), false)
102+
}
103+
implicit class EnrichBoxedShortSteppableWithSeqStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Short]])
104+
extends MakesSequentialStream[java.lang.Integer, IntStream] {
105+
def seqStream: IntStream = StreamSupport.intStream(new Stepper.WideningShortStepper(steppize(cc).stepper), false)
106+
}
107+
implicit class EnrichBoxedShortKeySteppableWithSeqKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Short]]) {
108+
def seqKeyStream: IntStream = StreamSupport.intStream(new Stepper.WideningShortStepper(steppize(cc).keyStepper), false)
109+
}
110+
implicit class EnrichBoxedShortValueSteppableWithSeqValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Short]]) {
111+
def seqValueStream: IntStream = StreamSupport.intStream(new Stepper.WideningShortStepper(steppize(cc).valueStepper), false)
112+
}
113+
implicit class EnrichBoxedCharSteppableWithSeqStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[Char]])
114+
extends MakesSequentialStream[java.lang.Integer, IntStream] {
115+
def seqStream: IntStream = StreamSupport.intStream(new Stepper.WideningCharStepper(steppize(cc).stepper), false)
116+
}
117+
implicit class EnrichBoxedCharKeySteppableWithSeqKeyStream[CC](cc: CC)(implicit steppize: CC => MakesKeyStepper[AnyStepper[Char]]) {
118+
def seqKeyStream: IntStream = StreamSupport.intStream(new Stepper.WideningCharStepper(steppize(cc).keyStepper), false)
119+
}
120+
implicit class EnrichBoxedCharValueSteppableWithSeqValueStream[CC](cc: CC)(implicit steppize: CC => MakesValueStepper[AnyStepper[Char]]) {
121+
def seqValueStream: IntStream = StreamSupport.intStream(new Stepper.WideningCharStepper(steppize(cc).valueStepper), false)
122+
}
123+
}
124+
41125
trait Priority2StreamConverters extends Priority3StreamConverters {
42126
implicit class EnrichDoubleSteppableWithParStream[CC](cc: CC)(implicit steppize: CC => MakesStepper[DoubleStepper with EfficientSubstep])
43127
extends MakesParallelStream[java.lang.Double, DoubleStream] {

src/main/scala/scala/compat/java8/collectionImpl/Stepper.scala

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,24 +239,24 @@ trait AnyStepper[A] extends Stepper[A] with java.util.Iterator[A] with Spliterat
239239
def parStream: java.util.stream.Stream[A] = java.util.stream.StreamSupport.stream(this, true)
240240
}
241241

242-
object AnyStepper {
243-
private[collectionImpl] class BoxedDoubleStepper(st: DoubleStepper) extends AnyStepper[Double] {
242+
private[collectionImpl] object AnyStepper {
243+
final class BoxedDoubleStepper(st: DoubleStepper) extends AnyStepper[Double] {
244244
def hasNext(): Boolean = st.hasNext()
245245
def next(): Double = st.next()
246246
def characteristics(): Int = st.characteristics()
247247
def estimateSize(): Long = st.estimateSize()
248248
def substep(): AnyStepper[Double] = new BoxedDoubleStepper(st.substep())
249249
}
250250

251-
private[collectionImpl] class BoxedIntStepper(st: IntStepper) extends AnyStepper[Int] {
251+
final class BoxedIntStepper(st: IntStepper) extends AnyStepper[Int] {
252252
def hasNext(): Boolean = st.hasNext()
253253
def next(): Int = st.next()
254254
def characteristics(): Int = st.characteristics()
255255
def estimateSize(): Long = st.estimateSize()
256256
def substep(): AnyStepper[Int] = new BoxedIntStepper(st.substep())
257257
}
258258

259-
private[collectionImpl] class BoxedLongStepper(st: LongStepper) extends AnyStepper[Long] {
259+
final class BoxedLongStepper(st: LongStepper) extends AnyStepper[Long] {
260260
def hasNext(): Boolean = st.hasNext()
261261
def next(): Long = st.next()
262262
def characteristics(): Int = st.characteristics()
@@ -564,4 +564,41 @@ object Stepper {
564564
case _ => new OfLongSpliterator(sp)
565565
}
566566

567+
/* These adapter classes can wrap an AnyStepper of a small numeric type into the appropriately widened
568+
* primitive Stepper type. This provides a basis for more efficient stream processing on unboxed values
569+
* provided that the original source of the data is already boxed. In other cases the widening conversion
570+
* should always be performed directly on the original unboxed values in a custom Stepper implementation
571+
* (see for example StepsWidenedByteArray). */
572+
573+
private[java8] class WideningByteStepper(st: AnyStepper[Byte]) extends IntStepper {
574+
def hasNext(): Boolean = st.hasNext()
575+
def nextInt(): Int = st.next()
576+
def characteristics(): Int = st.characteristics() | NonNull
577+
def estimateSize(): Long = st.estimateSize()
578+
def substep(): IntStepper = new WideningByteStepper(st.substep())
579+
}
580+
581+
private[java8] class WideningCharStepper(st: AnyStepper[Char]) extends IntStepper {
582+
def hasNext(): Boolean = st.hasNext()
583+
def nextInt(): Int = st.next()
584+
def characteristics(): Int = st.characteristics() | NonNull
585+
def estimateSize(): Long = st.estimateSize()
586+
def substep(): IntStepper = new WideningCharStepper(st.substep())
587+
}
588+
589+
private[java8] class WideningShortStepper(st: AnyStepper[Short]) extends IntStepper {
590+
def hasNext(): Boolean = st.hasNext()
591+
def nextInt(): Int = st.next()
592+
def characteristics(): Int = st.characteristics() | NonNull
593+
def estimateSize(): Long = st.estimateSize()
594+
def substep(): IntStepper = new WideningShortStepper(st.substep())
595+
}
596+
597+
private[java8] class WideningFloatStepper(st: AnyStepper[Float]) extends DoubleStepper {
598+
def hasNext(): Boolean = st.hasNext()
599+
def nextDouble(): Double = st.next()
600+
def characteristics(): Int = st.characteristics() | NonNull
601+
def estimateSize(): Long = st.estimateSize()
602+
def substep(): DoubleStepper = new WideningFloatStepper(st.substep())
603+
}
567604
}

src/main/scala/scala/compat/java8/converterImpl/StepsArray.scala

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,28 @@ extends StepsLikeIndexed[Boolean, StepsBoxedBooleanArray](_i0, _iN) {
3535
def semiclone(half: Int) = new StepsBoxedBooleanArray(underlying, i0, half)
3636
}
3737

38-
private[java8] class StepsBoxedByteArray(underlying: Array[Byte], _i0: Int, _iN: Int)
39-
extends StepsLikeIndexed[Byte, StepsBoxedByteArray](_i0, _iN) {
40-
def next() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
41-
def semiclone(half: Int) = new StepsBoxedByteArray(underlying, i0, half)
38+
private[java8] class StepsWidenedByteArray(underlying: Array[Byte], _i0: Int, _iN: Int)
39+
extends StepsIntLikeIndexed[StepsWidenedByteArray](_i0, _iN) {
40+
def nextInt() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
41+
def semiclone(half: Int) = new StepsWidenedByteArray(underlying, i0, half)
4242
}
4343

44-
private[java8] class StepsBoxedCharArray(underlying: Array[Char], _i0: Int, _iN: Int)
45-
extends StepsLikeIndexed[Char, StepsBoxedCharArray](_i0, _iN) {
46-
def next() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
47-
def semiclone(half: Int) = new StepsBoxedCharArray(underlying, i0, half)
44+
private[java8] class StepsWidenedCharArray(underlying: Array[Char], _i0: Int, _iN: Int)
45+
extends StepsIntLikeIndexed[StepsWidenedCharArray](_i0, _iN) {
46+
def nextInt() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
47+
def semiclone(half: Int) = new StepsWidenedCharArray(underlying, i0, half)
4848
}
4949

50-
private[java8] class StepsBoxedShortArray(underlying: Array[Short], _i0: Int, _iN: Int)
51-
extends StepsLikeIndexed[Short, StepsBoxedShortArray](_i0, _iN) {
52-
def next() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
53-
def semiclone(half: Int) = new StepsBoxedShortArray(underlying, i0, half)
50+
private[java8] class StepsWidenedShortArray(underlying: Array[Short], _i0: Int, _iN: Int)
51+
extends StepsIntLikeIndexed[StepsWidenedShortArray](_i0, _iN) {
52+
def nextInt() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
53+
def semiclone(half: Int) = new StepsWidenedShortArray(underlying, i0, half)
5454
}
5555

56-
private[java8] class StepsBoxedFloatArray(underlying: Array[Float], _i0: Int, _iN: Int)
57-
extends StepsLikeIndexed[Float, StepsBoxedFloatArray](_i0, _iN) {
58-
def next() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
59-
def semiclone(half: Int) = new StepsBoxedFloatArray(underlying, i0, half)
56+
private[java8] class StepsWidenedFloatArray(underlying: Array[Float], _i0: Int, _iN: Int)
57+
extends StepsDoubleLikeIndexed[StepsWidenedFloatArray](_i0, _iN) {
58+
def nextDouble() = if (hasNext()) { val j = i0; i0 += 1; underlying(j) } else throwNSEE
59+
def semiclone(half: Int) = new StepsWidenedFloatArray(underlying, i0, half)
6060
}
6161

6262
private[java8] class StepsDoubleArray(underlying: Array[Double], _i0: Int, _iN: Int)
@@ -97,20 +97,20 @@ final class RichArrayBooleanCanStep(private val underlying: Array[Boolean]) exte
9797
@inline def stepper: AnyStepper[Boolean] with EfficientSubstep = new StepsBoxedBooleanArray(underlying, 0, underlying.length)
9898
}
9999

100-
final class RichArrayByteCanStep(private val underlying: Array[Byte]) extends AnyVal with MakesStepper[AnyStepper[Byte] with EfficientSubstep] {
101-
@inline def stepper: AnyStepper[Byte] with EfficientSubstep = new StepsBoxedByteArray(underlying, 0, underlying.length)
100+
final class RichArrayByteCanStep(private val underlying: Array[Byte]) extends AnyVal with MakesStepper[IntStepper with EfficientSubstep] {
101+
@inline def stepper: IntStepper with EfficientSubstep = new StepsWidenedByteArray(underlying, 0, underlying.length)
102102
}
103103

104-
final class RichArrayCharCanStep(private val underlying: Array[Char]) extends AnyVal with MakesStepper[AnyStepper[Char] with EfficientSubstep] {
105-
@inline def stepper: AnyStepper[Char] with EfficientSubstep = new StepsBoxedCharArray(underlying, 0, underlying.length)
104+
final class RichArrayCharCanStep(private val underlying: Array[Char]) extends AnyVal with MakesStepper[IntStepper with EfficientSubstep] {
105+
@inline def stepper: IntStepper with EfficientSubstep = new StepsWidenedCharArray(underlying, 0, underlying.length)
106106
}
107107

108-
final class RichArrayShortCanStep(private val underlying: Array[Short]) extends AnyVal with MakesStepper[AnyStepper[Short] with EfficientSubstep] {
109-
@inline def stepper: AnyStepper[Short] with EfficientSubstep = new StepsBoxedShortArray(underlying, 0, underlying.length)
108+
final class RichArrayShortCanStep(private val underlying: Array[Short]) extends AnyVal with MakesStepper[IntStepper with EfficientSubstep] {
109+
@inline def stepper: IntStepper with EfficientSubstep = new StepsWidenedShortArray(underlying, 0, underlying.length)
110110
}
111111

112-
final class RichArrayFloatCanStep(private val underlying: Array[Float]) extends AnyVal with MakesStepper[AnyStepper[Float] with EfficientSubstep] {
113-
@inline def stepper: AnyStepper[Float] with EfficientSubstep = new StepsBoxedFloatArray(underlying, 0, underlying.length)
112+
final class RichArrayFloatCanStep(private val underlying: Array[Float]) extends AnyVal with MakesStepper[DoubleStepper with EfficientSubstep] {
113+
@inline def stepper: DoubleStepper with EfficientSubstep = new StepsWidenedFloatArray(underlying, 0, underlying.length)
114114
}
115115

116116
final class RichArrayDoubleCanStep(private val underlying: Array[Double]) extends AnyVal with MakesStepper[DoubleStepper with EfficientSubstep] {

src/test/scala/scala/compat/java8/StepConvertersTest.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,23 @@ class StepConvertersTest {
437437
Okay( (cc.TrieMap[Int, Int](0xDEEDED -> 654321): cc.Map[Int, Int]).valueStepper )
438438
}
439439

440+
@Test
441+
def shortWidening() {
442+
implicit val spec = SpecCheck(_.isInstanceOf[IntStepper])
443+
444+
good( Array[Short](654321.toShort).stepper )
445+
446+
//TODO: None of these currently work because there are no native Stepper implementations. This does not only
447+
// affect widening conversions though. While you can get, for example, an IntStepper for a WrappedArray[Int],
448+
// all values have to go through a boxing/unboxing step!
449+
450+
//good( ci.NumericRange(123456.toShort, 123458.toShort, 1.toShort).stepper )
451+
//good( ((Array[Short](654321.toShort): cm.WrappedArray[Short]): cm.ArrayLike[Short, cm.WrappedArray[Short]]).stepper )
452+
//good( (Array[Short](654321.toShort): cm.ArrayOps[Short]).stepper )
453+
//good( cm.ResizableArray[Short](654321.toShort).stepper )
454+
//good( (Array[Short](654321.toShort): cm.WrappedArray[Short]).stepper )
455+
}
456+
440457
@Test
441458
def comprehensivelyLong() {
442459
implicit val spec = SpecCheck(_.isInstanceOf[LongStepper])

src/test/scala/scala/compat/java8/StreamConvertersTest.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,17 @@ class StreamConvertersTest {
234234
assert(hsL.parStream.isInstanceOf[LongStream])
235235
}
236236
}
237+
238+
@Test
239+
def primitiveStreamTypes(): Unit = {
240+
// Unboxed native + widening Steppers available:
241+
assertEquals(Vector[Int](1, 2, 3), (Array[Int](1, 2, 3).seqStream: IntStream).toScala[Vector])
242+
assertEquals(Vector[Short](1.toShort, 2.toShort, 3.toShort), (Array[Short](1.toShort, 2.toShort, 3.toShort).seqStream: IntStream).toScala[Vector])
243+
assertEquals(Vector[String]("a", "b"), (Array[String]("a", "b").seqStream: Stream[String]).toScala[Vector])
244+
245+
// Boxed collections, widening via boxed AnySteppers:
246+
assertEquals(Vector[Int](1, 2, 3), (Vector[Int](1, 2, 3).seqStream: IntStream).toScala[Vector])
247+
assertEquals(Vector[Short](1.toShort, 2.toShort, 3.toShort), (Vector[Short](1.toShort, 2.toShort, 3.toShort).seqStream: IntStream).toScala[Vector])
248+
assertEquals(Vector[String]("a", "b"), (Vector[String]("a", "b").seqStream: Stream[String]).toScala[Vector])
249+
}
237250
}

0 commit comments

Comments
 (0)