view mde/mergetag/dataset.d @ 8:f63f4f41a2dc

Big changes to init; got some way towards input event support; changed mergetag ID to char[] from uint. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 25 Jan 2008 18:17:38 +0000
parents b544c3a7c9ca
children 1885a9080f2a
line wrap: on
line source

/// This module contains the mergetag DataSet class together with an interface for DataSections.
module mde.mergetag.dataset;

// package imports
public import mde.mergetag.exception;
public import mde.mergetag.defaultdata;	// used in DataSet so it should be publically imported

//import tango.util.log.Log : Log, Logger;

/** Typedef for data & section indexes (can be changed to ulong if necessary.) */
typedef char[] ID;

package struct MTFormatVersion {
    enum VERS : ubyte {	// convenient list of all known file format versions
        INVALID	= 0x00,
        MT01	= 0x01,		// not yet final
    }
    /// The current MergeTag version
    static const VERS Current = VERS.MT01;
    static const char[2] CurrentString = "01";
    
    static VERS parseString (char[] str)
    in {
            assert (str.length == 2);
    } body {
        if (str[0] == '0' && str[1] == '1') return VERS.MT01;
        else return VERS.INVALID;
    }
}

/+private Logger logger;
static this () {
    logger = Log.getLogger ("mde.mergetag.dataset");
}+/

/**************************************************************************************************
 * Data class; contains a DataSection class instance for each loaded section of a file.
 *
 * Stored data is available for direct access via header and sec; all functions are just helper
 * functions.
 *
 * Any class implementing DataSection may be used to store data; by default a DefaultData class is
 * used when reading a file. Another class may be used by creating the sections before reading the
 * file or passing the reader a function to create the sections (see Reader.dataSecCreator).
 *
 * Could be a struct, except that structs are value types (not reference types).
 */
class DataSet
{
    DefaultData header;			/// Header section.
    DataSection[ID] sec;		/// Dynamic array of sections
    
    /// Template to return all sections of a child-class type.
    T[ID] getSections (T : DataSection) () {
        T[ID] ret;
        foreach (ID id, DataSection s; sec) {
            T x = cast(T) s;
            if (x) ret[id] = x;	// if non-null
        }
        return ret;
    }
}

/**
 * Interface for data storage classes, which contain all data-tags loaded from a single section of a
 * file.
 *
 * A class implementing this may implement the addTag function to do whatever it likes with the
 * data passed; DefaultData separates this data out into supported types and stores it
 * appropriately, while throwing an error when unsupported types are passed, but a different
 * implementation could filter out the tags desired and use them directly, while ignoring the rest.
 * The parse module provides a useful set of templated functions to
 * convert the data accordingly. It is advised to keep the type definitions as defined in the file-
 * format except for user-defined types.
 *
 * Another idea for a DataSection class:
 * Use a void*[ID] variable to store all data (may also need a type var for each item).
 * addTag should call a templated function which calls parse then casts to a void* and stores the data.
 * Use a templated get(T)(ID) method which checks the type and casts to T.
 */
interface DataSection
{
    typedef void delegate (char[],ID,char[]) ItemDelg;
    /** Handles parsing of data items for all recognised types.
     *
     * Should throw an MTUnknownTypeException for unsupported types with a short explanation of the
     * form: "Package ClassName: supported types" or similar.
     *
     * Only MTUnknownTypeException and MTaddTagParseException exceptions are caught by a reader
     * calling addTag. */
    void addTag (char[],ID,char[]);
    void writeAll (ItemDelg);	/// TBD
    debug void debugFunc ();		/// Run in debug builds after parseSection.
}

unittest {	// Only covers DataSet really.
    DataSet ds = new DataSet;
    ds.sec[1] = new DefaultData;
    assert (ds.getSections!(DefaultData)().length == 1);
    ds.sec[1].addTag ("int",0," -543 ");
    assert (ds.getSections!(DefaultData)()[1]._int[0] == -543);
}