first version of peek next
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 1033871..81636f0 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -866,6 +866,28 @@
 
 
 /**
+ @brief Get the next data item without consuming it.
+
+ @param[in]  pCtx          The decoder context.
+ @param[out] pDecodedItem  Holds the CBOR item just decoded.
+
+ This is the same as QCBORDecode_GetNext() but does not consume
+ the data item. This only looks ahead one item. Calling it
+ repeatedly will just return the same item over and over.
+
+ This uses a lot of stack, far more than anything else
+ here in qcbor_decode.h because it saves a copy of most of
+ the decode context temporarily.
+
+ This is useful for looking ahead to determine the type
+ of a data item to know which type-specific spiffy decode
+ function to call. 
+ */
+QCBORError
+QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
+
+
+/**
  @brief Gets the next item including full list of tags for item.
 
  @param[in]  pCtx          The decoder context.
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 001a778..afc3651 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -2030,6 +2030,9 @@
 }
 
 
+/*
+ Public function, see header qcbor/qcbor_decode.h file
+ */
 QCBORError
 QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
 {
@@ -2046,6 +2049,24 @@
 /*
  Public function, see header qcbor/qcbor_decode.h file
  */
+QCBORError
+QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
+{
+   const QCBORDecodeNesting SaveNesting = pMe->nesting;
+   const UsefulInputBuf Save = pMe->InBuf;
+
+   QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
+
+   pMe->nesting = SaveNesting;
+   pMe->InBuf = Save;
+
+   return uErr;
+}
+
+
+/*
+ Public function, see header qcbor/qcbor_decode.h file
+ */
 void QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
 {
    if(pMe->uLastError != QCBOR_SUCCESS) {
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index edcaad7..70fd3b1 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -6586,3 +6586,206 @@
 
    return 0;
 }
+
+
+
+
+int32_t PeekTest()
+{
+   QCBORItem          Item;
+   QCBORError         nCBORError;
+   QCBORDecodeContext DCtx;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return 100+(int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 200;
+   }
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 300;
+   }
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return 400 + (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 500;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 600;
+   }
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return 900 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 42 ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+      return 1000;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 1100 + (int32_t)nCBORError;
+   }
+
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 42 ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+      return 1200;
+   }
+
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 1300 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+      Item.uDataType != QCBOR_TYPE_ARRAY ||
+      Item.val.uCount != 2)
+      return 1400;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 1500 + (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string1")) {
+      return 1600;
+   }
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return 1700 + (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string2")) {
+      return 1800;
+   }
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string2")) {
+      return 1900;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string2")) {
+      return 2000;
+   }
+
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 2100 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.label.string, "map in a map") ||
+      Item.uDataType != QCBOR_TYPE_MAP ||
+      Item.val.uCount != 4) {
+      return 2100;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 2200 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "xxxx")) {
+      return 2300;
+   }
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return 2400 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBufCompareToSZ(Item.label.string, "bytes 2") ||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "yyyy")) {
+      return 2500;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 2600 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBufCompareToSZ(Item.label.string, "bytes 2") ||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "yyyy")) {
+      return 2700;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 2800 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.label.string, "another int") ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 98)
+      return 2900;
+
+   if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
+      return 3000 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) {
+      return 3100;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 3200 + (int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) {
+      return 3300;
+   }
+
+   return 0;
+}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index 3cbb82d..7e11e35 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -298,4 +298,11 @@
 int32_t SpiffyIndefiniteLengthStringsTests(void);
 
 
+/*
+ Test PeekNext().
+ */
+int32_t PeekTest(void);
+
+
+
 #endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/test/run_tests.c b/test/run_tests.c
index 0383b21..aa42013 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -118,6 +118,7 @@
     TEST_ENTRY(CBORSequenceDecodeTests),
     TEST_ENTRY(IntToTests),
     TEST_ENTRY(DecodeTaggedTypeTests),
+    TEST_ENTRY(PeekTest),
 #ifndef     QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
     TEST_ENTRY(EncodeLengthThirtyoneTest),
     TEST_ENTRY(ExponentAndMantissaDecodeTests),