From d53fab56b6ae770cfe02be093e236d97e8162265 Mon Sep 17 00:00:00 2001 From: Davide Bettio Date: Fri, 11 Oct 2024 00:07:59 +0200 Subject: [PATCH] externalterm: make serialize to buffer functions accessible Make functions for writing a term using external term format to a buffer accessible, so there is no need to use a binary. externalterm_serialize_term(_raw) and externalterm_compute_external_size(_raw) functions can be useful when using external term format in NIFs or port drivers. Before this change `externalterm_to_binary` was the only available function, but was forcing using a binary term as output. Signed-off-by: Davide Bettio --- CHANGELOG.md | 2 + src/libAtomVM/externalterm.c | 16 +++++++- src/libAtomVM/externalterm.h | 73 ++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd0e31a5..721368f61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ also non string parameters (e.g. `Enum.join([1, 2], ",")` [#1100](https://github.com/atomvm/AtomVM/issues/1100) - Support for mounting/unmounting storage on ESP32 (such as SD or internal flash) using `esp:mount/4` and `esp:umount/1` +- Make external term serialize functions available without using `externalterm_to_binary` so terms +can be written directly to a buffer. ### Changed diff --git a/src/libAtomVM/externalterm.c b/src/libAtomVM/externalterm.c index 9d5cfb8ad..0936ad6b0 100644 --- a/src/libAtomVM/externalterm.c +++ b/src/libAtomVM/externalterm.c @@ -32,7 +32,6 @@ #include "unicode.h" #include "utils.h" -#define EXTERNAL_TERM_TAG 131 #define NEW_FLOAT_EXT 70 #define SMALL_INTEGER_EXT 97 #define INTEGER_EXT 98 @@ -947,3 +946,18 @@ static int calculate_heap_usage(const uint8_t *external_term_buf, size_t remaini return INVALID_TERM_SIZE; } } + +enum ExternalTermResult externalterm_compute_external_size_raw( + term t, size_t *size, GlobalContext *glb) +{ + *size = compute_external_size(t, glb); + + return EXTERNAL_TERM_OK; +} + +enum ExternalTermResult externalterm_serialize_term_raw(void *buf, term t, GlobalContext *glb) +{ + serialize_term(buf, t, glb); + + return EXTERNAL_TERM_OK; +} diff --git a/src/libAtomVM/externalterm.h b/src/libAtomVM/externalterm.h index a43c3813a..6a4b363fb 100644 --- a/src/libAtomVM/externalterm.h +++ b/src/libAtomVM/externalterm.h @@ -30,6 +30,8 @@ #include "term.h" +#define EXTERNAL_TERM_TAG 131 + #ifdef __cplusplus extern "C" { #endif @@ -94,6 +96,77 @@ enum ExternalTermResult externalterm_from_binary(Context *ctx, term *dst, term b */ term externalterm_to_binary(Context *ctx, term t); +/** + * @brief Computes the size required for a external term (tag excluded) + * + * @details This function should be called in order to calculate the required buffer size to store + * a serialized term in external term format. This function doesn't prepend the external term 1 byte + * tag. + * + * @param t the term for which size is calculated + * @param size the required buffer size (tag excluded) + * @param glb the global context + * @returns EXTERNAL_TERM_OK in case of success + */ +enum ExternalTermResult externalterm_compute_external_size_raw( + term t, size_t *size, GlobalContext *glb); + +/** + * @brief Serialize a term (tag excluded) + * + * @details This function serializes in external term format given term, and writes it to the given + * buffer. This function doesn't prepend the external term 1 byte tag. + * + * @param buf the buffer where the external term is written + * @param t the term that will be serialized + * @param glb the global context + * @returns EXTERNAL_TERM_OK in case of success + */ +enum ExternalTermResult externalterm_serialize_term_raw(void *buf, term t, GlobalContext *glb); + +/** + * @brief Computes the size required for a external term + * + * @details This function should be called in order to calculate the required buffer size to store + * a serialized term in external term format. + * + * @param t the term for which size is calculated + * @param size the required buffer size (tag excluded) + * @param glb the global context + * @returns EXTERNAL_TERM_OK in case of success + */ +static inline enum ExternalTermResult externalterm_compute_external_size( + term t, size_t *size, GlobalContext *glb) +{ + size_t raw_size; + enum ExternalTermResult result = externalterm_compute_external_size_raw(t, &raw_size, glb); + if (LIKELY(result == EXTERNAL_TERM_OK)) { + *size = raw_size + 1; + } + return result; +} + +/** + * @brief Serialize a term + * + * @details This function serializes in external term format given term, and writes it to the given + * buffer. + * + * @param buf the buffer where the external term is written + * @param t the term that will be serialized + * @param glb the global context + * @returns EXTERNAL_TERM_OK in case of success + */ +static inline enum ExternalTermResult externalterm_serialize_term( + void *buf, term t, GlobalContext *glb) +{ + enum ExternalTermResult result = externalterm_serialize_term_raw((uint8_t *) buf + 1, t, glb); + if (LIKELY(result == EXTERNAL_TERM_OK)) { + ((uint8_t *) buf)[0] = EXTERNAL_TERM_TAG; + } + return result; +} + #ifdef __cplusplus } #endif