/* NSC -- new Scala compiler * Copyright 2009-2013 Typesafe/Scala Solutions and LAMP/EPFL * @author Martin Odersky */ package scala.tools.nsc package interactive /** Typical interaction, given a predicate , a function , * and an exception handler : * * val TIMEOUT = 100 // (milliseconds) or something like that * val r = new Response() * while (!r.isComplete && !r.isCancelled) { * if () r.cancel() * else r.get(TIMEOUT) match { * case Some(Left(data)) => (data) * case Some(Right(exc)) => (exc) * case None => * } * } */ class Response[T] { private var data: Option[Either[T, Throwable]] = None private var complete = false private var cancelled = false /** Set provisional data, more to come */ def setProvisionally(x: T) = synchronized { data = Some(Left(x)) } /** Set final data, and mark response as complete. */ def set(x: T) = synchronized { data = Some(Left(x)) complete = true notifyAll() } /** Store raised exception in data, and mark response as complete. */ def raise(exc: Throwable) = synchronized { data = Some(Right(exc)) complete = true notifyAll() } /** Get final data, wait as long as necessary. * When interrupted will return with Right(InterruptedException) */ def get: Either[T, Throwable] = synchronized { while (!complete) { try { wait() } catch { case exc: InterruptedException => { Thread.currentThread().interrupt() raise(exc) } } } data.get } /** Optionally get data within `timeout` milliseconds. * When interrupted will return with Some(Right(InterruptedException)) * When timeout ends, will return last stored provisional result, * or else None if no provisional result was stored. */ def get(timeout: Long): Option[Either[T, Throwable]] = synchronized { val start = System.currentTimeMillis var current = start while (!complete && start + timeout > current) { try { wait(timeout - (current - start)) } catch { case exc: InterruptedException => { Thread.currentThread().interrupt() raise(exc) } } current = System.currentTimeMillis } data } /** Final data set was stored */ def isComplete = synchronized { complete } /** Cancel action computing this response (Only the * party that calls get on a response may cancel). */ def cancel() = synchronized { cancelled = true } /** A cancel request for this response has been issued */ def isCancelled = synchronized { cancelled } def clear() = synchronized { data = None complete = false cancelled = false } }