// Path: src/main/java/jresp/RespDecoder.java
// public class RespDecoder {
// 
//     private SimpleStrState simpleStrDecoder = new SimpleStrState();
//     private ErrState errDecoder = new ErrState();
//     private IntState intDecoder = new IntState();
//     private BulkStrState bulkStrDecoder;
// 
//     private State state = null;
// 
//     RespDecoder() {
//         bulkStrDecoder = new BulkStrState(this);
//     }
// 
//     protected void decode(ByteBuffer in, Consumer<RespType> out) {
//         while (true) {
//             int availableBytes = in.remaining();
//             if (availableBytes == 0) {
//                 //
//                 // We need more bytes
//                 //
//                 break;
//             }
// 
//             if (state == null) {
//                 //
//                 // There is no current state, so read the next byte
//                 //
//                 char nextChar = (char) in.get();
//                 state = nextState(nextChar);
//             }
//             if (state.decode(in)) {
//                 out.accept(state.finish());
//                 state = null;
//             } else {
//                 //
//                 // We need more bytes
//                 //
//                 break;
//             }
//         }
//     }
// 
//     public State nextState(char token) {
//         switch (token) {
//             case '+':
//                 return simpleStrDecoder.reset();
//             case '-':
//                 return errDecoder.reset();
//             case ':':
//                 return intDecoder.reset();
//             case '$':
//                 return bulkStrDecoder.reset();
//             case '*':
//                 return new AryState(this);
//             default:
//                 throw new IllegalStateException(String.format("Unknown token %s", token));
//         }
//     }
// 
//     public IntState intDecoder() {
//         return (IntState)intDecoder.reset();
//     }
// }
// 
// Path: src/main/java/jresp/protocol/BulkStr.java
// public class BulkStr implements RespType {
//     private static final Map<String, BulkStr> cache = Collections.synchronizedMap(new HashMap<>());
// 
//     private byte[] payload;
// 
//     public BulkStr(String s) {
//         try {
//             payload = s.getBytes("UTF-8");
//         } catch (UnsupportedEncodingException e) {
//             throw new IllegalStateException(e);
//         }
//     }
// 
//     public BulkStr(byte[] s) {
//         payload = s;
//     }
// 
//     public BulkStr() {
//         this.payload = null;
//     }
// 
//     public static BulkStr get(String str) {
//         BulkStr val = cache.get(str);
//         if (val == null) {
//             val = new BulkStr(str);
//             cache.put(str, val);
//         }
//         return val;
//     }
// 
//     public String toString() {
//         return String.format("%s[%s]", getClass().getName(), Arrays.toString(payload));
//     }
// 
//     @Override
//     public void writeBytes(Deque<ByteBuffer> out) {
//         int size = 1;
//         byte[] header;
//         if (payload == null) {
//             header = Resp.longToByteArray(-1);
//         } else {
//             header = Resp.longToByteArray(payload.length);
//             size += 2 + payload.length;
//         }
//         size += 2 + header.length;
// 
//         ByteBuffer o = Resp.buffer(out, size);
//         o.put((byte)'$');
//         o.put(header);
//         if (payload != null) {
//             o.put(Resp.CRLF);
//             o.put(payload);
//         }
//         o.put(Resp.CRLF);
//     }
// 
//     public byte[] raw() {
//         return payload;
//     }
// 
//     @Override
//     public Object unwrap() {
//         if (payload == null) {
//             return null;
//         }
//         try {
//             return new String(payload, "UTF-8");
//         } catch (UnsupportedEncodingException e) {
//             throw new IllegalStateException(e);
//         }
//     }
// 
//     @Override
//     public int hashCode() {
//         return Arrays.hashCode(payload);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (o instanceof BulkStr) {
//             BulkStr bs = (BulkStr)o;
//             return Arrays.equals(payload, bs.payload);
//         } else {
//             return false;
//         }
//     }
// }
// 
// Path: src/main/java/jresp/protocol/RespType.java
// public interface RespType {
//     /**
//      * Write the RESP form to the ByteBuf
//      */
//     void writeBytes(Deque<ByteBuffer> out);
// 
//     /**
//      * Return the high-level Java equivalent.
//      */
//     Object unwrap();
// }


import jresp.RespDecoder;
import jresp.protocol.BulkStr;
import jresp.protocol.RespType;
import java.nio.ByteBuffer;
                 } else {
                     stringLength = (int)(len + 2); // To account for CRLF
                 }
             } else {
                 return false;
             }
        }
        if (stringLength < 0) {
            return true;
        } else {
            if (buffer == null || buffer.length < stringLength) {
                buffer = new byte[stringLength];
            }
            int diff = stringLength - idx;
            if (diff == 0) {
                return true;
            } else if (diff < 0) {
                throw new IllegalStateException("Got too much data");
            } else {
                int readable = Math.min(diff, in.remaining());
                in.get(buffer, idx, readable);
                idx += readable;
                return readable == diff;
            }
        }
    }

    @Override
    public RespType finish() {
        if (stringLength < 0) {
// Path: src/main/java/jresp/RespDecoder.java
// public class RespDecoder {
// 
//     private SimpleStrState simpleStrDecoder = new SimpleStrState();
//     private ErrState errDecoder = new ErrState();
//     private IntState intDecoder = new IntState();
//     private BulkStrState bulkStrDecoder;
// 
//     private State state = null;
// 
//     RespDecoder() {
//         bulkStrDecoder = new BulkStrState(this);
//     }
// 
//     protected void decode(ByteBuffer in, Consumer<RespType> out) {
//         while (true) {
//             int availableBytes = in.remaining();
//             if (availableBytes == 0) {
//                 //
//                 // We need more bytes
//                 //
//                 break;
//             }
// 
//             if (state == null) {
//                 //
//                 // There is no current state, so read the next byte
//                 //
//                 char nextChar = (char) in.get();
//                 state = nextState(nextChar);
//             }
//             if (state.decode(in)) {
//                 out.accept(state.finish());
//                 state = null;
//             } else {
//                 //
//                 // We need more bytes
//                 //
//                 break;
//             }
//         }
//     }
// 
//     public State nextState(char token) {
//         switch (token) {
//             case '+':
//                 return simpleStrDecoder.reset();
//             case '-':
//                 return errDecoder.reset();
//             case ':':
//                 return intDecoder.reset();
//             case '$':
//                 return bulkStrDecoder.reset();
//             case '*':
//                 return new AryState(this);
//             default:
//                 throw new IllegalStateException(String.format("Unknown token %s", token));
//         }
//     }
// 
//     public IntState intDecoder() {
//         return (IntState)intDecoder.reset();
//     }
// }
// 
// Path: src/main/java/jresp/protocol/BulkStr.java
// public class BulkStr implements RespType {
//     private static final Map<String, BulkStr> cache = Collections.synchronizedMap(new HashMap<>());
// 
//     private byte[] payload;
// 
//     public BulkStr(String s) {
//         try {
//             payload = s.getBytes("UTF-8");
//         } catch (UnsupportedEncodingException e) {
//             throw new IllegalStateException(e);
//         }
//     }
// 
//     public BulkStr(byte[] s) {
//         payload = s;
//     }
// 
//     public BulkStr() {
//         this.payload = null;
//     }
// 
//     public static BulkStr get(String str) {
//         BulkStr val = cache.get(str);
//         if (val == null) {
//             val = new BulkStr(str);
//             cache.put(str, val);
//         }
//         return val;
//     }
// 
//     public String toString() {
//         return String.format("%s[%s]", getClass().getName(), Arrays.toString(payload));
//     }
// 
//     @Override
//     public void writeBytes(Deque<ByteBuffer> out) {
//         int size = 1;
//         byte[] header;
//         if (payload == null) {
//             header = Resp.longToByteArray(-1);
//         } else {
//             header = Resp.longToByteArray(payload.length);
//             size += 2 + payload.length;
//         }
//         size += 2 + header.length;
// 
//         ByteBuffer o = Resp.buffer(out, size);
//         o.put((byte)'$');
//         o.put(header);
//         if (payload != null) {
//             o.put(Resp.CRLF);
//             o.put(payload);
//         }
//         o.put(Resp.CRLF);
//     }
// 
//     public byte[] raw() {
//         return payload;
//     }
// 
//     @Override
//     public Object unwrap() {
//         if (payload == null) {
//             return null;
//         }
//         try {
//             return new String(payload, "UTF-8");
//         } catch (UnsupportedEncodingException e) {
//             throw new IllegalStateException(e);
//         }
//     }
// 
//     @Override
//     public int hashCode() {
//         return Arrays.hashCode(payload);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (o instanceof BulkStr) {
//             BulkStr bs = (BulkStr)o;
//             return Arrays.equals(payload, bs.payload);
//         } else {
//             return false;
//         }
//     }
// }
// 
// Path: src/main/java/jresp/protocol/RespType.java
// public interface RespType {
//     /**
//      * Write the RESP form to the ByteBuf
//      */
//     void writeBytes(Deque<ByteBuffer> out);
// 
//     /**
//      * Return the high-level Java equivalent.
//      */
//     Object unwrap();
// }


// Path: src/main/java/jresp/state/BulkStrState.java
import jresp.RespDecoder;
import jresp.protocol.BulkStr;
import jresp.protocol.RespType;
import java.nio.ByteBuffer;

                 } else {
                     stringLength = (int)(len + 2); // To account for CRLF
                 }
             } else {
                 return false;
             }
        }
        if (stringLength < 0) {
            return true;
        } else {
            if (buffer == null || buffer.length < stringLength) {
                buffer = new byte[stringLength];
            }
            int diff = stringLength - idx;
            if (diff == 0) {
                return true;
            } else if (diff < 0) {
                throw new IllegalStateException("Got too much data");
            } else {
                int readable = Math.min(diff, in.remaining());
                in.get(buffer, idx, readable);
                idx += readable;
                return readable == diff;
            }
        }
    }

    @Override
    public RespType finish() {
        if (stringLength < 0) {
            return new BulkStr();