
-------------------------------------------------------------------------------
What is a meta getter/setter?

A meta getter/setter is a function which is designed to get and/or set
the value of some field in a tree meant for describing another field.
This could be a function that can return and set the element count
in an array when the count isnt stored as a literal value anywhere.
It could also be a function that gets/sets any other meta attribute,
such as pointers or switch cases.

*For brevity, meta_getter_setter will be abbreviated to mgs*

Take this mgs for example:

def size8(parent=None, new_value=None, **kwargs):
    '''
    Size getter for rsa key data where the byte size
    of the integer is (parent.parent.bitlen + 7) // 8
    (the + 7 is to round up to the nearest multiple of 8)

    We dont want to have this be a setter since bitlen
    is used by more than one attribute and while it may 
    work for some bigints, it may be too small for others.
    '''
    if new_value is None:
        return (parent.parent.bitlen + 7) // 8

This mgs is solely a getter, and returns the number of bytes that a bigint
would be if the bit length of the bigint is stored in parent.parent.bitlen


Here is another example which includes both getter and setter functionality:

def record_param_count(parent=None, new_value=None, **kwargs):
    '''Size getter/setter for the record parameters array element count.'''
    if parent is None:
        raise KeyError("Cannot get/set the size of record parameter " +
                       "array without a supplied parent.")
    if new_value is None:
        return (parent.size - 3)*2

    assert not new_value % 2, 'record byte sizes must be a multiple of 2.'

    parent.size = 3 + new_value//2

The size is stored as a word count(words are 2 bytes), but the word count
also includes the size of the record header(6 bytes, or 3 words).
This function will return the size attribute as a byte count(minus the header)
and will set the size attribute when given a byte count(plus the header).


Meta getter/setters should be as simple as possible, but as complex as needed.
Here is a final example using multiple attributes to calculate a byte size.

def tga_pixel_bytes_size(parent=None, attr_index=None,
                         new_value=None, **kwargs):
    '''Size getter for the byte size of tga pixel data'''
    if new_value is not None:
        return
    if parent is None:
        raise KeyError("Cannot calculate the size of tga " +
                       "pixels without without a supplied parent.")
    if attr_index is not None and hasattr(parent[attr_index], '__len__'):
        return len(parent[attr_index])

    header = parent.parent.header
    pixels = header.width * header.height
    image_type = header.image_type

    if image_type.format == 0:
        return pixels // 8
    elif header.bpp in (15, 16):
        return 2 * pixels
    return header.bpp * pixels // 8


-------------------------------------------------------------------------------
Where are they used?

Meta getter/setters exist in descriptors under string keys.
Currently the only descriptor keys they should be found under are
the SIZE, CASE, and POINTER keys.

When a Blocks get_meta/set_meta methods is called and the item under the
given descriptor key is a function, it will be called as a meta getter/setter.
This also occurs when a Blocks get_size/set_size methods is called and
the given descriptor key is a function(getting and setting size has a
few gotchas that warrent it having its own set of methods).

When a Switch fields parser function is being run, the CASE entry of the 
descriptor will be called as a meta getter/setter to determine which
structure to build. For WhileArray fields, the parser function uses the CASE
entry as an mgs to determine whether or not to keep building structures.

For fields which can be pointered, the POINTER descriptor entry can be an
mgs that will return the integer pointer to jump to in the rawdata stream.


-------------------------------------------------------------------------------
Why are they used?

There are times where data needs to be manipulated before being returned or
set, such as converting units(bits to bytes) or adjusting pointer offsets.
There are also times where there is no single attribute that holds the
exact value you are looking for, such as getting an images byte size by
multiplying width*height*bytes_per_pixel.

For those situations it is necessary to write a function that can properly get
and(if applicable) set the meta data. A meta getter/setter is usually written
exclusively for a single field, and should be as fast as possible.

Meta getter/setters are needed as a way for a Switch to decide what to build
and for WhileArrays to decide whether or not to continue building entries.
Sometimes more versatility and control is needed when getting and setting
meta data than what you could get from simply using a nodepath.


-------------------------------------------------------------------------------
What arguments should a meta getter/setter expect and what are their purposes?

keyword:
    node -------- The node whose meta value is being returned/set.

    parent ------ The parent Block of the node argument. This is provided
                  for the scenarios where node is not an instance of Block.
                  If this argument is to be considered valid, attr_index must
                  be provided and valid as well.

    attr_index -- The index that node can be found under in parent by doing:
                      parent[attr_index].
                  If this is None, assume the parent argument is not valid.

    rawdata ----- A peekable buffer that has been pre-seeked to the 
                  correct position for reading any data that is
                  pertinent to getting or setting the meta data.
                  This is primarily used for retrieving data from a stream
                  that is about to be parsed into a node, but the way the
                  node is to be built depends on the upcoming data.

                  For example, one may need to check for a sequence of marker
                  bytes that specify what kind of structure is coming next.

    new_value --- The value to change the meta data to.
                  If this is None or unprovided, it means that the
                  function should return the meta data. Otherwise
                  the function should set the meta data to new_value.

Meta getter/setters are expected to use only keyword arguments, and must
make use of **kwargs since unused keyword arguments may be provided.