Prototype simple map decoder
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 4c641ae..44e11fd 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -923,6 +923,19 @@
 QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
 
 
+
+typedef QCBORError (*MapCB)(void *pCBCtx, QCBORDecodeContext *pDecodeCtx, QCBORItem *pDecodedItem);
+
+typedef struct {
+   int64_t nLabel;
+   uint8_t uType;
+   MapCB   pCB;
+} MCB;
+
+
+QCBORError QCBORDecode_Mappie(QCBORDecodeContext *pCtx, uint16_t uMapSize, const MCB *pCBList, void *pCBCtx, UsefulBuf DupDetectionBuffer);
+
+
 /**
  * @brief Get the next item, fully consuming it if it is a map or array.
  *
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 8217073..4b6fbd2 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -2811,6 +2811,74 @@
 }
 
 
+QCBORError
+QCBORDecode_Mappie(QCBORDecodeContext *pMe,
+                   const uint16_t      uMapSize,
+                   const MCB          *pCBList,
+                   void               *pCBCtx,
+                   const UsefulBuf     DupDetection)
+{
+   QCBORItem  Item;
+   QCBORError uErr;
+
+   if(!UsefulBuf_IsNULL(DupDetection)) {
+      if(DupDetection.len < uMapSize * sizeof(int64_t)) {
+         /* Dup detection buffer too small*/
+         return 888;
+      }
+   }
+
+   /* Loop over items */
+   for(int xx = 0; xx< uMapSize; xx++) {
+      uErr = QCBORDecode_GetNext(pMe, &Item);
+      if(uErr) {
+         goto Done;
+      }
+
+      if(Item.uLabelType != QCBOR_TYPE_INT64) {
+         /* Only works on integer labels */
+         // TODO: proper error code
+         return 99;
+      }
+
+      /* Duplicate detection if caller supplied a buffer */
+      if(!UsefulBuf_IsNULL(DupDetection)) {
+         for(int j = 0; j < xx; j++) {
+            if(((int64_t *)DupDetection.ptr)[xx] == Item.label.int64) {
+               /* Found a duplicate */
+               return 777;
+            }
+         }
+
+         ((int64_t *)DupDetection.ptr)[xx] = Item.label.int64;
+      }
+
+      /* Loop over CB's looking for label */
+      for(int i = 0 ; pCBList[i].pCB != NULL; i++) {
+
+         if(pCBList[i].nLabel == Item.label.int64) {
+            if(pCBList[i].uType != Item.uDataType &&
+               pCBList[i].uType != QCBOR_TYPE_ANY) {
+               uErr = QCBOR_ERR_UNEXPECTED_TYPE;
+               goto Done;
+            }
+
+            /* Matched label, make call back */
+            uErr = (*pCBList[i].pCB)(pCBCtx, pMe, &Item);
+            if(uErr) {
+               goto Done;
+            }
+            break; /* First callback for label wins */
+         }
+      }
+   }
+   uErr = QCBOR_SUCCESS;
+
+Done:
+   return uErr;
+}
+
+
 
 /* Call only on maps and arrays. Rewinds the cursor
  * to the start as if it was just entered.
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index edb0861..8e4212f 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -6070,7 +6070,7 @@
 
    uCBORError = QCBORDecode_Finish(&DCtx);
 
-   return uCBORError;
+   return (int32_t)uCBORError;
 }
 
 int32_t CBORSequenceDecodeTests(void)
@@ -7901,3 +7901,82 @@
 
    return 0;
 }
+
+
+
+/*
+ {1: "hi", 2: 42, 3: 3.14}
+ */
+
+static const uint8_t spMappieT[] = {0xA3, 0x01, 0x62, 0x68, 0x69, 0x02, 0x18, 0x2A, 0x03, 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F};
+
+struct MappieTest {
+   UsefulBufC   Text;
+   int64_t      Int;
+   double       Float;
+};
+
+
+
+static QCBORError
+DecodeOne(void *pCBCtx, QCBORDecodeContext *pDCtx, QCBORItem *Item)
+{
+   struct MappieTest *pMt = (struct MappieTest *)pCBCtx;
+
+   pMt->Text = Item->val.string;
+
+   return 0;
+}
+
+static QCBORError
+DecodeTwo(void *pCBCtx, QCBORDecodeContext *pDCtx, QCBORItem *Item)
+{
+   struct MappieTest *pMt = (struct MappieTest *)pCBCtx;
+
+   pMt->Int = Item->val.int64;
+
+   return 0;
+}
+
+static QCBORError
+DecodeThree(void *pCBCtx, QCBORDecodeContext *pDCtx, QCBORItem *Item)
+{
+   struct MappieTest *pMt = (struct MappieTest *)pCBCtx;
+
+   pMt->Float = Item->val.dfnum;
+
+   return 0;
+}
+
+
+int32_t MappieTest(void)
+{
+   QCBORDecodeContext DC;
+   QCBORItem          Item;
+   QCBORError         uErr;
+   MakeUsefulBufOnStack(DupDetect, (sizeof(int64_t) * 4));
+
+   struct MappieTest  MT;
+
+   MCB MM[] = {
+      {1, QCBOR_TYPE_TEXT_STRING, &DecodeOne},
+      {2, QCBOR_TYPE_INT64, &DecodeTwo},
+      {3, QCBOR_TYPE_DOUBLE, &DecodeThree},
+      {0, QCBOR_TYPE_NONE, NULL}
+   };
+
+
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMappieT), 0);
+
+   QCBORDecode_GetNext(&DC, &Item);
+
+   uErr = QCBORDecode_Mappie(&DC, Item.val.uCount, MM, &MT, DupDetect);
+
+   uErr = QCBORDecode_Finish(&DC);
+
+   if(MT.Int != 42) {
+      return 99;
+   }
+
+   return 0;
+}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index 11fdc94..847039c 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -318,4 +318,9 @@
 */
 int32_t CBORTestIssue134(void);
 
+
+
+int32_t MappieTest(void);
+
+
 #endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/test/run_tests.c b/test/run_tests.c
index 54cd883..b471731 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -66,6 +66,7 @@
 
 
 static test_entry s_tests[] = {
+    TEST_ENTRY(MappieTest),
     TEST_ENTRY(OpenCloseBytesTest),
     TEST_ENTRY(EnterBstrTest),
     TEST_ENTRY(IntegerConvertTest),