1 module hunt.Enum;
2 
3 import hunt.Exceptions;
4 import hunt.util.Common;
5 import hunt.util.Comparator;
6 
7 import std.traits;
8 
9 /**
10 */
11 interface Enum(E) : Comparable!E {
12     
13     string name();
14 
15     int ordinal();
16 
17     string toString();
18 }
19 
20 /**
21  * This is the common base class of all enumeration types.
22  */
23 abstract class AbstractEnum(E) : Enum!E {
24 
25     /**
26      * Sole constructor.  Programmers cannot invoke this constructor.
27      * It is for use by code emitted by the compiler in response to
28      * enum type declarations.
29      *
30      * @param name - The name of this enum constant, which is the identifier
31      *               used to declare it.
32      * @param ordinal - The ordinal of this enumeration constant (its position
33      *         in the enum declaration, where the initial constant is assigned
34      *         an ordinal of zero).
35      */
36     protected this(string name, int ordinal) {
37         this._name = name;
38         this._ordinal = ordinal;
39     }
40     
41     /**
42      * The name of this enum constant, as declared in the enum declaration.
43      * Most programmers should use the {@link #toString} method rather than
44      * accessing this field.
45      */
46     protected string _name;
47 
48     /**
49      * Returns the name of this enum constant, exactly as declared in its
50      * enum declaration.
51      *
52      * <b>Most programmers should use the {@link #toString} method in
53      * preference to this one, as the toString method may return
54      * a more user-friendly name.</b>  This method is designed primarily for
55      * use in specialized situations where correctness depends on getting the
56      * exact name, which will not vary from release to release.
57      *
58      * @return the name of this enum constant
59      */
60     final string name() {
61         return _name;
62     }
63 
64     /**
65      * The ordinal of this enumeration constant (its position
66      * in the enum declaration, where the initial constant is assigned
67      * an ordinal of zero).
68      *
69      * Most programmers will have no use for this field.  It is designed
70      * for use by sophisticated enum-based data structures, such as
71      * {@link java.util.EnumSet} and {@link java.util.EnumMap}.
72      */
73     protected int _ordinal;
74 
75     /**
76      * Returns the ordinal of this enumeration constant (its position
77      * in its enum declaration, where the initial constant is assigned
78      * an ordinal of zero).
79      *
80      * Most programmers will have no use for this method.  It is
81      * designed for use by sophisticated enum-based data structures, such
82      * as {@link java.util.EnumSet} and {@link java.util.EnumMap}.
83      *
84      * @return the ordinal of this enumeration constant
85      */
86     final int ordinal() {
87         return _ordinal;
88     }
89 
90     /**
91      * Returns the name of this enum constant, as contained in the
92      * declaration.  This method may be overridden, though it typically
93      * isn't necessary or desirable.  An enum type should override this
94      * method when a more "programmer-friendly" string form exists.
95      *
96      * @return the name of this enum constant
97      */
98     override string toString() {
99         return _name;
100     }
101 
102     /**
103      * Returns true if the specified object is equal to this
104      * enum constant.
105      *
106      * @param other the object to be compared for equality with this object.
107      * @return  true if the specified object is equal to this
108      *          enum constant.
109      */
110     final override bool opEquals(Object other) {
111         return this is other;
112     }
113 
114     /**
115      * Returns a hash code for this enum constant.
116      *
117      * @return a hash code for this enum constant.
118      */
119     // final int hashCode() {
120     //     return super.hashCode();
121     // }
122 
123     /**
124      * Throws CloneNotSupportedException.  This guarantees that enums
125      * are never cloned, which is necessary to preserve their "singleton"
126      * status.
127      *
128      * @return (never returns)
129      */
130     // protected final Object clone() {
131     //     throw new CloneNotSupportedException();
132     // }
133 
134     /**
135      * Compares this enum with the specified object for order.  Returns a
136      * negative integer, zero, or a positive integer as this object is less
137      * than, equal to, or greater than the specified object.
138      *
139      * Enum constants are only comparable to other enum constants of the
140      * same enum type.  The natural order implemented by this
141      * method is the order in which the constants are declared.
142      */
143     final int opCmp(E o) {
144         Enum!E other = cast(Enum!E) o;
145         Enum!E self = this;
146         if (other is null)
147             throw new NullPointerException();
148         return compare(self.ordinal, other.ordinal);
149     }
150 }
151 
152 
153 
154 
155 
156 /**
157  * Returns the enum constant of the specified enum type with the
158  * specified name.  The name must match exactly an identifier used
159  * to declare an enum constant in this type.  (Extraneous whitespace
160  * characters are not permitted.)
161  *
162  * <p>Note that for a particular enum type {@code T}, the
163  * implicitly declared {@code static T valueOf(string)}
164  * method on that enum may be used instead of this method to map
165  * from a name to the corresponding enum constant.  All the
166  * constants of an enum type can be obtained by calling the
167  * implicit {@code static T[] values()} method of that
168  * type.
169  *
170  * @param <T> The enum type whose constant is to be returned
171  * @param enumType the {@code Class} object of the enum type from which
172  *      to return a constant
173  * @param name the name of the constant to return
174  * @return the enum constant of the specified enum type with the
175  *      specified name
176  * @throws IllegalArgumentException if the specified enum type has
177  *         no constant with the specified name, or the specified
178  *         class object does not represent an enum type
179  */    
180 T valueOf(T)(string name, T defaultValue = T.init) if(is(T : Enum!(T))) {
181     static if(hasStaticMember!(T, "values")) {
182             enum string code = generateLocator!(T, "values", name.stringof, defaultValue.stringof)();
183             mixin(code);
184     } else {
185         static assert(false, "Can't find static member values in " ~ fullyQualifiedName!T ~ ".");
186     }
187 }
188 
189  private string generateLocator(T, string memberName, string paramName, string defaultValue)() 
190     if(is(T : Enum!(T))) {
191     import std.format;
192     string s;
193 
194     s = format(`
195         foreach(T t; T.%1$s) {
196             if(t.name() == %2$s) return t;
197         }
198         
199         import hunt.logging;
200         warning("Can't locate the member: " ~ %2$s ~ " in " ~ typeid(T).name ~ ".%1$s");
201         return %3$s;`, memberName, paramName, defaultValue);
202 
203     return s;
204 }