mangling 0.2.3

mangling generates safe, recognizable identifiers from byte streams.
Documentation
#ifndef mangling_h
#define mangling_h

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

/**
 * Provides a C-compatible interface to the `demangle` function.
 *
 * This function is compatible with the C function declaration:
 * ```c
 * int mangling_demangle(size_t insize, const char *instr, size_t *outsize, char *outptr);
 * ```
 *
 * This function:
 * - returns a zero value upon success and a non-zero value on failure,
 * - has well-defined behavior for any combination of null pointer arguments,
 * - places its output into a buffer provided by the caller,
 * - produces a sequence of arbitrary bytes, possibly including embedded NULs,
 * - writes no more bytes than specified by the caller via `outsize`,
 * - updates the size referenced by `outsize` with the number of bytes copied through `outptr`.
 *
 * A failure is indicated with a non-zero exit code under the following conditions:
 * - the input string was not a valid mangled name.
 *
 * It is not an error to supply an output buffer that is too small; in such a case, the output
 * will simply be truncated to the provided length.
 *
 * A null input pointer (`None` in the Rust interface) is not an error *per se*, but since at best
 * (when `insize` is 0) it can represent only an empty string, which is never demanglable, failure
 * is reported:
 * ```
 * # use mangling::clib::*;
 * // Demangling an empty string is not meaningful, and must fail
 * let success = mangling_demangle(0, None, None, None);
 * assert_ne!(success, 0);
 * ```
 *
 * # Example
 * In C:
 * ```c
 * char result[128];
 * size_t outsize = sizeof result;
 * int success = mangling_demangle(strlen(argv[1]), argv[1], &outsize, result);
 * fwrite(result, 1, outsize, stdout);
 * ```
 */
int mangling_demangle(uintptr_t insize, const char *instr, uintptr_t *outsize, char *outptr);

/**
 * Provides a C-compatible interface to the `mangle` function.
 *
 * This function is compatible with the C function declaration:
 * ```c
 * int mangling_mangle(size_t insize, const char *inptr, size_t *outsize, char *outstr);
 * ```
 *
 * This function:
 * - returns a zero value upon success and a non-zero value on failure,
 * - has well-defined behavior for any combination of null pointer arguments,
 * - writes a sequence of non-NUL bytes into a buffer provided by the caller,
 * - writes no more bytes than specified in `outsize`, and
 * - updates the size referenced by `outsize` with the number of bytes copied through `outstr`.
 *
 * A failure is indicated with a non-zero exit code under the following conditions:
 * - a null pointer was passed in for the `inptr` argument but the `insize` is nonzero.
 *
 * It is not an error to supply an output buffer that is too small; in such a case, the output
 * will simply be truncated to the provided length.
 *
 * The output is never NUL-terminated. If NUL termination is desired, and the `outstr` buffer is
 * big enough, simply perform `outstr[*outsize] = '\0';` after `mangling_mangle`.
 *
 * # Examples
 * Some of the examples below are shown in (doctested) Rust code to demonstrate correctness, but
 * it is not expected that Rust users will use the C interfaces.
 *
 * Null pointers (`None` in the Rust interface) are not inherently erroneous:
 * ```
 * # use mangling::clib::*;
 * let success = mangling_mangle(0, None, None, None);
 * assert_eq!(0, success);
 * ```
 * This behavior can be used to determine the correct size of buffer to allocate (here
 * demonstrated with Rust code):
 * ```
 * # use mangling::clib::*;
 * # use std::os::raw::c_char;
 * let input = "hello, world";
 * let mut len = std::usize::MAX;
 * let inptr = unsafe { &*(input.as_ptr() as *const c_char) };
 * let success = mangling_mangle(input.len(), Some(inptr), Some(&mut len), None);
 * assert_eq!(0, success);
 *
 * // Now the required buffer size is known in `len` and can be used for allocation
 * let mut v: Vec<u8> = Vec::with_capacity(len);
 * let outptr = unsafe { &mut *(v.as_mut_ptr() as *mut c_char) };
 * let success = mangling_mangle(input.len(), Some(inptr), Some(&mut len), Some(outptr));
 * unsafe { v.set_len(len); }
 * assert_eq!(&v[..], "_5hello02_2c205world".as_bytes());
 * assert_eq!(0, success);
 * ```
 * Similar C code might look like this:
 * ```c
 * size_t need = -1;
 * int rc = mangling_mangle(strlen(input), input, &need, NULL);
 * if (rc != 0) return;
 * char *buf = malloc(need);
 * rc = mangling_mangle(strlen(input), input, &need, buf);
 * ```
 *
 * However, if the `insize` parameter indicates that some data should be expected, then a null
 * pointer is an error, though still safe:
 * ```
 * # use mangling::clib::*;
 * let success = mangling_mangle(1, None, None, None);
 * assert_ne!(0, success);
 * ```
 *
 * In C, if the output buffer is sized safely according to the bounds specified in the `mangle`
 * documentation, then a mangling call can be as simple as the following:
 * ```c
 * char input[16] = "hello, world",
 * char result[1 + 5 * sizeof input]; // Worst-case length
 * size_t outsize = sizeof result;
 * int success = mangling_mangle(strlen(input), input, &outsize, result);
 * fwrite(result, 1, outsize, stdout);
 * ```
 */
int mangling_mangle(uintptr_t insize, const char *inptr, uintptr_t *outsize, char *outstr);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

#endif /* mangling_h */