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    }