Skip to content

Commit

Permalink
Better representation for SelectionKey operations #21
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladimir Shevtsov committed Aug 14, 2019
1 parent f096d1a commit 4b2ee05
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 17 deletions.
18 changes: 14 additions & 4 deletions src/main/scala/zio/nio/channels/SelectableChannel.scala
Expand Up @@ -9,6 +9,7 @@ import java.nio.channels.{
SocketChannel => JSocketChannel
}

import zio.nio.channels.SelectionKey.Operation
import zio.nio.channels.spi.SelectorProvider
import zio.nio.{ Buffer, SocketAddress, SocketOption }
import zio.{ IO, UIO }
Expand All @@ -27,12 +28,21 @@ class SelectableChannel(private val channel: JSelectableChannel) {
final def keyFor(sel: Selector): UIO[Option[SelectionKey]] =
IO.effectTotal(Option(channel.keyFor(sel.selector)).map(new SelectionKey(_)))

final def register(sel: Selector, ops: Int, att: Option[AnyRef]): IO[IOException, SelectionKey] =
IO.effect(new SelectionKey(channel.register(sel.selector, ops, att.orNull)))
final def register(sel: Selector, ops: Set[Operation], att: Option[AnyRef]): IO[IOException, SelectionKey] =
IO.effect(new SelectionKey(channel.register(sel.selector, Operation.toInt(ops), att.orNull)))
.refineToOrDie[IOException]

final def register(sel: Selector, ops: Int): IO[IOException, SelectionKey] =
IO.effect(new SelectionKey(channel.register(sel.selector, ops))).refineToOrDie[IOException]
final def register(sel: Selector, ops: Set[Operation]): IO[IOException, SelectionKey] =
IO.effect(new SelectionKey(channel.register(sel.selector, Operation.toInt(ops))))
.refineToOrDie[IOException]

final def register(sel: Selector, op: Operation, att: Option[AnyRef]): IO[IOException, SelectionKey ] =
IO.effect(new SelectionKey(channel.register(sel.selector, op.intVal, att.orNull)))
.refineToOrDie[IOException]

final def register(sel: Selector, op: Operation): IO[IOException, SelectionKey ] =
IO.effect(new SelectionKey(channel.register(sel.selector, op.intVal)))
.refineToOrDie[IOException]

final def configureBlocking(block: Boolean): IO[IOException, SelectableChannel] =
IO.effect(new SelectableChannel(channel.configureBlocking(block))).refineToOrDie[IOException]
Expand Down
38 changes: 30 additions & 8 deletions src/main/scala/zio/nio/channels/SelectionKey.scala
Expand Up @@ -14,6 +14,24 @@ object SelectionKey {
case e: CancelledKeyException => e
}

sealed abstract class Operation(val intVal: Int)
object Operation {

final case object Read extends Operation(JSelectionKey.OP_READ)
final case object Write extends Operation(JSelectionKey.OP_WRITE)
final case object Connect extends Operation(JSelectionKey.OP_CONNECT)
final case object Accept extends Operation(JSelectionKey.OP_ACCEPT)

final val fullSet: Set[Operation] = Set(Read, Write, Connect, Accept)

def fromInt(ops: Int): Set[Operation] = {
fullSet.filter(op => (ops & op.intVal) != 0)
}

def toInt(set: Set[Operation]): Int = {
set.foldLeft(0) ((ops, op) => ops | op.intVal)
}
}
}

class SelectionKey(private[nio] val selectionKey: JSelectionKey) {
Expand All @@ -32,16 +50,20 @@ class SelectionKey(private[nio] val selectionKey: JSelectionKey) {
final val cancel: UIO[Unit] =
IO.effectTotal(selectionKey.cancel())

final val interestOps: IO[CancelledKeyException, Int] =
IO.effect(selectionKey.interestOps()).refineToOrDie[CancelledKeyException]

final def interestOps(ops: Int): IO[CancelledKeyException, SelectionKey] =
IO.effect(selectionKey.interestOps(ops))
.map(new SelectionKey(_))
final val interestOps: IO[CancelledKeyException, Set[Operation]] =
IO.effectTotal(selectionKey.interestOps())
.map(Operation.fromInt(_))
.refineToOrDie[CancelledKeyException]

final val readyOps: IO[CancelledKeyException, Int] =
IO.effect(selectionKey.readyOps()).refineToOrDie[CancelledKeyException]
final def interestOps(ops: Set[Operation]): IO[CancelledKeyException, Unit] =
IO.effect(selectionKey.interestOps(Operation.toInt(ops)))
.unit
.refineToOrDie[CancelledKeyException]

final val readyOps: IO[CancelledKeyException, Set[Operation]] =
IO.effect(selectionKey.readyOps())
.map(Operation.fromInt(_))
.refineToOrDie[CancelledKeyException]

final def isReadable: IO[CancelledKeyException, Boolean] =
IO.effect(selectionKey.isReadable()).refineOrDie(JustCancelledKeyException)
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/async_file_write_test.txt
@@ -0,0 +1 @@
Hello World
11 changes: 6 additions & 5 deletions src/test/scala/zio/nio/SelectorSuite.scala
@@ -1,11 +1,12 @@
package zio.nio

import java.nio.channels.{ CancelledKeyException, SelectionKey => JSelectionKey, SocketChannel => JSocketChannel }
import java.nio.channels.{CancelledKeyException, SocketChannel => JSocketChannel}

import testz.{Harness, assert}
import zio._
import zio.clock.Clock
import testz.{ Harness, assert }
import zio.nio.channels.{ Selector, ServerSocketChannel, SocketChannel }
import zio.nio.channels.SelectionKey.Operation
import zio.nio.channels.{Selector, ServerSocketChannel, SocketChannel}

object SelectorSuite extends DefaultRuntime {

Expand Down Expand Up @@ -36,7 +37,7 @@ object SelectorSuite extends DefaultRuntime {
clientOpt <- channel.accept
client = clientOpt.get
_ <- client.configureBlocking(false)
_ <- client.register(selector, JSelectionKey.OP_READ)
_ <- client.register(selector, Operation.Read)
} yield ()
} *>
IO.whenM(safeStatusCheck(key.isReadable)) {
Expand All @@ -62,7 +63,7 @@ object SelectorSuite extends DefaultRuntime {
channel <- ServerSocketChannel.open
_ <- channel.bind(address)
_ <- channel.configureBlocking(false)
_ <- channel.register(selector, JSelectionKey.OP_ACCEPT)
_ <- channel.register(selector, Operation.Accept)
buffer <- Buffer.byte(256)
_ <- started.succeed(())

Expand Down

0 comments on commit 4b2ee05

Please sign in to comment.