package org.rascalmpl.eclipse.repl;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class REPLPipedInputStream extends InputStream {
private final ConcurrentLinkedQueue<Byte> queue;
private volatile boolean closed;
private final Semaphore newData = new Semaphore(0);
public REPLPipedInputStream() {
this.queue = new ConcurrentLinkedQueue<Byte>();
this.closed = false;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
// we have to at least read one (so block until we can)
int atLeastOne = read();
if (atLeastOne == -1) {
return -1;
}
int index = off;
b[index++] = (byte) atLeastOne;
// now consume the rest of the available bytes
Byte current;
while ((current = queue.poll()) != null && (index < off + len)) {
b[index++] = current;
}
return index - off;
}
@Override
public int read() throws IOException {
Byte result = null;
while ((result = queue.poll()) == null) {
try {
newData.tryAcquire(10, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
return -1;
}
if (closed) {
return -1;
}
}
return (result & 0xFF);
}
@Override
public void close() throws IOException {
closed = true;
}
public void write(byte[] b, int off, int len) {
for (int i = off; i < off + len; i++) {
queue.add(b[i]);
}
newData.release();
}
public void write(byte b) {
queue.add(b);
newData.release();
}
}