Mapping of SPEAD protocol to Python
-----------------------------------
For incoming heaps:

* Any descriptor with a numpy header is handled by numpy. If the dtype
  contains only a single field which is non-native endian, it will be
  converted to native endian in-place. In other cases, the value retrieved
  from numpy will still be correct, but usage may be slow.
* If no numpy header is present, the following may be used in the format
  with good efficiency:

  * u8, u16, u32, u64
  * i8, i16, i32, i64
  * f32, f64
  * b8
  * c8 (converted to dtype S1)

  Each type will be converted to a numpy type. If there are multiple fields,
  their names will be generated by numpy (`f0`, `f1`, etc). Note that all the
  fields must be of the types above to hit the fast path. Other fields will
  be kept as Python objects.

  At most one element of the shape may indicate a variable-length field,
  whose length will be computed from the size of the item, or 0 if any other
  element of the shape is zero.
* The valid range of the `c` conversion depends on the Python
  version: for Python 2 it must be 0 to 255, for Python 3 it is interpreted
  as a Unicode code point.
* The `0` type is not supported.

Two cases are treated specially:

* A zero-dimensional array is returned as a scalar, rather than a
  zero-dimensional array object.
* A one-dimensional array of characters (numpy dtype 'S1') is converted to a
  Python string, using ASCII encoding.
