Add one more puzzle-piece for async parsing api
diff --git a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java
new file mode 100644
index 0000000..6c67e26
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java
@@ -0,0 +1,220 @@
+package com.fasterxml.jackson.core.json.async;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.core.async.ByteArrayFeeder;
+import com.fasterxml.jackson.core.async.NonBlockingInputFeeder;
+import com.fasterxml.jackson.core.io.IOContext;
+import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
+import com.fasterxml.jackson.core.util.VersionUtil;
+
+public class NonBlockingJsonParser
+ extends NonBlockingJsonParserBase
+ implements ByteArrayFeeder
+{
+ /*
+ /**********************************************************************
+ /* Input source config
+ /**********************************************************************
+ */
+
+ /**
+ * This buffer is actually provided via {@link NonBlockingInputFeeder}
+ */
+ protected byte[] _inputBuffer = NO_BYTES;
+
+ /**
+ * In addition to current buffer pointer, and end pointer,
+ * we will also need to know number of bytes originally
+ * contained. This is needed to correctly update location
+ * information when the block has been completed.
+ */
+ protected int _origBufferLen;
+
+ // And from ParserBase:
+// protected int _inputPtr;
+// protected int _inputEnd;
+
+ /*
+ /**********************************************************************
+ /* Life-cycle
+ /**********************************************************************
+ */
+
+ public NonBlockingJsonParser(IOContext ctxt, int parserFeatures,
+ ByteQuadsCanonicalizer sym)
+ {
+ super(ctxt, parserFeatures, sym);
+ }
+
+ /*
+ /**********************************************************************
+ /* AsyncInputFeeder impl
+ /**********************************************************************
+ */
+
+ @Override
+ public ByteArrayFeeder getNonBlockingInputFeeder() {
+ return this;
+ }
+
+ @Override
+ public final boolean needMoreInput() {
+ return (_inputPtr >=_inputEnd) && !_endOfInput;
+ }
+
+ @Override
+ public void feedInput(byte[] buf, int start, int end) throws IOException
+ {
+ // Must not have remaining input
+ if (_inputPtr < _inputEnd) {
+ _reportError("Still have %d undecoded bytes, should not call 'feedInput'", _inputEnd - _inputPtr);
+ }
+ if (end < start) {
+ _reportError("Input end (%d) may not be before start (%d)", end, start);
+ }
+ // and shouldn't have been marked as end-of-input
+ if (_endOfInput) {
+ _reportError("Already closed, can not feed more input");
+ }
+ // Time to update pointers first
+ _currInputProcessed += _origBufferLen;
+
+ // And then update buffer settings
+ _inputBuffer = buf;
+ _inputPtr = start;
+ _inputEnd = end;
+ _origBufferLen = end - start;
+ }
+
+ @Override
+ public void endOfInput() {
+ _endOfInput = true;
+ }
+
+ /*
+ /**********************************************************************
+ /* Abstract methods/overrides from JsonParser
+ /**********************************************************************
+ */
+
+ /* Implementing these methods efficiently for non-blocking cases would
+ * be complicated; so for now let's just use the default non-optimized
+ * implementation
+ */
+
+// public boolean nextFieldName(SerializableString str) throws IOException
+// public String nextTextValue() throws IOException
+// public int nextIntValue(int defaultValue) throws IOException
+// public long nextLongValue(long defaultValue) throws IOException
+// public Boolean nextBooleanValue() throws IOException
+
+ @Override
+ public int releaseBuffered(OutputStream out) throws IOException {
+ int avail = _inputEnd - _inputPtr;
+ if (avail > 0) {
+ out.write(_inputBuffer, _inputPtr, avail);
+ }
+ return avail;
+ }
+
+ /*
+ /**********************************************************************
+ /* Main-level decoding
+ /**********************************************************************
+ */
+
+ @Override
+ public JsonToken nextToken() throws IOException
+ {
+ // First: regardless of where we really are, need at least one more byte;
+ // can simplify some of the checks by short-circuiting right away
+ if (_inputPtr >= _inputEnd) {
+ if (_closed) {
+ return null;
+ }
+ // note: if so, do not even bother changing state
+ if (_endOfInput) { // except for this special case
+ return _eofAsNextToken();
+ }
+ return JsonToken.NOT_AVAILABLE;
+ }
+ // in the middle of tokenization?
+ if (_currToken == JsonToken.NOT_AVAILABLE) {
+ return _finishToken();
+ }
+
+ // No: fresh new token; may or may not have existing one
+ _numTypesValid = NR_UNKNOWN;
+// _tokenInputTotal = _currInputProcessed + _inputPtr;
+ // also: clear any data retained so far
+ _binaryValue = null;
+ int ch = _inputBuffer[_inputPtr++];
+
+ switch (_majorState) {
+ case MAJOR_INITIAL:
+ // TODO: Bootstrapping? BOM?
+
+ case MAJOR_ROOT:
+ return _startValue(ch);
+
+ case MAJOR_OBJECT_FIELD: // field or end-object
+ // expect name
+ return _startFieldName(ch);
+
+ case MAJOR_OBJECT_VALUE:
+ case MAJOR_ARRAY_ELEMENT: // element or end-array
+ return _startValue(ch);
+
+ default:
+ }
+ VersionUtil.throwInternal();
+ return null;
+ }
+
+ /**
+ * Method called when a (scalar) value type has been detected, but not all of
+ * contents have been decoded due to incomplete input available.
+ */
+ protected final JsonToken _finishToken() throws IOException
+ {
+ // NOTE: caller ensures availability of at least one byte
+
+ switch (_minorState) {
+ }
+ return null;
+ }
+
+ /*
+ /**********************************************************************
+ /* Second-level decoding, root level
+ /**********************************************************************
+ */
+
+ /**
+ * Helper method called to detect type of a value token (at any level), and possibly
+ * decode it if contained in input buffer.
+ * Note that possible header has been ruled out by caller and is not checked here.
+ */
+ private final JsonToken _startValue(int ch) throws IOException
+ {
+ return null;
+ }
+
+ /*
+ /**********************************************************************
+ /* Second-level decoding, Name decoding
+ /**********************************************************************
+ */
+
+ /**
+ * Method that handles initial token type recognition for token
+ * that has to be either FIELD_NAME or END_OBJECT.
+ */
+ protected final JsonToken _startFieldName(int ch) throws IOException
+ {
+ return null;
+ }
+}