Initialization

Outside of the Wuffs base package, every Wuffs struct has an implicit initialize method, which needs to be called before any other method. In Wuffs' C language form, the initialize function for the foo package's bar struct is called wuffs_foo__bar__initialize. The function takes four arguments (or, in C++, the initialize method takes three arguments, with the implicit this pointer argument):

  • A pointer to the wuffs_foo__bar object: the this pointer.
  • The size (in bytes) of that object. Conceptually, this is sizeof(wuffs_foo__bar{}), but that expression generally won't compile, as wuffs_foo__bar is deliberately an incomplete type. Its size is not part of the stable ABI. Instead, call the sizeof__wuffs_foo__bar function, whose return value can change across Wuffs versions, even across point releases. For an example, look for sizeof__wuffs_json__decoder in the example/jsonptr program.
  • The Wuffs library version, WUFFS_VERSION.
  • Additional flags.

Initialization can fail if the caller and callee disagree on the size or the Wuffs version, or if unsupported flag bits are passed.

There are no destructor functions. Just free the memory. Wuffs structs don't store or otherwise own file descriptors, pointers to dynamically allocated memory or anything else that needs explicit releasing.

As a consequence, to restore a Wuffs object to its initial state (e.g. to re-use a Wuffs image decoder's memory to decode a different image), just call the initialize function again.

Flags

The flags are a bitmask of options. Zero (or equivalently, WUFFS_INITIALIZE__DEFAULT_OPTIONS) means that none of the options are set.

  • The WUFFS_INITIALIZE__ALREADY_ZEROED bit tells the initialize function to assume that the entire struct has already been zero-initialized. This can make the initialize call a little faster.
  • The WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED bit means to partially, not fully, zero-initialize the struct. Again, this can make the call a little faster. See the “Partial Zero-Initialization” section below for details. This bit is ignored if the WUFFS_INITIALIZE__ALREADY_ZEROED bit is also set.

Partial Zero-Initialization

Memory-safe programming languages typically initialize their variables and fields to zero, so that there is no way to read an uninitialized value. By default, Wuffs does so too, but in Wuffs' C/C++ form, there is the option (the WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED flag bit) to leave some struct fields uninitialized (although local variables are always zero-initialized), for performance reasons.

With or without this flag bit set, the Wuffs compiler still enforces bounds and arithmetic overflow checks. It's just that for potentially-uninitialized struct fields, the compiler has weaker starting assumptions: their numeric types cannot be refined.

Even with this flag bit set, the Wuffs standard library also considers reading from an uninitialized buffer to be a bug, and strives to never do so, but unlike buffer out-of-bounds reads or writes, it is not a bug class that the Wuffs compiler eliminates.

For those paranoid about security, leave this flag bit unset, so that wuffs_foo__bar__initialize will zero-initialize the entire struct (unless the WUFFS_INITIALIZE__ALREADY_ZEROED flag bit is also set).

Setting this flag bit (avoiding a fixed-size cost) gives a small absolute improvement on micro-benchmarks, mostly noticeable (in relative terms) only when the actual work to do (the input) is also small. Look for WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED in the benchmarks for performance numbers.

In Wuffs code, a struct definition has two parts, although the second part's () parentheses may be omitted if empty:

pub struct bar?(
    // Fields in the first part are always zero-initialized.
    x : etc,
    y : etc,
)(
    // Fields in the second part are optionally uninitialized, but are still
    // zero-initialized by default.
    //
    // Valid types for these fields are either unrefined numerical types, or
    // arrays of a valid type.
    //  - "base.u8" is ok.
    //  - "array[123] base.u8" is ok.
    //  - "array[123] base.u8[0 ..= 99]" is not, due to the refinement.
    z : etc,
)