diff --git a/source/tanya/typecons.d b/source/tanya/typecons.d index d92cc4d..c828ab0 100644 --- a/source/tanya/typecons.d +++ b/source/tanya/typecons.d @@ -17,23 +17,9 @@ */ module tanya.typecons; -import tanya.meta.metafunction; +import tanya.meta.metafunction : AliasSeq, AliasTuple = Tuple, Map; -/** - * $(D_PSYMBOL Pair) can store two heterogeneous objects. - * - * The objects can by accessed by index as $(D_INLINECODE obj[0]) and - * $(D_INLINECODE obj[1]) or by optional names (e.g. - * $(D_INLINECODE obj.first)). - * - * $(D_PARAM Specs) contains a list of object types and names. First - * comes the object type, then an optional string containing the name. - * If you want the object be accessible only by its index (`0` or `1`), - * just skip the name. - * - * Params: - * Specs = Field types and names. - */ +deprecated("Use tanya.typecons.Tuple instead") template Pair(Specs...) { template parseSpecs(size_t fieldCount, Specs...) @@ -47,13 +33,13 @@ template Pair(Specs...) static if (is(typeof(Specs[1]) == string)) { alias parseSpecs - = AliasSeq!(Tuple!(Specs[0], Specs[1]), + = AliasSeq!(AliasTuple!(Specs[0], Specs[1]), parseSpecs!(fieldCount + 1, Specs[2 .. $])); } else { alias parseSpecs - = AliasSeq!(Tuple!(Specs[0]), + = AliasSeq!(AliasTuple!(Specs[0]), parseSpecs!(fieldCount + 1, Specs[1 .. $])); } } @@ -90,10 +76,81 @@ template Pair(Specs...) } } +/** + * $(D_PSYMBOL Tuple) can store two heterogeneous objects. + * + * The objects can by accessed by index as $(D_INLINECODE obj[0]) and + * $(D_INLINECODE obj[1]) or by optional names (e.g. + * $(D_INLINECODE obj.first)). + * + * $(D_PARAM Specs) contains a list of object types and names. First + * comes the object type, then an optional string containing the name. + * If you want the object be accessible only by its index (`0` or `1`), + * just skip the name. + * + * Params: + * Specs = Field types and names. + */ +template Tuple(Specs...) +{ + template parseSpecs(size_t fieldCount, Specs...) + { + static if (Specs.length == 0) + { + alias parseSpecs = AliasSeq!(); + } + else static if (is(Specs[0]) && fieldCount < 2) + { + static if (is(typeof(Specs[1]) == string)) + { + alias parseSpecs + = AliasSeq!(AliasTuple!(Specs[0], Specs[1]), + parseSpecs!(fieldCount + 1, Specs[2 .. $])); + } + else + { + alias parseSpecs + = AliasSeq!(AliasTuple!(Specs[0]), + parseSpecs!(fieldCount + 1, Specs[1 .. $])); + } + } + else + { + static assert(false, "Invalid argument: " ~ Specs[0].stringof); + } + } + + alias ChooseType(alias T) = T.Seq[0]; + alias ParsedSpecs = parseSpecs!(0, Specs); + + static assert(ParsedSpecs.length == 2, "Invalid argument count"); + + struct Tuple + { + /// Field types. + alias Types = Map!(ChooseType, ParsedSpecs); + + // Create field aliases. + static if (ParsedSpecs[0].length == 2) + { + mixin("alias " ~ ParsedSpecs[0][1] ~ " = expand[0];"); + } + static if (ParsedSpecs[1].length == 2) + { + mixin("alias " ~ ParsedSpecs[1][1] ~ " = expand[1];"); + } + + /// Represents the values of the $(D_PSYMBOL Tuple) as a list of values. + Types expand; + + alias expand this; + } +} + /// @nogc nothrow pure @safe unittest { - auto pair = Pair!(int, "first", string, "second")(1, "second"); + auto pair = Tuple!(int, "first", string, "second")(1, "second"); assert(pair.first == 1); assert(pair[0] == 1); assert(pair.second == "second"); @@ -102,16 +159,16 @@ template Pair(Specs...) @nogc nothrow pure @safe unittest { - static assert(is(Pair!(int, int))); - static assert(!is(Pair!(int, 5))); + static assert(is(Tuple!(int, int))); + static assert(!is(Tuple!(int, 5))); - static assert(is(Pair!(int, "first", int))); - static assert(is(Pair!(int, "first", int, "second"))); - static assert(is(Pair!(int, "first", int))); + static assert(is(Tuple!(int, "first", int))); + static assert(is(Tuple!(int, "first", int, "second"))); + static assert(is(Tuple!(int, "first", int))); - static assert(is(Pair!(int, int, "second"))); - static assert(!is(Pair!("first", int, "second", int))); - static assert(!is(Pair!(int, int, int))); + static assert(is(Tuple!(int, int, "second"))); + static assert(!is(Tuple!("first", int, "second", int))); + static assert(!is(Tuple!(int, int, int))); - static assert(!is(Pair!(int, "first"))); + static assert(!is(Tuple!(int, "first"))); }