docs: function resolveTypes(types) {
  
    CORE_TYPES.forEach(function(t) {
      if (!types[t]) {
        types[t] = {type:t, resolved:true};
      }
    });
  
    // Resolve the type structure by copying all properties and read/write functions from the parent to the child
    // (if they aren't already defined)
    // Can (and will often be) run multiple times on the same object.
    // XXX: This isn't pretty
    function resolveType(type) {
  
      if (typeof type !== 'object') {
        throw new Error('Type definition must be an object. Illegal value: ' + type);
      }
  
      var parent = types[type.type];
  
      while (parent && !type.resolved) {
        resolveType(parent);
  
        _.defaults(type, JSON.parse(JSON.stringify(parent)));
        type.write = type.write || parent.write;
        type.read = type.read || parent.read;
        type.type = parent.type; // Always switch to the parent's type.
        parent = types[type.type];
      }
  
    }
  
    Object.keys(types).forEach(function(name) {
  
      var type = types[name];
      resolveType(type);
  
      type.name = name;
    });
  
    Object.keys(types).forEach(function(name) {
  
      var type = types[name];
      // Add any missing read/write functions
  
      if (!type.write) {
        type.write = function(builder, value, attribute) {
  
          if (attribute.mask) {
            if (typeof value == 'object') {
              var mask = '';
              attribute.mask.slice().reverse().forEach(function(property) {
                mask += value[property]?'1':'0'; // XXX: Is this a problem performance-wise?
              });
  
              debug('Created mask for ', attribute.name, mask, value);
              value = parseInt(mask, 2);
  
            }
          }
  
          if (attribute.enum) {
            switch(typeof value) {
              case 'string':
                value = attribute.enum[value];
                break;
              case 'number':
                value = attribute.enum.get(value);
                break;
            }
            value = value.value;
          }
  
          builder[attribute.type](value);
        };
      }
  
      if (!type.read) {
        type.read = function(parser, attribute) {
          parser[attribute.type](attribute.name);
  
          /*parser.tap(function() {
            debug('Read attribute', attribute.name, this.vars[attribute.name]);
          });*/
  
          if (attribute.mask) {
  
            parser.tap(function() {
              var value = {};
              this.vars[attribute.name].toString(2).split('').reverse().forEach(function(bit, pos) {
                value[attribute.mask[pos]] = (bit === '1');
              });
              this.vars[attribute.name] = value;
            });
          }
        };
      }
  
    });
  
    //debug('Resolved types', types);
  
    return types;
  }