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 }