/* This class allows user extensible types for Actor CStructs.
  To create a CStruct it's type must have been previously
  declared UserType. */!!

inherit(CType, #UserType, #(fields /* dictionary of field descriptions */), 2, nil)!!

now(class(UserType))!!

/* Create a new user type of CStruct, and add it to UserTypes.
  Where uName is a symbol that specifies the name of the user
  type and declarations is an array of the form
  (type name elements ...) which defines the fields of a
  user type. Where type is a previously declared CType or
  UserType, name is the symbolic field name and elements
  is the number of elements in the field. The number of
  elements need not be specified, in which case it defaults
  to one. Any number of type name elements occurrences may
  be specified. */
Def def(self, uName, declarations | type len offset tName occ fields idx)
{ offset := idx := 0;
  fields := new(OrderedDictionary, size(declarations) / 3 + 2);
  loop
  while idx + 2 <= size(declarations)
  begin type := findType(self, declarations[idx]);
    len := length(type);
    tName := declarations[idx+1];
    if idx + 2 < size(declarations)
    then occ := declarations[idx+2];
    else occ := nil;
    endif;
    if class(occ) ~= Int
    then idx := idx + 2;
      occ := 1;
    else idx := idx + 3
    endif;
    add(fields, tName, init(new(FieldInfo), tName, type, offset, occ));
    offset := offset + (len * occ);
  endLoop;
  ^register(new(self), uName, fields);
}!!

now(UserType)!!

/* A fetch of a user type returns a new CStruct. */
Def fetch(self, struct, offs | s)
{ s := new(SubStruct);
  ^setFields(s, fields, struct, offs);
}!!

/* Returns dictionary of field descriptions. */
Def fields(self)
{ ^fields;
}!!

/* Register a new user type in the UserTypes dictionary. */
Def register(self, sym, f)
{ name := sym;
  fields := f;
  length := 0;
  do(fields,
  {using(field) length := length + bytes(field);
  });
  add($UserTypes, sym, self);
}!!

/* Set fields to a new value. */
Def setFields(self, f)
{ fields := f;
}!!

/* Execute a store operation. This is not a valid
  user type operation and will generate and error. */
Def store(self, struct, val, offs)
{ alert(System, self, #userTypeStoreError)
}!!
