/* Placed into the public domain */
#ifndef CCAN_TCON_H
#define CCAN_TCON_H
#include "config.h"

/**
 * TCON - declare a _tcon type containing canary variables.
 * @decls: the semi-colon separated list of type canaries.
 *
 * This declares a _tcon member for a structure.  It should be the
 * last element in your structure; with sufficient compiler support it
 * will not use any actual storage.  tcon_check() will compare
 * expressions with one of these "type canaries" to cause warnings if
 * the container is misused.
 *
 * A type of "void *" will allow tcon_check() to pass on any (pointer) type.
 *
 * Example:
 *	// Simply typesafe linked list.
 *	struct list_head {
 *		struct list_head *prev, *next;
 *	};
 *
 *	struct string_list {
 *		struct list_head raw;
 *		TCON(char *canary);
 *	};
 *
 *	// More complex: mapping from one type to another.
 *	struct map {
 *		void *contents;
 *	};
 *
 *	struct int_to_string_map {
 *		struct map raw;
 *		TCON(char *charp_canary; int int_canary);
 *	};
 */
#if HAVE_FLEXIBLE_ARRAY_MEMBER
#define TCON(decls) struct { decls; } _tcon[]
#else
#define TCON(decls) struct { decls; } _tcon[1]
#endif

/**
 * tcon_check - typecheck a typed container
 * @x: the structure containing the TCON.
 * @canary: which canary to check against.
 * @expr: the expression whose type must match the TCON (not evaluated)
 *
 * This macro is used to check that the expression is the type
 * expected for this structure (note the "useless" sizeof() argument
 * which contains this comparison with the type canary).
 *
 * It evaluates to @x so you can chain it.
 *
 * Example:
 *	#define tlist_add(h, n, member) \
 *		list_add(&tcon_check((h), canary, (n))->raw, &(n)->member)
 */
#define tcon_check(x, canary, expr)				\
	(sizeof((x)->_tcon[0].canary == (expr)) ? (x) : (x))

/**
 * tcon_check_ptr - typecheck a typed container
 * @x: the structure containing the TCON.
 * @canary: which canary to check against.
 * @expr: the expression whose type must match &TCON (not evaluated)
 *
 * This macro is used to check that the expression is a pointer to the type
 * expected for this structure (note the "useless" sizeof() argument
 * which contains this comparison with the type canary), or NULL.
 *
 * It evaluates to @x so you can chain it.
 */
#define tcon_check_ptr(x, canary, expr)				\
	(sizeof(&(x)->_tcon[0].canary == (expr)) ? (x) : (x))


/**
 * tcon_type - the type within a container (or void *)
 * @x: the structure containing the TCON.
 * @canary: which canary to check against.
 */
#if HAVE_TYPEOF
#define tcon_type(x, canary) __typeof__((x)->_tcon[0].canary)
#else
#define tcon_type(x, canary) void *
#endif

/**
 * tcon_ptr_type - pointer to the type within a container (or void *)
 * @x: the structure containing the TCON.
 * @canary: which canary to check against.
 */
#if HAVE_TYPEOF
#define tcon_ptr_type(x, canary) __typeof__(&(x)->_tcon[0].canary)
#else
#define tcon_ptr_type(x, canary) void *
#endif

/**
 * tcon_cast - cast to a canary type for this container (or void *)
 * @x: a structure containing the TCON.
 * @canary: which canary to cast to.
 * @expr: the value to cast
 *
 * This is used to cast to the correct type for this container.  If the
 * platform doesn't HAVE_TYPEOF, then it casts to void * (which will
 * cause a warning if the user doesn't expect a pointer type).
 */
#define tcon_cast(x, canary, expr) ((tcon_type((x), canary))(expr))
#define tcon_cast_ptr(x, canary, expr) ((tcon_ptr_type((x), canary))(expr))

#endif /* CCAN_TCON_H */
