001 // Copyright 2008 Waterken Inc. under the terms of the MIT X license found at
002 // http://www.opensource.org/licenses/mit-license.html
003 package org.ref_send.scope;
004
005 import java.io.Serializable;
006
007 import org.joe_e.Powerless;
008 import org.joe_e.Selfless;
009 import org.joe_e.array.ConstArray;
010 import org.joe_e.array.PowerlessArray;
011 import org.ref_send.Record;
012 import org.ref_send.deserializer;
013 import org.ref_send.name;
014
015 /**
016 * Structural type of a {@linkplain Scope}.
017 * @param <T> nominal type
018 */
019 public final class
020 Layout<T> implements Powerless, Record, Selfless, Serializable {
021 static private final long serialVersionUID = 1L;
022
023 /**
024 * each member name
025 * <p>
026 * A member name MUST NOT be either {@code null} or {@code "@"}, and MUST
027 * be unique within the list of member names.
028 * </p>
029 */
030 public final PowerlessArray<String> names;
031
032 /**
033 * Constructs an instance.
034 * @param names {@link #names}
035 */
036 public @deserializer
037 Layout(@name("names") final PowerlessArray<String> names) {
038 for (int i = names.length(); 0 != i--;) {
039 final String name = names.get(i);
040 if (name.equals("@")) { throw new Unavailable(name); }
041 for (int j = i; 0 != j--;) {
042 if (name.equals(names.get(j))) { throw new Unavailable(name); }
043 }
044 }
045
046 this.names = names;
047 }
048
049 /**
050 * Defines a new structural type.
051 * @param <T> nominal type
052 * @param names {@link #names}
053 */
054 static public <T> Layout<T>
055 define(final String... names) {
056 return new Layout<T>(PowerlessArray.array(names));
057 }
058
059 // java.lang.Object interface
060
061 /**
062 * Is the given object the same?
063 * @param o compared to object
064 * @return <code>true</code> if the same, else <code>false</code>
065 */
066 public boolean
067 equals(final Object o) {
068 return null != o && Layout.class == o.getClass() &&
069 names.equals(((Layout<?>)o).names);
070 }
071
072 /**
073 * Calculates the hash code.
074 */
075 public int
076 hashCode() { return 0x4EF2A3E5 + names.hashCode(); }
077
078 // org.ref_send.scope.Layout interface
079
080 /**
081 * Constructs a scope.
082 * @param values {@link Scope#values}
083 */
084 public Scope<T>
085 make(final Object... values) {
086 return new Scope<T>(this, ConstArray.array(values));
087 }
088
089 /**
090 * Does a given scope conform to this structural type?
091 * @param scope instance to check
092 */
093 public boolean
094 of(final Scope<T> scope) { return names.equals(scope.meta.names); }
095
096 /**
097 * Finds the index of the named member.
098 * @param name searched for member name
099 * @return found index, or {@code -1} if not found
100 */
101 public int
102 find(final String name) {
103 int i = names.length();
104 while (0 != i-- && !names.get(i).equals(name)) {}
105 return i;
106 }
107 }