/* Supporting class for CStruct. Used to describe a
  field in a C structure object. */!!

inherit(Object, #FieldInfo,
#(name      /* field name */
type      /* field type symbol */
offset    /* starting byte offset in struct */
elements  /* num elements if arrayed */), 2, nil)!!

now(class(FieldInfo))!!

now(FieldInfo)!!

/* Return the number of bytes occupied by this field. */
Def bytes(self)
{ ^elements * length(type);
}!!

/* Return the number of elements in the field. */
Def elements(self)
{ ^elements;
}!!

/* Execute the fetch demon for this field's type. */
Def fetch(self, struct, base | coll len)
{ if elements = 1
  then ^fetch(type, struct, offset+base);
  endif;
  if type(type) == #char
  then coll := new(String, elements);
  else coll := new(Array, elements);
  endif;
  len := length(type);
  do(elements,
  {using(x) coll[x] := fetch(type, struct,
    base+offset+x*len);
  });
  ^coll;
}!!

/* Initialize a FieldInfo object with the given values. */
Def init(self, n, t, o, e)
{ name := n;
  type := t;
  offset := o;
  elements := e;
}!!

/* Return the field name. */
Def name(self)
{ ^name;
}!!

/* Return the starting byte offset of the field in memory. */
Def offset(self)
{ ^offset;
}!!

/* Print receiver to specified stream. */
Def printOn(self, aStream)
{ printOn(tuple(type, ' ', name), aStream);
  if elements > 1
  then printOn(tuple('[', elements, ']'), aStream);
  endif;
}!!

/* Execute the store demon for this field's type. */
Def store(self, struct, val, base | idx)
{ if elements = 1
  then ^store(type, struct, val, base+offset);
  endif;
  idx := 0;
  do(val,
  {using(elem)
    if idx < elements
    then storeElement(self, struct, elem, idx, base);
    else ^val;
    endif;
    idx := idx + 1;
  });
  ^val;
}!!

/* Store a logical element of this arrayed field. */
Def storeElement(self, aCStruct, val, offs, base | coll)
{ if offs >= elements
  then alert(System, self, #rangeError)
  endif;
  ^store(type, aCStruct, val, base + offset + length(type) * offs);
}!!

/* Return the field type. */
Def type(self)
{ ^type;
}!!
