Skip to content

Commit 4bd6325

Browse files
authored
Merge pull request #166 from embray/issue-138
Basic serialization support for GWCS extensions
2 parents 5eead86 + dccbaca commit 4bd6325

24 files changed

Lines changed: 1375 additions & 38 deletions

docs/api/asdf/yaml.h.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
asdf/yaml.h
2+
===========
3+
4+
.. autodoc:: include/asdf/yaml.h

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def read_config_h() -> tuple[str, str, str]:
100100

101101
# libasdf identifiers that should be documented but aren't yet
102102
('c:identifier', 'asdf_emitter_cfg_t'),
103+
('c:identifier', 'asdf_event_t'),
103104
('c:identifier', 'asdf_history_entry_t'),
104105
('c:identifier', 'asdf_parser_cfg_t'),
105106
]

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ headers.
4949
:maxdepth: 2
5050

5151
api/asdf/extension.h
52+
api/asdf/yaml.h
5253

5354

5455
Resources

include/asdf/core/ndarray.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,22 @@ ASDF_EXPORT uint64_t asdf_ndarray_nbytes(const asdf_ndarray_t *ndarray);
200200
ASDF_EXPORT void *asdf_ndarray_data_alloc(asdf_ndarray_t *ndarray);
201201

202202

203+
/**
204+
* Allocate a temporary data buffer for an ndarray to be written to a file,
205+
* with automatic cleanup after the write completes.
206+
*
207+
* Like `asdf_ndarray_data_alloc` but the allocated memory is freed
208+
* automatically after `asdf_write_to` (or `asdf_close`) is called.
209+
* Extension authors should use this instead of `asdf_ndarray_data_alloc`
210+
* when building ndarrays inside a serialize callback.
211+
*
212+
* :param file: The `asdf_file_t *` to register the cleanup with
213+
* :param ndarray: An `asdf_ndarray_t *` whose shape and datatype are already set
214+
* :return: A `void *` to the zero-initialized buffer, or NULL on OOM
215+
*/
216+
ASDF_EXPORT void *asdf_ndarray_data_alloc_temp(asdf_file_t *file, asdf_ndarray_t *ndarray);
217+
218+
203219
/**
204220
* Free ndarray data allocated with `asdf_ndarray_data_alloc`
205221
*

include/asdf/file.h

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,19 @@ static asdf_file_t *asdf_open_mem(const void *buf, size_t size);
144144

145145

146146
#define ASDF__OPEN_1(source) \
147-
_Generic((source), \
147+
_Generic( \
148+
(source), \
148149
FILE *: asdf_open_fp(source, NULL), \
149150
const char *: asdf_open_file(source, "r"), \
150151
char *: asdf_open_file(source, "r"), \
151-
void *: asdf_open_mem(NULL, 0) \
152-
)
152+
void *: asdf_open_mem(NULL, 0))
153153
#define ASDF__OPEN_2(source, ...) \
154-
_Generic((source), \
154+
_Generic( \
155+
(source), \
155156
FILE *: asdf_open_fp, \
156157
const char *: asdf_open_file, \
157158
char *: asdf_open_file, \
158-
const void *: asdf_open_mem \
159-
)(source, __VA_ARGS__)
159+
const void *: asdf_open_mem)(source, __VA_ARGS__)
160160

161161

162162
/**
@@ -194,12 +194,12 @@ static asdf_file_t *asdf_open_mem(const void *buf, size_t size);
194194
* `asdf_open_mem_ex` depending on the argument types
195195
*/
196196
#define asdf_open_ex(source, ...) /* NOLINT(readability-identifier-naming) */ \
197-
_Generic((source), \
197+
_Generic( \
198+
(source), \
198199
const char *: asdf_open_file_ex, \
199200
char *: asdf_open_file_ex, \
200201
FILE *: asdf_open_fp_ex, \
201-
void *: asdf_open_mem_ex \
202-
)(source, __VA_ARGS__)
202+
void *: asdf_open_mem_ex)(source, __VA_ARGS__)
203203

204204
/**
205205
* Opens an ASDF file for reading
@@ -238,44 +238,73 @@ static inline asdf_file_t *asdf_open_mem(const void *buf, size_t size) {
238238

239239

240240
#define ASDF__WRITE_TO_1(source, dest) \
241-
_Generic((dest), \
241+
_Generic( \
242+
(dest), \
242243
const char *: asdf_write_to_file, \
243244
char *: asdf_write_to_file, \
244-
FILE *: asdf_write_to_fp \
245-
)(file, dest)
245+
FILE *: asdf_write_to_fp)(file, dest)
246246

247247

248248
#define ASDF__WRITE_TO_2(source, dest, ...) asdf_write_to_mem(source, dest, __VA_ARGS__)
249249

250250

251+
/**
252+
* Write the contents of an ``asdf_file_t`` to a destination
253+
*
254+
* This is a type-generic macro that dispatches to one of the following based
255+
* on the type and number of arguments after ``file``:
256+
*
257+
* * ``asdf_write_to(file, filename)`` -- where ``filename`` is a
258+
* ``const char *`` or ``char *``: calls `asdf_write_to_file`
259+
* * ``asdf_write_to(file, fp)`` -- where ``fp`` is a ``FILE *``: calls
260+
* `asdf_write_to_fp`
261+
* * ``asdf_write_to(file, buf, size)`` -- where ``buf`` is a ``void **`` and
262+
* ``size`` is a ``size_t *``: calls `asdf_write_to_mem`
263+
*
264+
* :param file: The `asdf_file_t *` to write
265+
* :param ...: Destination argument(s) -- see above
266+
* :return: 0 on success, non-zero on failure
267+
*/
251268
#define asdf_write_to(file, ...) /* NOLINT(readability-identifier-naming) */ \
252269
ASDF__PP_CAT(ASDF__WRITE_TO_, ASDF__PP_NARGS(__VA_ARGS__))(file, __VA_ARGS__)
253270

254271

255272
/**
256273
* Write the contents of the ``asdf_file_t`` to the given filesystem path
274+
*
275+
* :param file: The `asdf_file_t *` to write
276+
* :param filename: Path to the output file; created or truncated as needed
277+
* :return: 0 on success, non-zero on failure
257278
*/
258279
ASDF_EXPORT int asdf_write_to_file(asdf_file_t *file, const char *filename);
259280

260281

261282
/**
262283
* Write the contents of the ``asdf_file_t`` to the given writeable ``FILE *``
263284
* stream
285+
*
286+
* :param file: The `asdf_file_t *` to write
287+
* :param fp: An open, writeable ``FILE *`` stream
288+
* :return: 0 on success, non-zero on failure
264289
*/
265290
ASDF_EXPORT int asdf_write_to_fp(asdf_file_t *file, FILE *fp);
266291

267292

268293
/**
269294
* Write the contents of the ``asdf_file_t`` to a memory buffer
270295
*
271-
* If the value of ``*buf`` is non-NULL then a user-provided buffer is assumed
272-
* and its size is read from ``*size``. If the size is not large enough to
273-
* hold the file, then it is simply truncated and a non-zero return value is
274-
* returned.
296+
* If ``*buf`` is non-NULL, a user-provided buffer is assumed and its size is
297+
* read from ``*size``. If the buffer is not large enough to hold the file,
298+
* the output is truncated and a non-zero value is returned.
299+
*
300+
* If ``*buf`` is NULL, a buffer is allocated with `malloc()` and a pointer to
301+
* it is stored in ``*buf``; the allocated size is written to ``*size``. The
302+
* caller is responsible for freeing the buffer with `free()`.
275303
*
276-
* Otherwise, memory is allocated with `malloc()` and the size of the buffer is
277-
* returned into the ``size`` argument. The user is responsible for freeing
278-
* the buffer with `free()`.
304+
* :param file: The `asdf_file_t *` to write
305+
* :param buf: Address of a ``void *`` buffer pointer (in/out)
306+
* :param size: Address of a ``size_t`` holding the buffer size (in/out)
307+
* :return: 0 on success, non-zero on failure
279308
*/
280309
ASDF_EXPORT int asdf_write_to_mem(asdf_file_t *file, void **buf, size_t *size);
281310

include/asdf/value.h

Lines changed: 153 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -406,38 +406,135 @@ ASDF_EXPORT void asdf_mapping_item_destroy(asdf_mapping_item_t *item);
406406
*/
407407
typedef struct asdf_sequence asdf_sequence_t;
408408

409+
/** Return true if ``value`` holds a YAML sequence */
409410
ASDF_EXPORT bool asdf_value_is_sequence(asdf_value_t *value);
411+
412+
/**
413+
* Return the number of items in ``sequence``
414+
*
415+
* :param sequence: The `asdf_sequence_t *` to query
416+
* :return: The number of items currently in the sequence
417+
*/
410418
ASDF_EXPORT int asdf_sequence_size(asdf_sequence_t *sequence);
419+
420+
/**
421+
* Return the value at ``index`` in ``sequence``
422+
*
423+
* Negative indices are supported (e.g. ``-1`` for the last item). Returns
424+
* ``NULL`` if ``index`` is out of range.
425+
*
426+
* :param sequence: The `asdf_sequence_t *` to query
427+
* :param index: Zero-based index; negative indices count from the end
428+
* :return: The `asdf_value_t *` at that position, or ``NULL``
429+
*/
411430
ASDF_EXPORT asdf_value_t *asdf_sequence_get(asdf_sequence_t *sequence, int index);
431+
432+
/**
433+
* Obtain a typed `asdf_sequence_t *` view of a generic value
434+
*
435+
* On success writes the `asdf_sequence_t *` into ``*out`` and returns
436+
* ``ASDF_VALUE_OK``. Returns an error code and leaves ``*out`` unchanged if
437+
* ``value`` is not a sequence.
438+
*
439+
* :param value: The generic `asdf_value_t *` to inspect
440+
* :param out: Receives the `asdf_sequence_t *` on success
441+
* :return: ``ASDF_VALUE_OK`` on success, otherwise an `asdf_value_err_t` error
442+
*/
412443
ASDF_EXPORT asdf_value_err_t asdf_value_as_sequence(asdf_value_t *value, asdf_sequence_t **out);
444+
445+
/**
446+
* Return the generic `asdf_value_t *` view of a sequence
447+
*
448+
* The returned pointer shares ownership with ``sequence``; the caller must
449+
* not free it independently.
450+
*
451+
* :param sequence: The `asdf_sequence_t *` to wrap
452+
* :return: The same object as a generic `asdf_value_t *`
453+
*/
413454
ASDF_EXPORT asdf_value_t *asdf_value_of_sequence(asdf_sequence_t *sequence);
455+
456+
/**
457+
* Create a new, empty sequence attached to ``file``
458+
*
459+
* The caller owns the returned sequence and must eventually release it with
460+
* `asdf_sequence_destroy`, or transfer ownership by inserting it into a
461+
* mapping or parent sequence. Returns ``NULL`` on allocation failure.
462+
*
463+
* :param file: The `asdf_file_t *` that will own the sequence
464+
* :return: A new `asdf_sequence_t *`, or ``NULL`` on failure
465+
*/
414466
ASDF_EXPORT asdf_sequence_t *asdf_sequence_create(asdf_file_t *file);
467+
468+
/**
469+
* Set the YAML node style used when serializing ``sequence``
470+
*
471+
* :param sequence: The `asdf_sequence_t *` to modify
472+
* :param style: The desired `asdf_yaml_node_style_t` (e.g. block or flow)
473+
*/
415474
ASDF_EXPORT void asdf_sequence_set_style(asdf_sequence_t *sequence, asdf_yaml_node_style_t style);
475+
476+
/**
477+
* Free a sequence and all values it contains
478+
*
479+
* Must not be called on a sequence that has been inserted into a mapping or
480+
* parent sequence -- ownership transfers at that point.
481+
*
482+
* :param sequence: The `asdf_sequence_t *` to free
483+
*/
416484
ASDF_EXPORT void asdf_sequence_destroy(asdf_sequence_t *sequence);
417485

418486

419487
/** Opaque struct holding sequence iterator state */
420488
typedef void *asdf_sequence_iter_t;
421489

490+
/**
491+
* Initialize an `asdf_sequence_iter_t` to its starting state
492+
*
493+
* Call this once before the first call to `asdf_sequence_iter`.
494+
*
495+
* :return: An initialized `asdf_sequence_iter_t`
496+
*/
422497
ASDF_EXPORT asdf_sequence_iter_t asdf_sequence_iter_init(void);
423498

424499

425500
/**
426-
* Iterate over a sequence value
501+
* Advance a sequence iterator and return the next value
427502
*
428-
* .. todo::
503+
* Typical usage::
429504
*
430-
* Finish documenting me.
505+
* asdf_sequence_iter_t iter = asdf_sequence_iter_init();
506+
* asdf_value_t *val;
507+
* while ((val = asdf_sequence_iter(seq, &iter)) != NULL) {
508+
* // use val ...
509+
* }
510+
*
511+
* Returns ``NULL`` when iteration is exhausted.
512+
*
513+
* :param sequence: The `asdf_sequence_t *` to iterate over
514+
* :param iter: Pointer to the iterator state; updated on each call
515+
* :return: The next `asdf_value_t *` in the sequence, or ``NULL`` when done
431516
*/
432517
ASDF_EXPORT asdf_value_t *asdf_sequence_iter(asdf_sequence_t *sequence, asdf_sequence_iter_t *iter);
433518

434519

435520
/**
436-
* Append values to sequences
521+
* Append a value to a sequence
437522
*
438-
* .. todo::
523+
* ``asdf_sequence_append`` appends an existing generic `asdf_value_t *`.
524+
* Ownership of ``value`` transfers to ``sequence`` on success.
525+
*
526+
* The ``asdf_sequence_append_<type>`` variants construct a new value from a C
527+
* scalar and append it in one step. ``asdf_sequence_append_string`` takes an
528+
* explicit byte length; ``asdf_sequence_append_string0`` expects a
529+
* NUL-terminated string. ``asdf_sequence_append_null`` takes no value
530+
* argument. All other variants accept the corresponding C type directly.
439531
*
440-
* Document these.
532+
* ``asdf_sequence_append_mapping`` and ``asdf_sequence_append_sequence``
533+
* transfer ownership of the supplied container to the parent sequence on
534+
* success.
535+
*
536+
* All functions return ``ASDF_VALUE_OK`` on success or an `asdf_value_err_t`
537+
* error code on failure.
441538
*/
442539
ASDF_EXPORT asdf_value_err_t asdf_sequence_append(asdf_sequence_t *sequence, asdf_value_t *value);
443540
ASDF_EXPORT asdf_value_err_t
@@ -467,6 +564,56 @@ ASDF_EXPORT asdf_value_err_t
467564
asdf_sequence_append_sequence(asdf_sequence_t *sequence, asdf_sequence_t *value);
468565

469566

567+
/**
568+
* Create a new sequence pre-populated from a C array in a single call
569+
*
570+
* Each ``asdf_sequence_of_<type>`` function allocates a new sequence attached
571+
* to ``file`` and appends ``size`` elements from ``arr``. On success the
572+
* caller owns the returned sequence and must eventually release it with
573+
* `asdf_sequence_destroy` (or transfer ownership by inserting it into a
574+
* mapping or parent sequence). Returns ``NULL`` on allocation failure.
575+
*
576+
* ``asdf_sequence_of_null`` creates a sequence of ``size`` null values; it
577+
* takes no array argument.
578+
*
579+
* ``asdf_sequence_of_string`` accepts an array of ``(str, len)`` pairs via
580+
* separate ``arr`` and ``lens`` pointer arguments.
581+
* ``asdf_sequence_of_string0`` is the null-terminated-string variant.
582+
*
583+
* All other variants mirror the corresponding ``asdf_sequence_append_<type>``
584+
* scalar types.
585+
*/
586+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_null(asdf_file_t *file, int size);
587+
588+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_string(
589+
asdf_file_t *file, const char *const *arr, const size_t *lens, int size);
590+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_string0(
591+
asdf_file_t *file, const char *const *arr, int size);
592+
593+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_bool(asdf_file_t *file, const bool *arr, int size);
594+
595+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_int8(asdf_file_t *file, const int8_t *arr, int size);
596+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_int16(
597+
asdf_file_t *file, const int16_t *arr, int size);
598+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_int32(
599+
asdf_file_t *file, const int32_t *arr, int size);
600+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_int64(
601+
asdf_file_t *file, const int64_t *arr, int size);
602+
603+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_uint8(
604+
asdf_file_t *file, const uint8_t *arr, int size);
605+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_uint16(
606+
asdf_file_t *file, const uint16_t *arr, int size);
607+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_uint32(
608+
asdf_file_t *file, const uint32_t *arr, int size);
609+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_uint64(
610+
asdf_file_t *file, const uint64_t *arr, int size);
611+
612+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_float(asdf_file_t *file, const float *arr, int size);
613+
ASDF_EXPORT asdf_sequence_t *asdf_sequence_of_double(
614+
asdf_file_t *file, const double *arr, int size);
615+
616+
470617
/**
471618
* Remove a value from a sequence and return the removed value
472619
*

0 commit comments

Comments
 (0)