commit dcee1e4f22eb339d8383622c8740ac9ac763aa62 Author: MrLetsplay Date: Thu Aug 1 18:44:59 2024 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7eaec72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/bin/ +/target/ +/dependency-reduced-pom.xml +/.settings/ +/.classpath diff --git a/.project b/.project new file mode 100644 index 0000000..4cba005 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + SimpleNIO + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..614d03a --- /dev/null +++ b/pom.xml @@ -0,0 +1,73 @@ + + 4.0.0 + me.mrletsplay + SimpleNIO + 1.0-SNAPSHOT + + src/main/java + + + maven-compiler-plugin + 3.10.1 + + 11 + UTF-8 + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.4.0 + + 11 + UTF-8 + src/main/java + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + + + + Graphite-Official + https://maven.graphite-official.com/releases + + + + + + org.junit.jupiter + junit-jupiter-api + 5.10.1 + test + + + me.mrletsplay + MrCore + 4.5 + + + \ No newline at end of file diff --git a/src/main/java/me/mrletsplay/simplenio/_test/SimpleNIOMain.java b/src/main/java/me/mrletsplay/simplenio/_test/SimpleNIOMain.java new file mode 100644 index 0000000..6463dd2 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/_test/SimpleNIOMain.java @@ -0,0 +1,5 @@ +package me.mrletsplay.simplenio._test; + +public class SimpleNIOMain { + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/Expectation.java b/src/main/java/me/mrletsplay/simplenio/reader/Expectation.java new file mode 100644 index 0000000..f113690 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/Expectation.java @@ -0,0 +1,17 @@ +package me.mrletsplay.simplenio.reader; + +import java.io.IOException; +import java.util.function.Supplier; + +import me.mrletsplay.simplenio.util.IOConsumer; +import me.mrletsplay.simplenio.util.IORunnable; + +public interface Expectation { + + public void orElseRun(IOConsumer> run); + + public void orElseRun(IORunnable run); + + public void orElseThrow(Supplier exception); + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/ExpectationImpl.java b/src/main/java/me/mrletsplay/simplenio/reader/ExpectationImpl.java new file mode 100644 index 0000000..ae8d764 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/ExpectationImpl.java @@ -0,0 +1,33 @@ +package me.mrletsplay.simplenio.reader; + +import java.io.IOException; +import java.util.function.Supplier; + +import me.mrletsplay.simplenio.util.IOConsumer; +import me.mrletsplay.simplenio.util.IORunnable; + +public class ExpectationImpl implements Expectation { + + private IOConsumer> run; + + @Override + public void orElseRun(IOConsumer> run) { + this.run = run; + } + + @Override + public void orElseRun(IORunnable run) { + this.run = instance -> run.run(); + } + + @Override + public void orElseThrow(Supplier exception) { + this.run = instance -> { throw exception.get(); }; + } + + public void fail(ReaderInstance instance) throws IOException { + if(run == null) throw new IOException("Expectation failed"); + run.accept(instance); + } + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/Operation.java b/src/main/java/me/mrletsplay/simplenio/reader/Operation.java new file mode 100644 index 0000000..3ec2f29 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/Operation.java @@ -0,0 +1,46 @@ +package me.mrletsplay.simplenio.reader; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import me.mrletsplay.simplenio.util.IOConsumer; +import me.mrletsplay.simplenio.util.IORunnable; + +public interface Operation extends OperationCallback { + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException; + + public Operation copy(); + + public void reset(); + + public default Operation then(Operation other) { + return Operations.allOf(this, other); + } + + /** + * API Note: {@code other} must be a stateless runnable, because it might be called from multiple threads. + * @param other The action to run + * @return An Operation + */ + public default Operation thenRun(IORunnable other) { + return then(Operations.stateless((instance, buf) -> { + other.run(); + return true; + })); + } + + /** + * API Note: {@code other} must be a stateless runnable, because it might be called from multiple threads. + * @param other The action to run + * @return An Operation + */ + public default Operation thenRun(IOConsumer> other) { + return then(Operations.stateless((instance, buf) -> { + other.accept(instance); + return true; + })); + } + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/OperationCallback.java b/src/main/java/me/mrletsplay/simplenio/reader/OperationCallback.java new file mode 100644 index 0000000..3bb580c --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/OperationCallback.java @@ -0,0 +1,10 @@ +package me.mrletsplay.simplenio.reader; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public interface OperationCallback { + + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException; + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/Operations.java b/src/main/java/me/mrletsplay/simplenio/reader/Operations.java new file mode 100644 index 0000000..98cf257 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/Operations.java @@ -0,0 +1,370 @@ +package me.mrletsplay.simplenio.reader; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import me.mrletsplay.simplenio.util.IOConsumer; +import me.mrletsplay.simplenio.util.IORunnable; + +public class Operations { + + public static Operation stateless(OperationCallback callback) { + return new Operation() { + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + return callback.read(instance, buf); + } + + @Override + public Operation copy() { + return this; + } + + @Override + public void reset() { + + } + + }; + } + + public static Operation run(IORunnable run) { + return stateless((instance, buf) -> { + run.run(); + return true; + }); + } + + public static Operation run(IOConsumer> run) { + return stateless((instance, buf) -> { + run.accept(instance); + return true; + }); + } + + public static Operation allOf(Operation... operations) { + return new CombinedOperation(operations); + } + + public static Operation readByte(SimpleRef ref) { + return stateless((instance, buf) -> { + if(!buf.hasRemaining()) return false; + ref.set(instance, buf.get()); + return true; + }); + } + + public static Operation readInt(SimpleRef ref) { + return new ReadIntOperation(ref); + } + + public static Operation readNBytes(SimpleRef ref, int n) { + return new ReadBytesOperation(ref, n); + } + + public static Operation readUntilBytes(SimpleRef ref, byte[] delimiter, int limit) { + return new ReadBytesUntilOperation(ref, delimiter, limit); + } + + public static Operation lazy(Ref lazy) { + return new LazyOperation(lazy); + } + + public static Operation branch(Ref value, Operation... branches) { + return new BranchOperation(value, branches); + } + + public static Operation loopUntil(Ref condition, Operation body) { + return new LoopUntilOperation(condition, body); + } + + public static Operation read(SimpleRef ref, Reader reader) { + return new ReaderOperation<>(ref, reader); + } + + private static class CombinedOperation implements Operation { + + private Operation[] operations; + private int i; + + public CombinedOperation(Operation... operations) { + this.operations = operations; + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + while(i < operations.length) { + if(operations[i].read(instance, buf)) { + i++; + }else if(!buf.hasRemaining()) break; + } + + return i == operations.length; + } + + @Override + public Operation copy() { + return new CombinedOperation(Arrays.stream(operations).map(Operation::copy).toArray(Operation[]::new)); + } + + @Override + public void reset() { + for(Operation op : operations) op.reset(); + i = 0; + } + + } + + private static class ReadIntOperation implements Operation { + + private SimpleRef ref; + private int value; + private int i; + + public ReadIntOperation(SimpleRef ref) { + this.ref = ref; + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + while(buf.hasRemaining() && i > 0) { + i--; + value |= (buf.get() & 0xFF) << i; + } + + if(i == 0) { + ref.set(instance, value); + return true; + } + + return false; + } + + @Override + public Operation copy() { + return new ReadIntOperation(ref); + } + + @Override + public void reset() { + this.value = 0; + this.i = 4; + } + + } + + private static class ReadBytesOperation implements Operation { + + private SimpleRef ref; + private byte[] bytes; + private int i; + + public ReadBytesOperation(SimpleRef ref, int n) { + this.ref = ref; + this.bytes = new byte[n]; + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + while(buf.hasRemaining() && i < bytes.length) { + bytes[i++] = buf.get(); + } + + if(i == bytes.length) { + ref.set(instance, bytes); + return true; + } + + return false; + } + + @Override + public Operation copy() { + return new ReadBytesOperation(ref, bytes.length); + } + + @Override + public void reset() { + i = 0; + } + + } + + private static class ReadBytesUntilOperation implements Operation { + + private SimpleRef ref; + private byte[] delimiter; + private byte[] bytes; + private int i; + + public ReadBytesUntilOperation(SimpleRef ref, byte[] delimiter, int limit) { + this.ref = ref; + this.delimiter = delimiter; + this.bytes = new byte[limit]; + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + while(buf.hasRemaining() && i < bytes.length) { + bytes[i++] = buf.get(); + + if(i >= delimiter.length && Arrays.equals(bytes, i - delimiter.length, i, delimiter, 0, delimiter.length)) { + ref.set(instance, Arrays.copyOfRange(bytes, 0, i)); + return true; + } + } + + if(i == bytes.length) throw new IOException("Buffer limit reached"); + + return false; + } + + @Override + public Operation copy() { + return new ReadBytesUntilOperation(ref, delimiter, bytes.length); + } + + @Override + public void reset() { + i = 0; + } + + } + + private static class LazyOperation implements Operation { + + private Ref operationSupplier; + private Operation operation; + + public LazyOperation(Ref operationSupplier) { + this.operationSupplier = operationSupplier; + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + if(operation == null) operation = operationSupplier.get(instance); + return operation.read(instance, buf); + } + + @Override + public Operation copy() { + return new LazyOperation(operationSupplier); + } + + @Override + public void reset() { + this.operation = null; + } + + } + + private static class BranchOperation implements Operation { + + private Ref value; + private Operation[] branches; + private int i; + + public BranchOperation(Ref value, Operation... branches) { + this.value = value; + this.branches = branches; + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + if(i == -1) i = value.get(instance); + if(branches[i] == null) return true; + return branches[i].read(instance, buf); + } + + @Override + public Operation copy() { + return new BranchOperation(value, Arrays.stream(branches).map(op -> op == null ? null : op.copy()).toArray(Operation[]::new)); + } + + @Override + public void reset() { + for(Operation op : branches) { + if(op != null) op.reset(); + } + this.i = -1; + } + + } + + private static class LoopUntilOperation implements Operation { + + private Ref condition; + private Operation body; + + public LoopUntilOperation(Ref condition, Operation body) { + this.condition = condition; + this.body = body; + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + if(body.read(instance, buf)) { + body.reset(); + if(condition.get(instance)) return true; + } + + return false; + } + + @Override + public Operation copy() { + return new LoopUntilOperation(condition, body.copy()); + } + + @Override + public void reset() { + body.reset(); + } + + } + + private static class ReaderOperation implements Operation { + + private SimpleRef ref; + private Reader reader; + private ReaderInstance readerInstance; + + public ReaderOperation(SimpleRef ref, Reader reader) { + this.ref = ref; + this.reader = reader; + this.readerInstance = reader.createInstance(); + reset(); + } + + @Override + public boolean read(ReaderInstance instance, ByteBuffer buf) throws IOException { + if(readerInstance.read(buf)) { + ref.set(instance, readerInstance.get()); + return true; + } + + return false; + } + + @Override + public Operation copy() { + return new ReaderOperation<>(ref, reader); + } + + @Override + public void reset() { + readerInstance.reset(); + } + + } + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/Reader.java b/src/main/java/me/mrletsplay/simplenio/reader/Reader.java new file mode 100644 index 0000000..87daefe --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/Reader.java @@ -0,0 +1,61 @@ +package me.mrletsplay.simplenio.reader; + +import java.util.List; + +import me.mrletsplay.simplenio.util.IOConsumer; +import me.mrletsplay.simplenio.util.IOFunction; +import me.mrletsplay.simplenio.util.IORunnable; + +public interface Reader { + + public Ref readByte(); + + public Ref readInt(); + + public Ref readNBytes(int n); + + public Ref readNBytes(Ref n); + + public Ref readUntilByte(byte delimiter, int limit); + + public Ref readUntilByte(Ref delimiter, int limit); + + public Ref readUntilBytes(byte[] delimiter, int limit); + + public Ref readUntilBytes(Ref delimiter, int limit); + + public void read(Operation operation); + + public Ref read(Reader reader); + + public void branch(Ref condition, Operation ifTrue, Operation ifFalse); + + public void branch(Ref value, Operation... branches); + + public Ref branch(Ref condition, Reader ifTrue, Reader ifFalse); + + public Ref branch(Ref value, @SuppressWarnings("unchecked") Reader... branches); + + public void loopUntil(Ref condition, Operation body); + + public Ref> loopUntil(Ref condition, Reader body); + + public void run(IORunnable action); + + public void run(IOConsumer> action); + + public Expectation expect(Ref condition); + + public Expectation expectByte(byte b); + + public Expectation expectByte(Ref b); + + public Expectation expectBytes(byte[] bytes); + + public Expectation expectBytes(Ref b); + + public void setConverter(IOFunction, T> converter); + + public ReaderInstance createInstance(); + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/ReaderException.java b/src/main/java/me/mrletsplay/simplenio/reader/ReaderException.java new file mode 100644 index 0000000..0326428 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/ReaderException.java @@ -0,0 +1,5 @@ +package me.mrletsplay.simplenio.reader; + +public class ReaderException { + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/ReaderImpl.java b/src/main/java/me/mrletsplay/simplenio/reader/ReaderImpl.java new file mode 100644 index 0000000..c535e76 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/ReaderImpl.java @@ -0,0 +1,286 @@ +package me.mrletsplay.simplenio.reader; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import me.mrletsplay.simplenio.util.IOConsumer; +import me.mrletsplay.simplenio.util.IOFunction; +import me.mrletsplay.simplenio.util.IORunnable; + +public class ReaderImpl implements Reader { + + private List operations; + private Map stackTraces; + private IOFunction, T> converter; + + public ReaderImpl() { + this.operations = new ArrayList<>(); + this.stackTraces = new HashMap<>(); + } + + private void addOperation(Operation operation) { + operations.add(operation); + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + stackTraces.put(operation, Arrays.copyOfRange(stackTrace, 1, stackTrace.length)); + } + + @Override + public Ref readByte() { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.readByte(ref)); + return ref; + } + + @Override + public Ref readInt() { + SimpleRef valueRef = SimpleRef.create(); + addOperation(Operations.readInt(valueRef)); + return valueRef; + } + + @Override + public Ref readNBytes(int n) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.readNBytes(ref, n)); + return ref; + } + + @Override + public Ref readNBytes(Ref n) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.lazy(instance -> Operations.readNBytes(ref, n.get(instance)))); + return ref; + } + + @Override + public Ref readUntilByte(byte delimiter, int limit) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.readUntilBytes(ref, new byte[] {delimiter}, limit)); + return ref; + } + + @Override + public Ref readUntilByte(Ref delimiter, int limit) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.lazy(instance -> Operations.readUntilBytes(ref, new byte[] {delimiter.get(instance)}, limit))); + return ref; + } + + @Override + public Ref readUntilBytes(byte[] delimiter, int limit) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.readUntilBytes(ref, delimiter, limit)); + return ref; + } + + @Override + public Ref readUntilBytes(Ref delimiter, int limit) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.lazy(instance -> Operations.readUntilBytes(ref, delimiter.get(instance), limit))); + return ref; + } + + @Override + public void read(Operation operation) { + addOperation(operation); + } + + @Override + public Ref read(Reader reader) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.read(ref, reader)); + return ref; + } + + @Override + public void branch(Ref condition, Operation ifTrue, Operation ifFalse) { + addOperation(Operations.branch(condition.map(c -> c ? 0 : 1), ifTrue, ifFalse)); + } + + @Override + public void branch(Ref value, Operation... branches) { + addOperation(Operations.branch(value, branches)); + } + + @Override + public Ref branch(Ref condition, Reader ifTrue, Reader ifFalse) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.branch(condition.map(c -> c ? 0 : 1), ifTrue == null ? null : Operations.read(ref, ifTrue), ifFalse == null ? null : Operations.read(ref, ifFalse))); + return ref; + } + + @Override + public Ref branch(Ref value, @SuppressWarnings("unchecked") Reader... branches) { + SimpleRef ref = SimpleRef.create(); + addOperation(Operations.branch(value, Arrays.stream(branches).map(b -> b == null ? null : Operations.read(ref, b)).toArray(Operation[]::new))); + return ref; + } + + @Override + public void loopUntil(Ref condition, Operation body) { + addOperation(Operations.loopUntil(condition, body)); + } + + @Override + public Ref> loopUntil(Ref condition, Reader body) { + SimpleRef current = SimpleRef.create(); + SimpleRef> ref = SimpleRef.create(); + addOperation(Operations.run(instance -> ref.set(instance, new ArrayList<>())).then(Operations.loopUntil(condition, Operations.read(current, body).thenRun(instance -> ref.get(instance).add(current.get(instance)))))); + return ref; + } + + @Override + public void run(IORunnable action) { + addOperation(Operations.run(action)); + } + + @Override + public void run(IOConsumer> action) { + addOperation(Operations.run(action)); + } + + @Override + public Expectation expect(Ref condition) { + ExpectationImpl expectation = new ExpectationImpl(); + addOperation(Operations.stateless((instance, buf) -> { + if(!condition.get(instance)) expectation.fail(instance); + return true; + })); + return expectation; + } + + @Override + public Expectation expectByte(byte b) { + Ref read = readByte(); + return expect(instance -> read.get(instance) == b); + } + + @Override + public Expectation expectByte(Ref b) { + Ref read = readByte(); + return expect(instance -> read.get(instance) == b.get(instance)); + } + + @Override + public Expectation expectBytes(byte[] bytes) { + Ref read = readNBytes(bytes.length); + return expect(instance -> Arrays.equals(read.get(instance), bytes)); + } + + @Override + public Expectation expectBytes(Ref bytes) { + SimpleRef read = SimpleRef.create(); + addOperation(Operations.lazy(instance -> Operations.readNBytes(read, bytes.get(instance).length))); + return expect(instance -> Arrays.equals(read.get(instance), bytes.get(instance))); + } + + @Override + public void setConverter(IOFunction, T> converter) { + this.converter = converter; + } + + @Override + public ReaderInstance createInstance() { + return new Instance(); + } + + protected class Instance implements ReaderInstance { + + private List operations; + private Map stackTraces; + private int idx; + private Map, Object> refValues; + private boolean finished; + private T value; + private Consumer onFinished; + + public Instance() { + this.stackTraces = new HashMap<>(); + this.operations = new ArrayList<>(ReaderImpl.this.operations.size()); + for(Operation op : ReaderImpl.this.operations) { + Operation copy = op.copy(); + this.operations.add(copy); + this.stackTraces.put(copy, ReaderImpl.this.stackTraces.get(op)); + } + this.refValues = new HashMap<>(); + reset(); + } + + @Override + public boolean read(ByteBuffer buffer) throws IOException { + if(idx >= operations.size()) throw new IllegalStateException("Read after finished"); + + while(idx < operations.size()) { + try { + Operation operation = operations.get(idx); + if(operation.read(this, buffer)) { + idx++; + }else if(!buffer.hasRemaining()) break; + }catch(Exception e) { + IOException ex = new IOException("Operation at index " + idx + " failed", e); + ex.setStackTrace(stackTraces.get(operations.get(idx))); + throw ex; + } + } + + if(idx == operations.size()) { + finished(); + return true; + } + + return false; + } + + @Override + public ReaderInstance onFinished(Consumer consumer) { + this.onFinished = consumer; + return this; + } + + private void finished() throws IOException { + finished = true; + value = converter.apply(this); + if(onFinished != null) onFinished.accept(value); + } + + @Override + public T get() throws IllegalStateException { + if(!finished) throw new IllegalStateException("Reader is not finished"); + return value; + } + + @Override + public void setRef(SimpleRef ref, R value) { + refValues.put(ref, value); + } + + @SuppressWarnings("unchecked") + @Override + public R getRef(SimpleRef ref) throws IllegalStateException { + if(!refValues.containsKey(ref)) throw new IllegalStateException("Tried to access ref before it was set (make sure you only call get() in a callback)"); + return (R) refValues.get(ref); + } + + @Override + public boolean isRefSet(SimpleRef ref) { + return refValues.containsKey(ref); + } + + @Override + public void reset() { + for(Operation op : operations) op.reset(); + this.idx = 0; + this.refValues.clear(); + this.finished = false; + this.value = null; + } + + } + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/ReaderInstance.java b/src/main/java/me/mrletsplay/simplenio/reader/ReaderInstance.java new file mode 100644 index 0000000..f35abfd --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/ReaderInstance.java @@ -0,0 +1,23 @@ +package me.mrletsplay.simplenio.reader; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.function.Consumer; + +public interface ReaderInstance { + + public boolean read(ByteBuffer buf) throws IOException; + + public ReaderInstance onFinished(Consumer consumer); + + public T get() throws IllegalStateException; + + public void setRef(SimpleRef ref, R value); + + public R getRef(SimpleRef ref) throws IllegalStateException; + + public boolean isRefSet(SimpleRef ref); + + public void reset(); + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/Ref.java b/src/main/java/me/mrletsplay/simplenio/reader/Ref.java new file mode 100644 index 0000000..9d32de8 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/Ref.java @@ -0,0 +1,52 @@ +package me.mrletsplay.simplenio.reader; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.function.Function; + +/** + * Readonly representation of a reference. + * @param The referenced type + */ +public interface Ref { + + public T get(ReaderInstance instance) throws IllegalStateException; + + public default Ref map(Function map) { + return instance -> map.apply(get(instance)); + } + + public default boolean isSet(ReaderInstance instance) { + try { + get(instance); + return true; + }catch(IllegalStateException e) { + return false; + } + } + + public default T getOrElse(ReaderInstance instance, T other) { + try { + return get(instance); + }catch(IllegalStateException e) { + return other; + } + } + + public static Ref asString(Ref bytes, Charset charset) { + return bytes.map(b -> new String(b, charset)); + } + + public static Ref asString(Ref bytes) { + return asString(bytes, StandardCharsets.UTF_8); + } + + public static Ref asBytes(Ref string, Charset charset) { + return string.map(s -> s.getBytes(charset)); + } + + public static Ref asBytes(Ref string) { + return asBytes(string, StandardCharsets.UTF_8); + } + +} diff --git a/src/main/java/me/mrletsplay/simplenio/reader/SimpleRef.java b/src/main/java/me/mrletsplay/simplenio/reader/SimpleRef.java new file mode 100644 index 0000000..6d8642f --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/reader/SimpleRef.java @@ -0,0 +1,31 @@ +package me.mrletsplay.simplenio.reader; + +public class SimpleRef implements Ref { + + private SimpleRef() {} + + public void set(ReaderInstance instance, T value) { + instance.setRef(this, value); + } + + @Override + public boolean isSet(ReaderInstance instance) { + return instance.isRefSet(this); + } + + @Override + public T get(ReaderInstance instance) throws IllegalStateException { + return instance.getRef(this); + } + + @Override + public T getOrElse(ReaderInstance instance, T other) { + if(!instance.isRefSet(this)) return other; + return get(instance); + } + + public static SimpleRef create() { + return new SimpleRef<>(); + } + +} diff --git a/src/main/java/me/mrletsplay/simplenio/util/IOConsumer.java b/src/main/java/me/mrletsplay/simplenio/util/IOConsumer.java new file mode 100644 index 0000000..583f717 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/util/IOConsumer.java @@ -0,0 +1,9 @@ +package me.mrletsplay.simplenio.util; + +import java.io.IOException; + +public interface IOConsumer { + + public void accept(T value) throws IOException; + +} diff --git a/src/main/java/me/mrletsplay/simplenio/util/IOFunction.java b/src/main/java/me/mrletsplay/simplenio/util/IOFunction.java new file mode 100644 index 0000000..3b3d1f9 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/util/IOFunction.java @@ -0,0 +1,9 @@ +package me.mrletsplay.simplenio.util; + +import java.io.IOException; + +public interface IOFunction { + + public O apply(I i) throws IOException; + +} diff --git a/src/main/java/me/mrletsplay/simplenio/util/IORunnable.java b/src/main/java/me/mrletsplay/simplenio/util/IORunnable.java new file mode 100644 index 0000000..f0ac864 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/util/IORunnable.java @@ -0,0 +1,9 @@ +package me.mrletsplay.simplenio.util; + +import java.io.IOException; + +public interface IORunnable { + + public void run() throws IOException; + +} diff --git a/src/main/java/me/mrletsplay/simplenio/util/IOSupplier.java b/src/main/java/me/mrletsplay/simplenio/util/IOSupplier.java new file mode 100644 index 0000000..4759401 --- /dev/null +++ b/src/main/java/me/mrletsplay/simplenio/util/IOSupplier.java @@ -0,0 +1,9 @@ +package me.mrletsplay.simplenio.util; + +import java.io.IOException; + +public interface IOSupplier { + + public T get() throws IOException; + +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000..f779a36 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,6 @@ +module me.mrletsplay.simplenio { + exports me.mrletsplay.simplenio.reader; + exports me.mrletsplay.simplenio.util; + + requires transitive me.mrletsplay.mrcore; +} \ No newline at end of file diff --git a/src/test/java/me/mrletsplay/simplenio/ReaderTest.java b/src/test/java/me/mrletsplay/simplenio/ReaderTest.java new file mode 100644 index 0000000..45a3551 --- /dev/null +++ b/src/test/java/me/mrletsplay/simplenio/ReaderTest.java @@ -0,0 +1,12 @@ +package me.mrletsplay.simplenio; + +import org.junit.jupiter.api.Test; + +public class ReaderTest { + + @Test + public void testReader() { + + } + +}