From 829b22e9cb5fcc64ae5f83ebb36becbd40babd8c Mon Sep 17 00:00:00 2001 From: Rex Kerr Date: Mon, 27 Apr 2015 20:55:09 -0700 Subject: [PATCH] Conversions from Scala and Java Iterators to the new java.lang.PrimitiveIterator trio, OfDouble, OfInt, and OfLong. Docs and tests included. No explicit Java support, but new scala.compat.java8.wrappers.IteratorPrimitiveIntWrapper(i) is not _that_ hard. --- .../IteratorPrimitiveDoubleWrapper.java | 13 +++ .../wrappers/IteratorPrimitiveIntWrapper.java | 13 +++ .../IteratorPrimitiveLongWrapper.java | 13 +++ .../java8/PrimitiveIteratorConversions.scala | 108 ++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveDoubleWrapper.java create mode 100644 src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveIntWrapper.java create mode 100644 src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveLongWrapper.java create mode 100644 src/main/scala/scala/compat/java8/PrimitiveIteratorConversions.scala diff --git a/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveDoubleWrapper.java b/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveDoubleWrapper.java new file mode 100644 index 0000000..36f9fa9 --- /dev/null +++ b/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveDoubleWrapper.java @@ -0,0 +1,13 @@ +package scala.compat.java8.wrappers; + +public class IteratorPrimitiveDoubleWrapper implements java.util.PrimitiveIterator.OfDouble { + private java.util.Iterator it; + public IteratorPrimitiveDoubleWrapper(java.util.Iterator it) { + this.it = it; + } + public boolean hasNext() { return it.hasNext(); } + public double nextDouble() { return it.next().doubleValue(); } + public void forEachRemaining(java.util.function.Consumer c) { + it.forEachRemaining(c); + } +} diff --git a/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveIntWrapper.java b/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveIntWrapper.java new file mode 100644 index 0000000..91753ae --- /dev/null +++ b/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveIntWrapper.java @@ -0,0 +1,13 @@ +package scala.compat.java8.wrappers; + +public class IteratorPrimitiveIntWrapper implements java.util.PrimitiveIterator.OfInt { + private java.util.Iterator it; + public IteratorPrimitiveIntWrapper(java.util.Iterator it) { + this.it = it; + } + public boolean hasNext() { return it.hasNext(); } + public int nextInt() { return it.next().intValue(); } + public void forEachRemaining(java.util.function.Consumer c) { + it.forEachRemaining(c); + } +} diff --git a/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveLongWrapper.java b/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveLongWrapper.java new file mode 100644 index 0000000..c332358 --- /dev/null +++ b/src/main/java/scala/compat/java8/wrappers/IteratorPrimitiveLongWrapper.java @@ -0,0 +1,13 @@ +package scala.compat.java8.wrappers; + +public class IteratorPrimitiveLongWrapper implements java.util.PrimitiveIterator.OfLong { + private java.util.Iterator it; + public IteratorPrimitiveLongWrapper(java.util.Iterator it) { + this.it = it; + } + public boolean hasNext() { return it.hasNext(); } + public long nextLong() { return it.next().longValue(); } + public void forEachRemaining(java.util.function.Consumer c) { + it.forEachRemaining(c); + } +} diff --git a/src/main/scala/scala/compat/java8/PrimitiveIteratorConversions.scala b/src/main/scala/scala/compat/java8/PrimitiveIteratorConversions.scala new file mode 100644 index 0000000..61ca1a4 --- /dev/null +++ b/src/main/scala/scala/compat/java8/PrimitiveIteratorConversions.scala @@ -0,0 +1,108 @@ +package scala.compat.java8 + +import language.implicitConversions +import java.util.{ Iterator => JIterator, PrimitiveIterator } + +/** This class enables conversion from `scala.Iterator` to the set of + * `java.util.PrimitiveIterator` classes. + * + * Scala's `Iterator` is generic, as is its `java.util` counterpart. However, + * `java.util.PrimitiveIterator` offers three manually-specialized variants of + * `Iterator`: `OfDouble`, `OfInt`, and `OfLong`. This class provides + * `.asPrimitive` extension methods for Scala and Java iterators to present + * the generic versions as the specialized version. + * + * Example usage: + * + * {{{ + * import scala.compat.java8.PrimitiveIteratorConverters._ + * val it = Iterator(1.0, 2.0, math.Pi) + * val jpid = it.asPrimitive // PrimitiveIterator.OfDouble + * }}} + */ +object PrimitiveIteratorConverters { + /** Type class implementing conversion from generic `Option` or `Optional` to manually specialized variants. */ + sealed abstract class SpecializerOfIterators[A, That] { + /** Packages a Java `Iterator` as a manually specialized variant `That` */ + def fromJava(it: JIterator[A]): That + /** Packages a Scala `Iterator` to a manually specialized Java variant `That` */ + def fromScala(it: Iterator[A]): That + } + + /** Implementation of wrapping of `java.util.Iterator[Double]` or `scala.collection.Iterator[Double]` as a `java.util.PrimitiveIterator.OfDouble` */ + implicit val specializer_PrimitiveIteratorDouble = new SpecializerOfIterators[Double, PrimitiveIterator.OfDouble] { + /** Packages a `java.util.Iterator[Double]` as a `java.util.PrimitiveIterator.OfDouble` */ + def fromJava(it: JIterator[Double]): PrimitiveIterator.OfDouble = + new wrappers.IteratorPrimitiveDoubleWrapper(it.asInstanceOf[JIterator[java.lang.Double]]) + + /** Packages a `scala.collection.Iterator[Double]` as a `java.util.PrimitiveIterator.OfDouble` */ + def fromScala(it: Iterator[Double]): PrimitiveIterator.OfDouble = new PrimitiveIterator.OfDouble { + def hasNext = it.hasNext + def next() = it.next() + def nextDouble() = it.next() + def remove() { throw new UnsupportedOperationException("remove on scala.collection.Iterator") } + def forEachRemaining(c: java.util.function.Consumer[_ >: java.lang.Double]) { + while (it.hasNext) c.accept(it.next) + } + def forEachRemaining(c: java.util.function.DoubleConsumer) { + while (it.hasNext) c.accept(it.next) + } + } + } + + /** Implementation of wrapping of `java.util.Iterator[Int]` or `scala.collection.Iterator[Int]` as a `java.util.PrimitiveIterator.OfInt` */ + implicit val specializer_PrimitiveIteratorInt = new SpecializerOfIterators[Int, PrimitiveIterator.OfInt] { + /** Packages a `java.util.Iterator[Int]` as a `java.util.PrimitiveIterator.OfInt` */ + def fromJava(it: JIterator[Int]): PrimitiveIterator.OfInt = + new wrappers.IteratorPrimitiveIntWrapper(it.asInstanceOf[JIterator[java.lang.Integer]]) + + /** Packages a `scala.collection.Iterator[Int]` as a `java.util.PrimitiveIterator.OfInt` */ + def fromScala(it: Iterator[Int]): PrimitiveIterator.OfInt = new PrimitiveIterator.OfInt { + def hasNext = it.hasNext + def next() = it.next() + def nextInt() = it.next() + def remove() { throw new UnsupportedOperationException("remove on scala.collection.Iterator") } + def forEachRemaining(c: java.util.function.Consumer[_ >: java.lang.Integer]) { + while (it.hasNext) c.accept(it.next) + } + def forEachRemaining(c: java.util.function.IntConsumer) { + while (it.hasNext) c.accept(it.next) + } + } + } + + /** Implementation of wrapping of `java.util.Iterator[Long]` or `scala.collection.Iterator[Long]` as a `java.util.PrimitiveIterator.OfLong` */ + implicit val specializer_PrimitiveIteratorLong = new SpecializerOfIterators[Long, PrimitiveIterator.OfLong] { + /** Packages a `java.util.Iterator[Long]` as a `java.util.PrimitiveIterator.OfLong` */ + def fromJava(it: JIterator[Long]): PrimitiveIterator.OfLong = + new wrappers.IteratorPrimitiveLongWrapper(it.asInstanceOf[JIterator[java.lang.Long]]) + + /** Packages a `scala.collection.Iterator[Long]` as a `java.util.PrimitiveIterator.OfLong` */ + def fromScala(it: Iterator[Long]): PrimitiveIterator.OfLong = new PrimitiveIterator.OfLong { + def hasNext = it.hasNext + def next() = it.next() + def nextLong() = it.next() + def remove() { throw new UnsupportedOperationException("remove on scala.collection.Iterator") } + def forEachRemaining(c: java.util.function.Consumer[_ >: java.lang.Long]) { + while (it.hasNext) c.accept(it.next) + } + def forEachRemaining(c: java.util.function.LongConsumer) { + while (it.hasNext) c.accept(it.next) + } + } + } + + /** Provides conversions from Java `Iterator` to manually specialized `PrimitiveIterator` variants, when available */ + implicit class RichJavaIteratorToPrimitives[A](val underlying: JIterator[A]) extends AnyVal { + /** Wraps this `java.util.Iterator` as a manually specialized variant, if possible */ + def asPrimitive[That](implicit specOp: SpecializerOfIterators[A, That]): That = specOp.fromJava(underlying) + } + + /** Provides conversions from Scala `Iterator` to manually specialized `PrimitiveIterator` variants, when available */ + implicit class RichIteratorToPrimitives[A](val underlying: Iterator[A]) extends AnyVal { + /** Wraps this `scala.collection.Iterator` as a manually specialized `java.util.PrimitiveIterator` variant, if possible */ + def asPrimitive[That](implicit specOp: SpecializerOfIterators[A, That]): That = specOp.fromScala(underlying) + } +} + +