Skip to content

Commit

Permalink
Merge pull request #1309 from bettio/external-term-serialize
Browse files Browse the repository at this point in the history
Add support for term serialize (as external term) to buffer

While there was a `externalterm_to_term` function that was taking a buffer and
returning a term, there wasn't the exact opposite, since it was returning a
binary.

These new functions can be useful for any NIF or function that manipulates just
the buffer and not the whole binary.
This will allow to implement later both support for compressed format or to
optimize/cleanup the `erlang:term_to_binary` NIF.

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
  • Loading branch information
bettio committed Oct 11, 2024
2 parents 6f5d064 + d53fab5 commit 69d6c01
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ also non string parameters (e.g. `Enum.join([1, 2], ",")`
- Support for `binary_to_integer/2`
- Support for `binary:decode_hex/1` and `binary:encode_hex/1,2`
- Support for Elixir `Base.decode16/2` and `Base.encode16/2`
- Make external term serialize functions available without using `externalterm_to_binary` so terms
can be written directly to a buffer.

### Changed

Expand Down
16 changes: 15 additions & 1 deletion src/libAtomVM/externalterm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
73 changes: 73 additions & 0 deletions src/libAtomVM/externalterm.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

#include "term.h"

#define EXTERNAL_TERM_TAG 131

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 69d6c01

Please sign in to comment.