msgbuf: Add insert and span APIs

pldm_msgbuf_insert() is generic APIs to insert data to a pointer.
It automatically calls the correct insertor API for the type of the
packing data.
pldm_msgbuf_span_required() spans the input number of bytes from
buffer to the input double pointer.
pldm_msgbuf_span_remaining() extracts the remaining number of bytes
from buffer to the input double pointer.

Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: Ide7dbf735f69a8288e6f39a0b7b5c33aad38a98e
diff --git a/src/msgbuf.h b/src/msgbuf.h
index 662ba46..f5d4a54 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -15,8 +15,18 @@
 #include <string.h>
 #include <sys/types.h>
 
+/*
+ * Fix up C11's _Static_assert() vs C++'s static_assert().
+ *
+ * Can we please have nice things for once.
+ */
+#ifdef __cplusplus
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+#define _Static_assert(...) static_assert(__VA_ARGS__)
+#endif
+
 struct pldm_msgbuf {
-	const uint8_t *cursor;
+	uint8_t *cursor;
 	ssize_t remaining;
 };
 
@@ -366,6 +376,213 @@
 	_Generic((*(dst)), uint8_t                                             \
 		 : pldm_msgbuf_extract_array_uint8)(ctx, dst, count)
 
+static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
+					    const uint32_t src)
+{
+	uint32_t val = htole32(src);
+
+	if (!ctx || !ctx->cursor) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	ctx->remaining -= sizeof(src);
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(ctx->cursor, &val, sizeof(val));
+	ctx->cursor += sizeof(src);
+
+	return PLDM_SUCCESS;
+}
+
+static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
+					    const uint16_t src)
+{
+	uint16_t val = htole16(src);
+
+	if (!ctx || !ctx->cursor) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	ctx->remaining -= sizeof(src);
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(ctx->cursor, &val, sizeof(val));
+	ctx->cursor += sizeof(src);
+
+	return PLDM_SUCCESS;
+}
+
+static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
+					   const uint8_t src)
+{
+	if (!ctx || !ctx->cursor) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	ctx->remaining -= sizeof(src);
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(ctx->cursor, &src, sizeof(src));
+	ctx->cursor += sizeof(src);
+
+	return PLDM_SUCCESS;
+}
+
+static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
+					   const int32_t src)
+{
+	int32_t val = htole32(src);
+
+	if (!ctx || !ctx->cursor) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	ctx->remaining -= sizeof(src);
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(ctx->cursor, &val, sizeof(val));
+	ctx->cursor += sizeof(src);
+
+	return PLDM_SUCCESS;
+}
+
+static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
+					   const int16_t src)
+{
+	int16_t val = htole16(src);
+
+	if (!ctx || !ctx->cursor) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	ctx->remaining -= sizeof(src);
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(ctx->cursor, &val, sizeof(val));
+	ctx->cursor += sizeof(src);
+
+	return PLDM_SUCCESS;
+}
+
+static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
+					  const int8_t src)
+{
+	if (!ctx || !ctx->cursor) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	ctx->remaining -= sizeof(src);
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(ctx->cursor, &src, sizeof(src));
+	ctx->cursor += sizeof(src);
+
+	return PLDM_SUCCESS;
+}
+
+#define pldm_msgbuf_insert(dst, src)                                           \
+	_Generic((src), uint8_t                                                \
+		 : pldm_msgbuf_insert_uint8, int8_t                            \
+		 : pldm_msgbuf_insert_int8, uint16_t                           \
+		 : pldm_msgbuf_insert_uint16, int16_t                          \
+		 : pldm_msgbuf_insert_int16, uint32_t                          \
+		 : pldm_msgbuf_insert_uint32, int32_t                          \
+		 : pldm_msgbuf_insert_int32)(dst, src)
+
+static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx,
+						 const uint8_t *src,
+						 size_t count)
+{
+	size_t len;
+	if (!ctx || !ctx->cursor || !src) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (!count) {
+		return PLDM_SUCCESS;
+	}
+
+	len = sizeof(*src) * count;
+	if (len > SSIZE_MAX) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	ctx->remaining -= (ssize_t)len;
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(ctx->cursor, src, len);
+	ctx->cursor += len;
+
+	return PLDM_SUCCESS;
+}
+
+#define pldm_msgbuf_insert_array(dst, src, count)                              \
+	_Generic((*(src)), uint8_t                                             \
+		 : pldm_msgbuf_insert_array_uint8)(dst, src, count)
+
+static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
+					    size_t required, void **cursor)
+{
+	if (!ctx || !ctx->cursor || !cursor || *cursor) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (required > SSIZE_MAX) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	ctx->remaining -= (ssize_t)required;
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*cursor = ctx->cursor;
+	ctx->cursor += required;
+
+	return PLDM_SUCCESS;
+}
+
+static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx,
+					     void **cursor, size_t *len)
+{
+	if (!ctx || !ctx->cursor || !cursor || *cursor || !len) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	assert(ctx->remaining >= 0);
+	if (ctx->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*cursor = ctx->cursor;
+	ctx->cursor += ctx->remaining;
+	*len = ctx->remaining;
+	ctx->remaining = 0;
+
+	return PLDM_SUCCESS;
+}
 #ifdef __cplusplus
 }
 #endif