/*----- Various pieces of implicit magic ----------------------------------*/
class InvalidCStringException(msg: String) extends Exception(msg);
-type CString = Array[Byte];
-object Magic {
+object Implicits {
/* --- Syntactic sugar for locks --- */
implicit class LockOps(lk: Lock) {
/* LK withLock { BODY }
* LK.withLock(INTERRUPT) { BODY }
- * LK.withLock(DUR, [INTERRUPT]) { BODY } orelse { ALT }
- * LK.withLock(DL, [INTERRUPT]) { BODY } orelse { ALT }
+ * LK.withLock(DUR, [INTERRUPT]) { BODY } orElse { ALT }
+ * LK.withLock(DL, [INTERRUPT]) { BODY } orElse { ALT }
*
* Acquire a lock while executing a BODY. If a duration or deadline is
* given then wait so long for the lock, and then give up and run ALT
def withLock[T](body: => T): T = withLock(true)(body);
}
- class PendingLock[T] private[Magic]
+ class PendingLock[T] private[Implicits]
(val lk: Lock, val dur: Duration,
val interrupt: Boolean, body: => T) {
- /* An auxiliary class for LockOps; provides the `orelse' qualifier. */
+ /* An auxiliary class for LockOps; provides the `orElse' qualifier. */
- def orelse(alt: => T): T = {
+ def orElse(alt: => T): T = {
val locked = (dur, interrupt) match {
case (Duration.Inf, true) => lk.lockInterruptibly(); true
case (Duration.Inf, false) => lk.lock(); true
else try { body; } finally lk.unlock();
}
}
-
- /* --- Conversion to/from C strings --- */
-
- implicit class ConvertJStringToCString(s: String) {
- /* Magic to convert a string into a C string (null-terminated bytes). */
-
- def toCString: CString = {
- /* Convert the receiver to a C string.
- *
- * We do this by hand, rather than relying on the JNI's built-in
- * conversions, because we use the default encoding taken from the
- * locale settings, rather than the ridiculous `modified UTF-8' which
- * is (a) insensitive to the user's chosen locale and (b) not actually
- * UTF-8 either.
- */
-
- val enc = Charset.defaultCharset.newEncoder;
- val in = CharBuffer.wrap(s);
- var sz: Int = (s.length*enc.averageBytesPerChar + 1).toInt;
- var out = ByteBuffer.allocate(sz);
-
- while (true) {
- /* If there's still stuff to encode, then encode it. Otherwise,
- * there must be some dregs left in the encoder, so flush them out.
- */
- val r = if (in.hasRemaining) enc.encode(in, out, true)
- else enc.flush(out);
-
- /* Sift through the wreckage to figure out what to do. */
- if (r.isError) r.throwException();
- else if (r.isOverflow) {
- /* No space in the buffer. Make it bigger. */
-
- sz *= 2;
- val newout = ByteBuffer.allocate(sz);
- out.flip(); newout.put(out);
- out = newout;
- } else if (r.isUnderflow) {
- /* All done. Check that there are no unexpected zero bytes -- so
- * this will indeed be a valid C string -- and convert into a byte
- * array that the C code will be able to pick apart.
- */
-
- out.flip(); val n = out.limit; val u = out.array;
- if ({val z = u.indexOf(0); 0 <= z && z < n})
- throw new InvalidCStringException("null byte in encoding");
- val v = new Array[Byte](n + 1);
- out.array.copyToArray(v, 0, n);
- v(n) = 0;
- return v;
- }
- }
-
- /* Placate the type checker. */
- unreachable("unreachable");
- }
- }
-
- implicit class ConvertCStringToJString(v: CString) {
- /* Magic to convert a C string into a `proper' string. */
-
- def toJString: String = {
- /* Convert the receiver to a C string.
- *
- * We do this by hand, rather than relying on the JNI's built-in
- * conversions, because we use the default encoding taken from the
- * locale settings, rather than the ridiculous `modified UTF-8' which
- * is (a) insensitive to the user's chosen locale and (b) not actually
- * UTF-8 either.
- */
-
- val inlen = v.indexOf(0) match {
- case -1 => v.length
- case n => n
- }
- val dec = Charset.defaultCharset.newDecoder;
- val in = ByteBuffer.wrap(v, 0, inlen);
- dec.decode(in).toString
- }
- }
}
/*----- Cleanup assistant -------------------------------------------------*/