#ifndef COMMON_SERIALIZABLE_H
#define COMMON_SERIALIZABLE_H

/*
 * Copyright (c) 2002, The EROS Group, LLC and Johns Hopkins
 * University. All rights reserved.
 * 
 * This software was developed to support the EROS secure operating
 * system project (http://www.eros-os.org). The latest version of
 * the OpenCM software can be found at http://www.opencm.org.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 * 
 * 3. Neither the name of the The EROS Group, LLC nor the name of
 *    Johns Hopkins University, nor the names of its contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/* Serializable -- all serializable entities obey this protocol */

#define OBTYPE(code,schema,nm,prefix,ver) TY_##nm = code,
enum {
#include "OBTYPES.def"
  
  TY_ntypes,
  TY_Serializable    /* means any Serializable object */
};

#define GETTYPE(s) (((Serializable *)(s))->ser_type->typ)

typedef struct DeserializeInfo DeserializeInfo;
struct DeserializeInfo {
  struct SerialType *st;
  uint32_t tyConst;	/* type constant as serialized */
  uint32_t ver;		/* version number as serialized */
};

typedef void (*markfn_t)(Repository*, const char* tn, void* state);

struct rbtree;

#define OBTYPE(code,schema,nm,prefix,ver) \
  extern void *prefix##_deserialize(const DeserializeInfo *, SDR_stream *); \
  extern void prefix##_serialize(SDR_stream *, const void *ob); \
  extern void prefix##_show(const void * ob); \
  extern void prefix##_mark(Repository *r, const void *container, const void * ob, struct rbtree *memObs); \
  extern OC_bool prefix##_check(const void * ob); \
  extern struct SerialType nm##_SerType;

#include "OBTYPES.def"

/** The SerialType record holds the object type/version and the
    per-type functions associated with the object. When deserialize()
    is called, the type has already been read.

    serialize() and show() take non-const objects because they may
    canonicalize the internal representation before displaying the
    object. */
struct SerialType {
  uint32_t typ;		/* type constant for this object */
  uint32_t ver;		/* highest version constant for this object */
  const char *  tyName;		/* used in texty formats */
  void *        (*deserialize) (const DeserializeInfo *, SDR_stream *);
  void          (*serialize)   (SDR_stream *, const void *ob);
  void          (*show)        (const void * ob);
  void          (*mark)        (Repository *r, const void *container,
				const void *ob,
				struct rbtree *memObs);
  OC_bool       (*check)       (const void * ob);
};

/** Serializable objects all start with a record containing the
    SerialType pointer and the object's true name. */
struct Serializable {
  SerialType *ser_type;
  uint32_t   ser_ver; /* serialized version constant for this object */
  OC_bool    canFreeze;
  const char *trueName;
} ;

void ser_init(void *s, SerialType *ty, uint32_t v);

/* Following is vestigial, but preserved against possible future
   need. */
#define SER_MODIFIED(s) do { } while (0)

#define serType ser.ser_type
#define serVer  ser.ser_ver
#define serTrueName ser.ser_trueName
#define serPrefix ser.ser_type->prefix

SerialType *ser_find_type(uint32_t ty);
#if 0
void ser_init(void);
#endif
#define ser_mark(r, pv, v, mo) ((Serializable *)v)->ser_type->mark(r, pv, v, mo)
/* #define mark_addmark(ob,mo,tn) strvec_append(mo,tn) */
void mark_addmark(const void *ob, struct rbtree *mo, const char *tn);

const char *ser_getTrueName(const void *);
void *ser_dup(const void *);

/* Support for assignment guards: */
#define CMVAR(x) cm_##x
#define CMSET(s,x,v)   (((Serializable *)s)->trueName = 0, s->CMVAR(x) = (v))
#define CMGET(s,x)     s->CMVAR(x)
#define CMCLOBBER(s,x) (((Serializable *)s)->trueName = 0, s->CMVAR(x))
#define CM_CANFREEZE(s) ((Serializable *)s)->canFreeze = FALSE
#endif /* COMMON_SERIALIZABLE_H */
