This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git

commit 48dc5688d5aa51d668434237c665685884f83ae5
Author: Andrew Stitcher <[email protected]>
AuthorDate: Mon Jul 20 13:47:49 2026 -0400

    PROTON-2954: Slim down pn_data_t memory use
    
    Reduce the per node memory cost from 72 bytes to 24 bytes (⅓ what it was)
    so that even complex AMQP values representions use much less memory.
---
 c/src/core/codec.c   | 402 +++++++++++++++++++++++++--------------------------
 c/src/core/data.h    |  95 ++++++++++--
 c/src/core/encoder.c | 146 +++++++++----------
 3 files changed, 353 insertions(+), 290 deletions(-)

diff --git a/c/src/core/codec.c b/c/src/core/codec.c
index 08ede0c6a..3745ab71b 100644
--- a/c/src/core/codec.c
+++ b/c/src/core/codec.c
@@ -75,12 +75,6 @@ const char *pn_type_name(pn_type_t type)
   return "<UNKNOWN>";
 }
 
-static inline void pni_atom_init(pn_atom_t *atom, pn_type_t type)
-{
-  memset(atom, 0, sizeof(pn_atom_t));
-  atom->type = type;
-}
-
 // data
 
 static void pn_data_finalize(void *object)
@@ -94,16 +88,16 @@ static void pn_data_finalize(void *object)
 static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
 {
   if (!node) return NULL;
-  if (node->atom.type != PN_DESCRIBED) return NULL;
+  if (node->type != PN_DESCRIBED) return NULL;
 
   pni_node_t *descriptor = pn_data_node(data, node->down);
 
-  if (!descriptor || descriptor->atom.type != PN_ULONG) {
+  if (!descriptor || descriptor->type != PN_ULONG) {
     return NULL;
   }
 
-  if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong 
<= FIELD_MAX) {
-    const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN];
+  if (descriptor->u.as_ulong >= FIELD_MIN && descriptor->u.as_ulong <= 
FIELD_MAX) {
+    const pn_fields_t *f = &FIELDS[descriptor->u.as_ulong-FIELD_MIN];
     return (f->name_index!=0) ? f : NULL;
   } else {
     return NULL;
@@ -272,7 +266,6 @@ static int pni_node_lindex(pn_data_t *data, pni_node_t 
*node)
 int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
 {
   pn_fixed_string_t *str = (pn_fixed_string_t *) ctx;
-  pn_atom_t *atom = (pn_atom_t *) &node->atom;
 
   pni_node_t *parent = pn_data_node(data, node->parent);
   const pn_fields_t *fields = pni_node_fields(data, parent);
@@ -280,7 +273,7 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, 
pni_node_t *node)
   const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
 
   if (grandfields) {
-    if (atom->type == PN_NULL) {
+    if (node->type == PN_NULL) {
       return 0;
     }
     pni_nid_t lindex = pni_node_lindex(data, node);
@@ -292,13 +285,13 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, 
pni_node_t *node)
     }
   }
 
-  switch (atom->type) {
+  switch (node->type) {
   case PN_DESCRIBED:
     pn_fixed_string_addf(str, "@");
     return 0;
   case PN_ARRAY:
     // XXX: need to fix for described arrays
-    pn_fixed_string_addf(str, "@%s[", pn_type_name(node->type));
+    pn_fixed_string_addf(str, "@%s[", pn_type_name(node->u.as_array.type));
     return 0;
   case PN_LIST:
     pn_fixed_string_addf(str, "[");
@@ -306,25 +299,42 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, 
pni_node_t *node)
   case PN_MAP:
     pn_fixed_string_addf(str, "{");
     return 0;
-  default:
+  default: {
+    pn_rwbytes_t buf = (data->buf) ? pn_buffer_memory(data->buf) : 
(pn_rwbytes_t){0};
+    pn_atom_t tmp = {node->type};
+    switch (node->type) {
+    case PN_BINARY: case PN_STRING: case PN_SYMBOL:
+      tmp.u.as_bytes = (pn_bytes_t){ node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset };
+      break;
+    case PN_DECIMAL128:
+      memcpy(tmp.u.as_decimal128.bytes, buf.start + node->u.as_bytes.offset, 
16);
+      break;
+    case PN_UUID:
+      memcpy(tmp.u.as_uuid.bytes, buf.start + node->u.as_bytes.offset, 16);
+      break;
+    default:
+      memcpy(&tmp.u, &node->u, sizeof(node->u));
+      break;
+    }
     if (fields && node->prev == 0) {
       pn_fixed_string_addf(str, "%s", (const char 
*)FIELD_STRINGPOOL.STRING0+FIELD_NAME[fields->name_index]);
       pn_fixed_string_addf(str, "(");
-      pni_inspect_atom(atom, str);
+      pni_inspect_atom(&tmp, str);
       pn_fixed_string_addf(str, ")");
       return 0;
     } else {
-      pni_inspect_atom(atom, str);
+      pni_inspect_atom(&tmp, str);
       return 0;
     }
   }
+  }
 }
 
 pni_node_t *pni_next_nonnull(pn_data_t *data, pni_node_t *node)
 {
   while (node) {
     node = pn_data_node(data, node->next);
-    if (node && node->atom.type != PN_NULL) {
+    if (node && node->type != PN_NULL) {
       return node;
     }
   }
@@ -336,7 +346,7 @@ int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t 
*node)
 {
   pn_fixed_string_t *str = (pn_fixed_string_t *) ctx;
 
-  switch (node->atom.type) {
+  switch (node->type) {
   case PN_ARRAY:
   case PN_LIST:
     pn_fixed_string_addf(str, "]");
@@ -351,11 +361,11 @@ int pni_inspect_exit(void *ctx, pn_data_t *data, 
pni_node_t *node)
   pni_node_t *parent = pn_data_node(data, node->parent);
   pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
   const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
-  if (!grandfields || node->atom.type != PN_NULL) {
+  if (!grandfields || node->type != PN_NULL) {
     if (node->next) {
-      if (parent && parent->atom.type == PN_MAP && (pni_node_lindex(data, 
node) % 2) == 0) {
+      if (parent && parent->type == PN_MAP && (pni_node_lindex(data, node) % 
2) == 0) {
         pn_fixed_string_addf(str, "=");
-      } else if (parent && parent->atom.type == PN_DESCRIBED && node->prev == 
0) {
+      } else if (parent && parent->type == PN_DESCRIBED && node->prev == 0) {
         pn_fixed_string_addf(str, " ");
       } else {
         if (!grandfields || pni_next_nonnull(data, node)) {
@@ -497,54 +507,19 @@ static ssize_t pni_data_intern(pn_data_t *data, const 
char *start, size_t size)
   return offset;
 }
 
-static pn_bytes_t *pni_data_bytes(pn_data_t *data, pni_node_t *node)
-{
-  switch (node->atom.type) {
-  case PN_BINARY:
-  case PN_STRING:
-  case PN_SYMBOL:
-    return &node->atom.u.as_bytes;
-  default: return NULL;
-  }
-}
-
-static void pni_data_rebase(pn_data_t *data, char *base)
+static int pni_data_intern_node(pn_data_t *data, pni_node_t *node, pn_bytes_t 
bytes)
 {
-  for (unsigned i = 0; i < data->size; i++) {
-    pni_node_t *node = &data->nodes[i];
-    if (node->data) {
-      pn_bytes_t *bytes = pni_data_bytes(data, node);
-      bytes->start = base + node->data_offset;
-    }
-  }
-}
-
-static int pni_data_intern_node(pn_data_t *data, pni_node_t *node)
-{
-  pn_bytes_t *bytes = pni_data_bytes(data, node);
-  if (!bytes) return 0;
   if (data->buf == NULL) {
-    // Heuristic to avoid growing small buffers too much
-    // size + 1 to allow for zero termination
-    size_t size = pn_max(bytes->size+1, PNI_INTERN_MINSIZE);
+    size_t size = pn_max(bytes.size+1, PNI_INTERN_MINSIZE);
     data->buf = pn_buffer(size);
   }
-  size_t oldcap = pn_buffer_capacity(data->buf);
-  ssize_t offset = pni_data_intern(data, bytes->start, bytes->size);
+  ssize_t offset = pni_data_intern(data, bytes.start, bytes.size);
   if (offset < 0) {
     pn_error_set(pni_data_error(data), PN_OUT_OF_MEMORY, "pn_data string 
buffer limit exceeded");
     return offset;
   }
-  node->data = true;
-  node->data_offset = offset;
-  node->data_size = bytes->size;
-  pn_rwbytes_t buf = pn_buffer_memory(data->buf);
-  bytes->start = buf.start + offset;
-
-  if (pn_buffer_capacity(data->buf) != oldcap) {
-    pni_data_rebase(data, buf.start);
-  }
-
+  node->u.as_bytes.offset = (uint32_t) offset;
+  node->u.as_bytes.size   = (uint32_t) bytes.size;
   return 0;
 }
 
@@ -720,8 +695,8 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list 
ap)
     case 'T':                   /* Set type of open array */
       {
         pni_node_t *parent = pn_data_node(data, data->parent);
-        if (parent->atom.type == PN_ARRAY) {
-          parent->type = (pn_type_t) va_arg(ap, int);
+        if (parent->type == PN_ARRAY) {
+          parent->u.as_array.type = (uint8_t) va_arg(ap, int);
         } else {
           return pn_error_format(pni_data_error(data), PN_ERR, "naked type");
         }
@@ -831,12 +806,12 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, 
va_list ap)
     pni_node_t *parent = pn_data_node(data, data->parent);
     pni_node_t *current = pn_data_node(data, data->current);
     while (parent) {
-      if (parent->atom.type == PN_DESCRIBED && parent->children == 2) {
-        current->described = true;
+      if (parent->type == PN_DESCRIBED && parent->children == 2) {
+        current->u.as_list.described = true;
         pn_data_exit(data);
         current = pn_data_node(data, data->current);
         parent = pn_data_node(data, data->parent);
-      } else if (parent->atom.type == PN_NULL && parent->children == 1) {
+      } else if (parent->type == PN_NULL && parent->children == 1) {
         pn_data_exit(data);
         current = pn_data_node(data, data->current);
         current->down = 0;
@@ -870,7 +845,7 @@ static bool pn_scan_next(pn_data_t *data, pn_type_t *type, 
bool suspend)
     return true;
   } else {
     pni_node_t *parent = pn_data_node(data, data->parent);
-    if (parent && parent->atom.type == PN_DESCRIBED) {
+    if (parent && parent->type == PN_DESCRIBED) {
       pn_data_exit(data);
       return pn_scan_next(data, type, suspend);
     } else {
@@ -1222,7 +1197,7 @@ int pn_data_vscan(pn_data_t *data, const char *fmt, 
va_list ap)
         if (!suspend) {
           size_t old = pn_data_size(dst);
           pni_node_t *next = pni_data_peek(data);
-          if (next && next->atom.type != PN_NULL) {
+          if (next && next->type != PN_NULL) {
             pn_data_narrow(data);
             int err = pn_data_appendn(dst, data, 1);
             pn_data_widen(data);
@@ -1243,8 +1218,8 @@ int pn_data_vscan(pn_data_t *data, const char *fmt, 
va_list ap)
         pn_atom_t *dst = va_arg(ap, pn_atom_t *);
         if (!suspend) {
           pni_node_t *next = pni_data_peek(data);
-          if (next && next->atom.type != PN_NULL) {
-            *dst = next->atom;
+          if (next && next->type != PN_NULL) {
+            *dst = pn_data_get_atom(data);
           } else {
             scanned = false;
           }
@@ -1462,7 +1437,7 @@ pn_type_t pn_data_type(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
   if (node) {
-    return node->atom.type;
+    return node->type;
   } else {
     return PN_INVALID;
   }
@@ -1472,7 +1447,7 @@ pn_type_t pni_data_parent_type(pn_data_t *data)
 {
   pni_node_t *node = pn_data_node(data, data->parent);
   if (node) {
-    return node->atom.type;
+    return node->type;
   } else {
     return PN_INVALID;
   }
@@ -1545,7 +1520,12 @@ void pn_data_dump(pn_data_t *data)
   {
     pni_node_t *node = &data->nodes[i];
     pn_fixed_string_t str = pn_fixed_string(buf, sizeof(buf));
-    pni_inspect_atom((pn_atom_t *) &node->atom, &str);
+    /* synthesise a tmp atom for debug display */
+    pn_handle_t saved = pn_data_point(data);
+    data->current = pni_data_id(data, node);
+    pn_atom_t tmp = pn_data_get_atom(data);
+    pn_data_restore(data, saved);
+    pni_inspect_atom(&tmp, &str);
     pn_fixed_string_terminate(&str);
     printf("Node %u: prev=%" PN_ZU ", next=%" PN_ZU ", parent=%" PN_ZU ", 
down=%" PN_ZU
            ", children=%" PN_ZU ", type=%s (%s)\n",
@@ -1554,7 +1534,7 @@ void pn_data_dump(pn_data_t *data)
            (size_t) node->parent,
            (size_t) node->down,
            (size_t) node->children,
-           pn_type_name(node->atom.type), buf);
+           pn_type_name(node->type), buf);
   }
 }
 
@@ -1610,10 +1590,7 @@ static pni_node_t *pni_data_add(pn_data_t *data)
 
   node->down = 0;
   node->children = 0;
-  node->data = false;
-  node->described = false;
-  node->data_offset = 0;
-  node->data_size = 0;
+  memset(&node->u, 0, sizeof(node->u));
   data->current = pni_data_id(data, node);
   return node;
 }
@@ -1649,7 +1626,8 @@ int pn_data_put_list(pn_data_t *data)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_LIST;
+  node->type = PN_LIST;
+  node->u.as_list.described = false;
   return 0;
 }
 
@@ -1657,7 +1635,7 @@ int pn_data_put_map(pn_data_t *data)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_MAP;
+  node->type = PN_MAP;
   return 0;
 }
 
@@ -1665,23 +1643,23 @@ int pn_data_put_array(pn_data_t *data, bool described, 
pn_type_t type)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_ARRAY;
-  node->described = described;
-  node->type = type;
+  node->type = PN_ARRAY;
+  node->u.as_array.described = described;
+  node->u.as_array.type = (uint8_t) type;
   return 0;
 }
 
 void pni_data_set_array_type(pn_data_t *data, pn_type_t type)
 {
   pni_node_t *array = pni_data_current(data);
-  if (array) array->type = type;
+  if (array) array->u.as_array.type = (uint8_t) type;
 }
 
 int pn_data_put_described(pn_data_t *data)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DESCRIBED;
+  node->type = PN_DESCRIBED;
   return 0;
 }
 
@@ -1689,7 +1667,7 @@ int pn_data_put_null(pn_data_t *data)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  pni_atom_init(&node->atom, PN_NULL);
+  node->type = PN_NULL;
   return 0;
 }
 
@@ -1697,8 +1675,8 @@ int pn_data_put_bool(pn_data_t *data, bool b)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_BOOL;
-  node->atom.u.as_bool = b;
+  node->type = PN_BOOL;
+  node->u.as_bool = b;
   return 0;
 }
 
@@ -1706,8 +1684,8 @@ int pn_data_put_ubyte(pn_data_t *data, uint8_t ub)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_UBYTE;
-  node->atom.u.as_ubyte = ub;
+  node->type = PN_UBYTE;
+  node->u.as_ubyte = ub;
   return 0;
 }
 
@@ -1715,8 +1693,8 @@ int pn_data_put_byte(pn_data_t *data, int8_t b)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_BYTE;
-  node->atom.u.as_byte = b;
+  node->type = PN_BYTE;
+  node->u.as_byte = b;
   return 0;
 }
 
@@ -1724,8 +1702,8 @@ int pn_data_put_ushort(pn_data_t *data, uint16_t us)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_USHORT;
-  node->atom.u.as_ushort = us;
+  node->type = PN_USHORT;
+  node->u.as_ushort = us;
   return 0;
 }
 
@@ -1733,8 +1711,8 @@ int pn_data_put_short(pn_data_t *data, int16_t s)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_SHORT;
-  node->atom.u.as_short = s;
+  node->type = PN_SHORT;
+  node->u.as_short = s;
   return 0;
 }
 
@@ -1742,8 +1720,8 @@ int pn_data_put_uint(pn_data_t *data, uint32_t ui)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_UINT;
-  node->atom.u.as_uint = ui;
+  node->type = PN_UINT;
+  node->u.as_uint = ui;
   return 0;
 }
 
@@ -1751,8 +1729,8 @@ int pn_data_put_int(pn_data_t *data, int32_t i)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_INT;
-  node->atom.u.as_int = i;
+  node->type = PN_INT;
+  node->u.as_int = i;
   return 0;
 }
 
@@ -1760,8 +1738,8 @@ int pn_data_put_char(pn_data_t *data, pn_char_t c)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_CHAR;
-  node->atom.u.as_char = c;
+  node->type = PN_CHAR;
+  node->u.as_char = c;
   return 0;
 }
 
@@ -1769,8 +1747,8 @@ int pn_data_put_ulong(pn_data_t *data, uint64_t ul)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_ULONG;
-  node->atom.u.as_ulong = ul;
+  node->type = PN_ULONG;
+  node->u.as_ulong = ul;
   return 0;
 }
 
@@ -1778,8 +1756,8 @@ int pn_data_put_long(pn_data_t *data, int64_t l)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_LONG;
-  node->atom.u.as_long = l;
+  node->type = PN_LONG;
+  node->u.as_long = l;
   return 0;
 }
 
@@ -1787,8 +1765,8 @@ int pn_data_put_timestamp(pn_data_t *data, pn_timestamp_t 
t)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_TIMESTAMP;
-  node->atom.u.as_timestamp = t;
+  node->type = PN_TIMESTAMP;
+  node->u.as_timestamp = t;
   return 0;
 }
 
@@ -1796,8 +1774,8 @@ int pn_data_put_float(pn_data_t *data, float f)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_FLOAT;
-  node->atom.u.as_float = f;
+  node->type = PN_FLOAT;
+  node->u.as_float = f;
   return 0;
 }
 
@@ -1805,8 +1783,8 @@ int pn_data_put_double(pn_data_t *data, double d)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DOUBLE;
-  node->atom.u.as_double = d;
+  node->type = PN_DOUBLE;
+  node->u.as_double = d;
   return 0;
 }
 
@@ -1814,8 +1792,8 @@ int pn_data_put_decimal32(pn_data_t *data, pn_decimal32_t 
d)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DECIMAL32;
-  node->atom.u.as_decimal32 = d;
+  node->type = PN_DECIMAL32;
+  node->u.as_decimal32 = d;
   return 0;
 }
 
@@ -1823,8 +1801,8 @@ int pn_data_put_decimal64(pn_data_t *data, pn_decimal64_t 
d)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DECIMAL64;
-  node->atom.u.as_decimal64 = d;
+  node->type = PN_DECIMAL64;
+  node->u.as_decimal64 = d;
   return 0;
 }
 
@@ -1832,59 +1810,70 @@ int pn_data_put_decimal128(pn_data_t *data, 
pn_decimal128_t d)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DECIMAL128;
-  memmove(node->atom.u.as_decimal128.bytes, d.bytes, 16);
-  return 0;
+  node->type = PN_DECIMAL128;
+  return pni_data_intern_node(data, node, (pn_bytes_t){16, (const 
char*)d.bytes});
 }
 
 int pn_data_put_uuid(pn_data_t *data, pn_uuid_t u)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_UUID;
-  memmove(node->atom.u.as_uuid.bytes, u.bytes, 16);
-  return 0;
+  node->type = PN_UUID;
+  return pni_data_intern_node(data, node, (pn_bytes_t){16, (const 
char*)u.bytes});
 }
 
 int pn_data_put_binary(pn_data_t *data, pn_bytes_t bytes)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_BINARY;
-  node->atom.u.as_bytes = bytes;
-  return pni_data_intern_node(data, node);
+  node->type = PN_BINARY;
+  return pni_data_intern_node(data, node, bytes);
 }
 
 int pn_data_put_string(pn_data_t *data, pn_bytes_t string)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_STRING;
-  node->atom.u.as_bytes = string;
-  return pni_data_intern_node(data, node);
+  node->type = PN_STRING;
+  return pni_data_intern_node(data, node, string);
 }
 
 int pn_data_put_symbol(pn_data_t *data, pn_bytes_t symbol)
 {
   pni_node_t *node = pni_data_add(data);
   if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_SYMBOL;
-  node->atom.u.as_bytes = symbol;
-  return pni_data_intern_node(data, node);
+  node->type = PN_SYMBOL;
+  return pni_data_intern_node(data, node, symbol);
 }
 
 int pn_data_put_atom(pn_data_t *data, pn_atom_t atom)
 {
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom = atom;
-  return pni_data_intern_node(data, node);
+  switch (atom.type) {
+  case PN_BINARY:  return pn_data_put_binary(data, atom.u.as_bytes);
+  case PN_STRING:  return pn_data_put_string(data, atom.u.as_bytes);
+  case PN_SYMBOL:  return pn_data_put_symbol(data, atom.u.as_bytes);
+  case PN_DECIMAL128: return pn_data_put_decimal128(data, 
atom.u.as_decimal128);
+  case PN_UUID:    return pn_data_put_uuid(data, atom.u.as_uuid);
+  default: {
+    pni_node_t *node = pni_data_add(data);
+    if (node == NULL) return PN_OUT_OF_MEMORY;
+    node->type = atom.type;
+    memcpy(&node->u, &atom.u, sizeof(node->u));
+    return 0;
+  }
+  }
+}
+
+static inline pn_bytes_t pni_node_bytes(pn_data_t *data, pni_node_t *node)
+{
+  pn_rwbytes_t buf = pn_buffer_memory(data->buf);
+  return (pn_bytes_t){ node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset };
 }
 
 size_t pn_data_get_list(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_LIST) {
+  if (node && node->type == PN_LIST) {
     return node->children;
   } else {
     return 0;
@@ -1894,7 +1883,7 @@ size_t pn_data_get_list(pn_data_t *data)
 size_t pn_data_get_map(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_MAP) {
+  if (node && node->type == PN_MAP) {
     return node->children;
   } else {
     return 0;
@@ -1904,8 +1893,8 @@ size_t pn_data_get_map(pn_data_t *data)
 size_t pn_data_get_array(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ARRAY) {
-    if (node->described) {
+  if (node && node->type == PN_ARRAY) {
+    if (node->u.as_array.described) {
       return node->children - 1;
     } else {
       return node->children;
@@ -1918,8 +1907,8 @@ size_t pn_data_get_array(pn_data_t *data)
 bool pn_data_is_array_described(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ARRAY) {
-    return node->described;
+  if (node && node->type == PN_ARRAY) {
+    return node->u.as_array.described;
   } else {
     return false;
   }
@@ -1928,8 +1917,8 @@ bool pn_data_is_array_described(pn_data_t *data)
 pn_type_t pn_data_get_array_type(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ARRAY) {
-    return node->type;
+  if (node && node->type == PN_ARRAY) {
+    return node->u.as_array.type;
   } else {
     return PN_INVALID;
   }
@@ -1938,20 +1927,20 @@ pn_type_t pn_data_get_array_type(pn_data_t *data)
 bool pn_data_is_described(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  return node && node->atom.type == PN_DESCRIBED;
+  return node && node->type == PN_DESCRIBED;
 }
 
 bool pn_data_is_null(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  return node && node->atom.type == PN_NULL;
+  return node && node->type == PN_NULL;
 }
 
 bool pn_data_get_bool(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_BOOL) {
-    return node->atom.u.as_bool;
+  if (node && node->type == PN_BOOL) {
+    return node->u.as_bool;
   } else {
     return false;
   }
@@ -1960,8 +1949,8 @@ bool pn_data_get_bool(pn_data_t *data)
 uint8_t pn_data_get_ubyte(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_UBYTE) {
-    return node->atom.u.as_ubyte;
+  if (node && node->type == PN_UBYTE) {
+    return node->u.as_ubyte;
   } else {
     return 0;
   }
@@ -1970,8 +1959,8 @@ uint8_t pn_data_get_ubyte(pn_data_t *data)
 int8_t pn_data_get_byte(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_BYTE) {
-    return node->atom.u.as_byte;
+  if (node && node->type == PN_BYTE) {
+    return node->u.as_byte;
   } else {
     return 0;
   }
@@ -1980,8 +1969,8 @@ int8_t pn_data_get_byte(pn_data_t *data)
 uint16_t pn_data_get_ushort(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_USHORT) {
-    return node->atom.u.as_ushort;
+  if (node && node->type == PN_USHORT) {
+    return node->u.as_ushort;
   } else {
     return 0;
   }
@@ -1990,8 +1979,8 @@ uint16_t pn_data_get_ushort(pn_data_t *data)
 int16_t pn_data_get_short(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_SHORT) {
-    return node->atom.u.as_short;
+  if (node && node->type == PN_SHORT) {
+    return node->u.as_short;
   } else {
     return 0;
   }
@@ -2000,8 +1989,8 @@ int16_t pn_data_get_short(pn_data_t *data)
 uint32_t pn_data_get_uint(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_UINT) {
-    return node->atom.u.as_uint;
+  if (node && node->type == PN_UINT) {
+    return node->u.as_uint;
   } else {
     return 0;
   }
@@ -2010,8 +1999,8 @@ uint32_t pn_data_get_uint(pn_data_t *data)
 int32_t pn_data_get_int(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_INT) {
-    return node->atom.u.as_int;
+  if (node && node->type == PN_INT) {
+    return node->u.as_int;
   } else {
     return 0;
   }
@@ -2020,8 +2009,8 @@ int32_t pn_data_get_int(pn_data_t *data)
 pn_char_t pn_data_get_char(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_CHAR) {
-    return node->atom.u.as_char;
+  if (node && node->type == PN_CHAR) {
+    return node->u.as_char;
   } else {
     return 0;
   }
@@ -2030,8 +2019,8 @@ pn_char_t pn_data_get_char(pn_data_t *data)
 uint64_t pn_data_get_ulong(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ULONG) {
-    return node->atom.u.as_ulong;
+  if (node && node->type == PN_ULONG) {
+    return node->u.as_ulong;
   } else {
     return 0;
   }
@@ -2040,8 +2029,8 @@ uint64_t pn_data_get_ulong(pn_data_t *data)
 int64_t pn_data_get_long(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_LONG) {
-    return node->atom.u.as_long;
+  if (node && node->type == PN_LONG) {
+    return node->u.as_long;
   } else {
     return 0;
   }
@@ -2050,8 +2039,8 @@ int64_t pn_data_get_long(pn_data_t *data)
 pn_timestamp_t pn_data_get_timestamp(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_TIMESTAMP) {
-    return node->atom.u.as_timestamp;
+  if (node && node->type == PN_TIMESTAMP) {
+    return node->u.as_timestamp;
   } else {
     return 0;
   }
@@ -2060,8 +2049,8 @@ pn_timestamp_t pn_data_get_timestamp(pn_data_t *data)
 float pn_data_get_float(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_FLOAT) {
-    return node->atom.u.as_float;
+  if (node && node->type == PN_FLOAT) {
+    return node->u.as_float;
   } else {
     return 0;
   }
@@ -2070,8 +2059,8 @@ float pn_data_get_float(pn_data_t *data)
 double pn_data_get_double(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DOUBLE) {
-    return node->atom.u.as_double;
+  if (node && node->type == PN_DOUBLE) {
+    return node->u.as_double;
   } else {
     return 0;
   }
@@ -2080,8 +2069,8 @@ double pn_data_get_double(pn_data_t *data)
 pn_decimal32_t pn_data_get_decimal32(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DECIMAL32) {
-    return node->atom.u.as_decimal32;
+  if (node && node->type == PN_DECIMAL32) {
+    return node->u.as_decimal32;
   } else {
     return 0;
   }
@@ -2090,8 +2079,8 @@ pn_decimal32_t pn_data_get_decimal32(pn_data_t *data)
 pn_decimal64_t pn_data_get_decimal64(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DECIMAL64) {
-    return node->atom.u.as_decimal64;
+  if (node && node->type == PN_DECIMAL64) {
+    return node->u.as_decimal64;
   } else {
     return 0;
   }
@@ -2100,30 +2089,28 @@ pn_decimal64_t pn_data_get_decimal64(pn_data_t *data)
 pn_decimal128_t pn_data_get_decimal128(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DECIMAL128) {
-    return node->atom.u.as_decimal128;
-  } else {
-    pn_decimal128_t t = {{0}};
-    return t;
+  pn_decimal128_t t = {{0}};
+  if (node && node->type == PN_DECIMAL128) {
+    memcpy(t.bytes, pni_node_bytes(data, node).start, 16);
   }
+  return t;
 }
 
 pn_uuid_t pn_data_get_uuid(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_UUID) {
-    return node->atom.u.as_uuid;
-  } else {
-    pn_uuid_t t = {{0}};
-    return t;
+  pn_uuid_t t = {{0}};
+  if (node && node->type == PN_UUID) {
+    memcpy(t.bytes, pni_node_bytes(data, node).start, 16);
   }
+  return t;
 }
 
 pn_bytes_t pn_data_get_binary(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_BINARY) {
-    return node->atom.u.as_bytes;
+  if (node && node->type == PN_BINARY) {
+    return pni_node_bytes(data, node);
   } else {
     pn_bytes_t t = {0};
     return t;
@@ -2133,8 +2120,8 @@ pn_bytes_t pn_data_get_binary(pn_data_t *data)
 pn_bytes_t pn_data_get_string(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_STRING) {
-    return node->atom.u.as_bytes;
+  if (node && node->type == PN_STRING) {
+    return pni_node_bytes(data, node);
   } else {
     pn_bytes_t t = {0};
     return t;
@@ -2144,8 +2131,8 @@ pn_bytes_t pn_data_get_string(pn_data_t *data)
 pn_bytes_t pn_data_get_symbol(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_SYMBOL) {
-    return node->atom.u.as_bytes;
+  if (node && node->type == PN_SYMBOL) {
+    return pni_node_bytes(data, node);
   } else {
     pn_bytes_t t = {0};
     return t;
@@ -2155,10 +2142,10 @@ pn_bytes_t pn_data_get_symbol(pn_data_t *data)
 pn_bytes_t pn_data_get_bytes(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node && (node->atom.type == PN_BINARY ||
-               node->atom.type == PN_STRING ||
-               node->atom.type == PN_SYMBOL)) {
-    return node->atom.u.as_bytes;
+  if (node && (node->type == PN_BINARY ||
+               node->type == PN_STRING ||
+               node->type == PN_SYMBOL)) {
+    return pni_node_bytes(data, node);
   } else {
     pn_bytes_t t = {0};
     return t;
@@ -2168,12 +2155,25 @@ pn_bytes_t pn_data_get_bytes(pn_data_t *data)
 pn_atom_t pn_data_get_atom(pn_data_t *data)
 {
   pni_node_t *node = pni_data_current(data);
-  if (node) {
-    return *((pn_atom_t *) &node->atom);
-  } else {
-    pn_atom_t t = {PN_NULL, {0,}};
-    return t;
+  if (!node) {
+    return (pn_atom_t){PN_NULL};
+  }
+  pn_atom_t t = {node->type};
+  switch (node->type) {
+  case PN_BINARY: case PN_STRING: case PN_SYMBOL:
+    t.u.as_bytes = pni_node_bytes(data, node);
+    break;
+  case PN_DECIMAL128:
+    memcpy(t.u.as_decimal128.bytes, pni_node_bytes(data, node).start, 16);
+    break;
+  case PN_UUID:
+    memcpy(t.u.as_uuid.bytes, pni_node_bytes(data, node).start, 16);
+    break;
+  default:
+    memcpy(&t.u, &node->u, sizeof(t.u));
+    break;
   }
+  return t;
 }
 
 int pn_data_copy(pn_data_t *data, pn_data_t *src)
diff --git a/c/src/core/data.h b/c/src/core/data.h
index 8b1f5a61e..946bb086d 100644
--- a/c/src/core/data.h
+++ b/c/src/core/data.h
@@ -31,21 +31,88 @@ typedef uint16_t pni_nid_t;
 #define PNI_NID_MAX ((pni_nid_t)-1)
 #define PNI_INTERN_MINSIZE 64
 
+/*
+ * Value payload for a pni_node_t.
+ *
+ * BINARY/STRING/SYMBOL/DECIMAL128/UUID nodes store their data in the intern
+ * buffer (data->buf); as_bytes.offset and as_bytes.size locate the bytes.
+ * DECIMAL128 and UUID always have as_bytes.size == 16.
+ *
+ * PN_ARRAY nodes use as_array: element type, whether the array has a
+ * descriptor child (described), and encoder scratch (start, small).
+ *
+ * PN_LIST nodes use as_list: whether the list is the body of a described
+ * value (controls trailing-null elision during encoding), and encoder
+ * scratch (start, small).
+ *
+ * PN_MAP nodes use as_map: encoder scratch (start, small).
+ *
+ * All other types (NULL, DESCRIBED) carry no payload; only the type tag
+ * on pni_node_t is meaningful.
+ */
+typedef union {
+  bool            as_bool;
+  uint8_t         as_ubyte;
+  int8_t          as_byte;
+  uint16_t        as_ushort;
+  int16_t         as_short;
+  uint32_t        as_uint;
+  int32_t         as_int;
+  uint32_t        as_char;        /* pn_char_t is typedef'd uint32_t */
+  uint64_t        as_ulong;
+  int64_t         as_long;
+  int64_t         as_timestamp;   /* pn_timestamp_t is typedef'd int64_t */
+  float           as_float;
+  double          as_double;
+  uint32_t        as_decimal32;
+  uint64_t        as_decimal64;
+  struct {
+    uint32_t      offset;         /* byte offset into data->buf */
+    uint32_t      size;           /* byte count (always 16 for 
decimal128/uuid) */
+  }               as_bytes;
+  struct {
+    uint32_t      start;          /* encoder scratch: output offset of size 
field */
+    bool          described;      /* true if first child is a descriptor */
+    uint8_t       type;           /* element type (pn_type_t fits in uint8_t: 
values 1-25) */
+    /* 2 implicit padding bytes */
+  }               as_array;
+  struct {
+    uint32_t      start;          /* encoder scratch: output offset of size 
field */
+    bool          described;      /* true if body of a described composite */
+    /* 3 implicit padding bytes */
+  }               as_list;
+  struct {
+    uint32_t      start;          /* encoder scratch: output offset of size 
field */
+    /* 4 implicit padding bytes */
+  }               as_map;
+} pni_node_payload_t;
+
+/*
+ * Layout (64-bit): 24 bytes.
+ *
+ *  offset  0  type        (4)  value type tag
+ *  offset  4  next        (2)  sibling link
+ *  offset  6  prev        (2)  sibling link
+ *  offset  8  down        (2)
+ *  offset 10  parent      (2)
+ *  offset 12  children    (2)
+ *  offset 14  <2 implicit alignment bytes before u>
+ *  offset 16  u           (8)  value payload (8-byte aligned)
+ *
+ * Note that there is still a bit of possibility to reduce this further:
+ * The type takes 4 bytes, but need only take 1; there is 2 bytes of padding 
still;
+ * I'm pretty sure that we could do away with one of the navigation links 
(having down
+ * and children seems redundant). However unless we can get it to 16 bytes 
there is
+ * little point as it must be 8 byte aligned anyway (because of the int64_t in 
the union).
+ */
 typedef struct {
-  size_t start;
-  size_t data_offset;
-  size_t data_size;
-  pn_atom_t atom;
-  pn_type_t type;
-  pni_nid_t next;
-  pni_nid_t prev;
-  pni_nid_t down;
-  pni_nid_t parent;
-  pni_nid_t children;
-  // for arrays
-  bool described;
-  bool data;
-  bool small;
+  pn_type_t           type;
+  pni_nid_t           next;
+  pni_nid_t           prev;
+  pni_nid_t           down;
+  pni_nid_t           parent;
+  pni_nid_t           children;
+  pni_node_payload_t  u;
 } pni_node_t;
 
 struct pn_data_t {
diff --git a/c/src/core/encoder.c b/c/src/core/encoder.c
index 97af8de16..b312fc4fb 100644
--- a/c/src/core/encoder.c
+++ b/c/src/core/encoder.c
@@ -84,61 +84,61 @@ static uint8_t pn_type2code(pn_encoder_t *encoder, 
pn_type_t type)
 
 static uint8_t pn_node2code(pn_encoder_t *encoder, pni_node_t *node)
 {
-  switch (node->atom.type) {
+  switch (node->type) {
   case PN_LONG:
-    if (-128 <= node->atom.u.as_long && node->atom.u.as_long <= 127) {
+    if (-128 <= node->u.as_long && node->u.as_long <= 127) {
       return PNE_SMALLLONG;
     } else {
       return PNE_LONG;
     }
   case PN_INT:
-    if (-128 <= node->atom.u.as_int && node->atom.u.as_int <= 127) {
+    if (-128 <= node->u.as_int && node->u.as_int <= 127) {
       return PNE_SMALLINT;
     } else {
       return PNE_INT;
     }
   case PN_ULONG:
-    if (node->atom.u.as_ulong == 0) {
+    if (node->u.as_ulong == 0) {
       return PNE_ULONG0;
-    } else if (node->atom.u.as_ulong < 256) {
+    } else if (node->u.as_ulong < 256) {
       return PNE_SMALLULONG;
     } else {
       return PNE_ULONG;
     }
   case PN_UINT:
-    if (node->atom.u.as_uint == 0) {
+    if (node->u.as_uint == 0) {
       return PNE_UINT0;
-    } else if (node->atom.u.as_uint < 256) {
+    } else if (node->u.as_uint < 256) {
       return PNE_SMALLUINT;
     } else {
       return PNE_UINT;
     }
   case PN_BOOL:
-    if (node->atom.u.as_bool) {
+    if (node->u.as_bool) {
       return PNE_TRUE;
     } else {
       return PNE_FALSE;
     }
   case PN_STRING:
-    if (node->atom.u.as_bytes.size < 256) {
+    if (node->u.as_bytes.size < 256) {
       return PNE_STR8_UTF8;
     } else {
       return PNE_STR32_UTF8;
     }
   case PN_SYMBOL:
-    if (node->atom.u.as_bytes.size < 256) {
+    if (node->u.as_bytes.size < 256) {
       return PNE_SYM8;
     } else {
       return PNE_SYM32;
     }
   case PN_BINARY:
-    if (node->atom.u.as_bytes.size < 256) {
+    if (node->u.as_bytes.size < 256) {
       return PNE_VBIN8;
     } else {
       return PNE_VBIN32;
     }
   default:
-    return pn_type2code(encoder, node->atom.type);
+    return pn_type2code(encoder, node->type);
   }
 }
 
@@ -225,23 +225,23 @@ static inline void pn_encoder_writev32(pn_encoder_t 
*encoder, const pn_bytes_t *
 
 /* True if node is an element of an array - not the descriptor. */
 static bool pn_is_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t 
*node) {
-  return (parent && parent->atom.type == PN_ARRAY) /* In array */
-    && !(parent->described && !node->prev); /* Not the descriptor */
+  return (parent && parent->type == PN_ARRAY) /* In array */
+    && !(parent->u.as_array.described && !node->prev); /* Not the descriptor */
 }
 
 /** True if node is the first element of an array, not the descriptor.
  *@pre pn_is_in_array(data, parent, node)
  */
 static bool pn_is_first_in_array(pn_data_t *data, pni_node_t *parent, 
pni_node_t *node) {
-  if (!node->prev) return !parent->described; /* First node */
-  return parent->described && (!pn_data_node(data, node->prev)->prev);
+  if (!node->prev) return !parent->u.as_array.described; /* First node */
+  return parent->u.as_array.described && (!pn_data_node(data, 
node->prev)->prev);
 }
 
 /** True if node is in a described list - not the descriptor.
  *  - In this case we can omit trailing nulls
  */
 static bool pn_is_in_described_list(pn_data_t *data, pni_node_t *parent, 
pni_node_t *node) {
-  return parent && parent->atom.type == PN_LIST && parent->described;
+  return parent && parent->type == PN_LIST && parent->u.as_list.described;
 }
 
 typedef union {
@@ -256,13 +256,12 @@ static int pni_encoder_enter(void *ctx, pn_data_t *data, 
pni_node_t *node)
 {
   pn_encoder_t *encoder = (pn_encoder_t *) ctx;
   pni_node_t *parent = pn_data_node(data, node->parent);
-  pn_atom_t *atom = &node->atom;
   uint8_t code;
   conv_t c;
 
   /** In an array we don't write the code before each element, only the first. 
*/
   if (pn_is_in_array(data, parent, node)) {
-    code = pn_type2code(encoder, parent->type);
+    code = pn_type2code(encoder, parent->u.as_array.type);
     if (pn_is_first_in_array(data, parent, node)) {
       pn_encoder_writef8(encoder, code);
     }
@@ -285,53 +284,57 @@ static int pni_encoder_enter(void *ctx, pn_data_t *data, 
pni_node_t *node)
     }
   }
 
+  pn_rwbytes_t buf = (data->buf) ? pn_buffer_memory(data->buf) : 
(pn_rwbytes_t){0};
   switch (code) {
   case PNE_DESCRIPTOR:
   case PNE_NULL:
   case PNE_TRUE:
   case PNE_FALSE: return 0;
-  case PNE_BOOLEAN: pn_encoder_writef8(encoder, atom->u.as_bool); return 0;
-  case PNE_UBYTE: pn_encoder_writef8(encoder, atom->u.as_ubyte); return 0;
-  case PNE_BYTE: pn_encoder_writef8(encoder, atom->u.as_byte); return 0;
-  case PNE_USHORT: pn_encoder_writef16(encoder, atom->u.as_ushort); return 0;
-  case PNE_SHORT: pn_encoder_writef16(encoder, atom->u.as_short); return 0;
+  case PNE_BOOLEAN: pn_encoder_writef8(encoder, node->u.as_bool); return 0;
+  case PNE_UBYTE: pn_encoder_writef8(encoder, node->u.as_ubyte); return 0;
+  case PNE_BYTE: pn_encoder_writef8(encoder, node->u.as_byte); return 0;
+  case PNE_USHORT: pn_encoder_writef16(encoder, node->u.as_ushort); return 0;
+  case PNE_SHORT: pn_encoder_writef16(encoder, node->u.as_short); return 0;
   case PNE_UINT0: return 0;
-  case PNE_SMALLUINT: pn_encoder_writef8(encoder, atom->u.as_uint); return 0;
-  case PNE_UINT: pn_encoder_writef32(encoder, atom->u.as_uint); return 0;
-  case PNE_SMALLINT: pn_encoder_writef8(encoder, atom->u.as_int); return 0;
-  case PNE_INT: pn_encoder_writef32(encoder, atom->u.as_int); return 0;
-  case PNE_UTF32: pn_encoder_writef32(encoder, atom->u.as_char); return 0;
+  case PNE_SMALLUINT: pn_encoder_writef8(encoder, node->u.as_uint); return 0;
+  case PNE_UINT: pn_encoder_writef32(encoder, node->u.as_uint); return 0;
+  case PNE_SMALLINT: pn_encoder_writef8(encoder, node->u.as_int); return 0;
+  case PNE_INT: pn_encoder_writef32(encoder, node->u.as_int); return 0;
+  case PNE_UTF32: pn_encoder_writef32(encoder, node->u.as_char); return 0;
   case PNE_ULONG0: return 0;
-  case PNE_ULONG: pn_encoder_writef64(encoder, atom->u.as_ulong); return 0;
-  case PNE_SMALLULONG: pn_encoder_writef8(encoder, atom->u.as_ulong); return 0;
-  case PNE_LONG: pn_encoder_writef64(encoder, atom->u.as_long); return 0;
-  case PNE_SMALLLONG: pn_encoder_writef8(encoder, atom->u.as_long); return 0;
-  case PNE_MS64: pn_encoder_writef64(encoder, atom->u.as_timestamp); return 0;
-  case PNE_FLOAT: c.f = atom->u.as_float; pn_encoder_writef32(encoder, c.i); 
return 0;
-  case PNE_DOUBLE: c.d = atom->u.as_double; pn_encoder_writef64(encoder, c.l); 
return 0;
-  case PNE_DECIMAL32: pn_encoder_writef32(encoder, atom->u.as_decimal32); 
return 0;
-  case PNE_DECIMAL64: pn_encoder_writef64(encoder, atom->u.as_decimal64); 
return 0;
-  case PNE_DECIMAL128: pn_encoder_writef128(encoder, 
atom->u.as_decimal128.bytes); return 0;
-  case PNE_UUID: pn_encoder_writef128(encoder, atom->u.as_uuid.bytes); return 
0;
-  case PNE_VBIN8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
-  case PNE_VBIN32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
-  case PNE_STR8_UTF8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
-  case PNE_STR32_UTF8: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 
0;
-  case PNE_SYM8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
-  case PNE_SYM32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
+  case PNE_ULONG: pn_encoder_writef64(encoder, node->u.as_ulong); return 0;
+  case PNE_SMALLULONG: pn_encoder_writef8(encoder, node->u.as_ulong); return 0;
+  case PNE_LONG: pn_encoder_writef64(encoder, node->u.as_long); return 0;
+  case PNE_SMALLLONG: pn_encoder_writef8(encoder, node->u.as_long); return 0;
+  case PNE_MS64: pn_encoder_writef64(encoder, node->u.as_timestamp); return 0;
+  case PNE_FLOAT: c.f = node->u.as_float; pn_encoder_writef32(encoder, c.i); 
return 0;
+  case PNE_DOUBLE: c.d = node->u.as_double; pn_encoder_writef64(encoder, c.l); 
return 0;
+  case PNE_DECIMAL32: pn_encoder_writef32(encoder, node->u.as_decimal32); 
return 0;
+  case PNE_DECIMAL64: pn_encoder_writef64(encoder, node->u.as_decimal64); 
return 0;
+  case PNE_DECIMAL128: pn_encoder_writef128(encoder, (buf.start + 
node->u.as_bytes.offset)); return 0;
+  case PNE_UUID: pn_encoder_writef128(encoder, (buf.start + 
node->u.as_bytes.offset)); return 0;
+  case PNE_VBIN8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset}; pn_encoder_writev8(encoder, &b); return 0; }
+  case PNE_VBIN32: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset}; pn_encoder_writev32(encoder, &b); return 0; }
+  case PNE_STR8_UTF8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset}; pn_encoder_writev8(encoder, &b); return 0; }
+  case PNE_STR32_UTF8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset}; pn_encoder_writev32(encoder, &b); return 0; }
+  case PNE_SYM8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset}; pn_encoder_writev8(encoder, &b); return 0; }
+  case PNE_SYM32: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + 
node->u.as_bytes.offset}; pn_encoder_writev32(encoder, &b); return 0; }
   case PNE_ARRAY32:
-    node->start = encoder->position;
-    node->small = false;
+    node->u.as_array.start = (uint32_t) encoder->position;
     // we'll backfill the size on exit
     encoder->position += 4;
-    pn_encoder_writef32(encoder, node->described ? node->children - 1 : 
node->children);
-    if (node->described)
+    pn_encoder_writef32(encoder, node->u.as_array.described ? node->children - 
1 : node->children);
+    if (node->u.as_array.described)
       pn_encoder_writef8(encoder, 0);
     return 0;
   case PNE_LIST32:
+    node->u.as_list.start = (uint32_t) encoder->position;
+    // we'll backfill the size later
+    encoder->position += 4;
+    pn_encoder_writef32(encoder, node->children);
+    return 0;
   case PNE_MAP32:
-    node->start = encoder->position;
-    node->small = false;
+    node->u.as_map.start = (uint32_t) encoder->position;
     // we'll backfill the size later
     encoder->position += 4;
     pn_encoder_writef32(encoder, node->children);
@@ -350,43 +353,36 @@ static int pni_encoder_exit(void *ctx, pn_data_t *data, 
pni_node_t *node)
 
   // Special case 0 length list, but not as element in an array
   pni_node_t *parent = pn_data_node(data, node->parent);
-  if (node->atom.type==PN_LIST && node->children-encoder->null_count==0 && 
!pn_is_in_array(data, parent, node)) {
-    encoder->position = node->start-1; // position of list opcode
+  if (node->type==PN_LIST && node->children-encoder->null_count==0 && 
!pn_is_in_array(data, parent, node)) {
+    encoder->position = node->u.as_list.start - 1; // position of list opcode
     pn_encoder_writef8(encoder, PNE_LIST0);
     encoder->null_count = 0;
     return 0;
   }
 
-  switch (node->atom.type) {
+  switch (node->type) {
   case PN_ARRAY:
-    if ((node->described && node->children == 1) || (!node->described && 
node->children == 0)) {
-      pn_encoder_writef8(encoder, pn_type2code(encoder, node->type));
+    if ((node->u.as_array.described && node->children == 1) || 
(!node->u.as_array.described && node->children == 0)) {
+      pn_encoder_writef8(encoder, pn_type2code(encoder, 
node->u.as_array.type));
     }
     PN_FALLTHROUGH;
   case PN_LIST:
-  case PN_MAP:
+  case PN_MAP: {
     pos = encoder->position;
-    encoder->position = node->start;
-    if (node->small) {
-      // backfill size
-      size_t size = pos - node->start - 1;
-      pn_encoder_writef8(encoder, size);
-      // Adjust count
-      if (encoder->null_count) {
-        pn_encoder_writef8(encoder, node->children-encoder->null_count);
-      }
-    } else {
-      // backfill size
-      size_t size = pos - node->start - 4;
-      pn_encoder_writef32(encoder, size);
-      // Adjust count
-      if (encoder->null_count) {
-        pn_encoder_writef32(encoder, node->children-encoder->null_count);
-      }
+    /* start is at the same offset in as_array/as_list/as_map — use as_list 
uniformly */
+    uint32_t start = node->u.as_list.start;
+    encoder->position = start;
+    // backfill size
+    size_t size = pos - start - 4;
+    pn_encoder_writef32(encoder, size);
+    // Adjust count
+    if (encoder->null_count) {
+      pn_encoder_writef32(encoder, node->children-encoder->null_count);
     }
     encoder->position = pos;
     encoder->null_count = 0;
     return 0;
+  }
   default:
     return 0;
   }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to