Skip to content

Instantly share code, notes, and snippets.

@NthPortal
Created October 28, 2018 08:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NthPortal/65ec5938fcb02c9c724d88b3b929e372 to your computer and use it in GitHub Desktop.
Save NthPortal/65ec5938fcb02c9c724d88b3b929e372 to your computer and use it in GitHub Desktop.
private final class SingleUse[R](resource: => R) {
private val used = new AtomicBoolean(false)
def useWith[A](f: R => A)(implicit r: Using.Resource[R]): A =
if (used.getAndSet(true)) throw new IllegalStateException("resource has already been used")
else Using.resource(resource)(f)
}
final class Using[R, A] private[Using](resource: SingleUse[R], op: R => A) {
private def use0()(implicit r: Resource[R]): A = resource.useWith(op)
def use()(implicit r: Resource[R]): Try[A] = Try { use0() }
def map[B](f: A => B): Use[R, B] = {
if (op eq cachedIdentity) new Using(resource, (r: R) => f(r.asInstanceOf[A]))
else new Using(resource, (r: R) => f(op(r)))
}
def apply[B](f: A => B)(implicit r: Resource[R]): Try[B] = map(f).use()
def flatMap[R1: Resource, B](f: A => Use[R1, B]): Use[R, B] =
new Using(resource, (r: R) => f(op(r)).use0())
def withFilter(p: A => Boolean): Use[R, A] =
new Using(resource, (r: R) => {
val res = op(r)
if (p(res)) res
else throw new NoSuchElementException("Predicate does not hold for result of using resource")
})
def foreach[U](f: A => U)(implicit r: Resource[R]): Unit = {
apply(f)
()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment