1 /* 2 * Copyright (C) 2017 The Libphonenumber Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.i18n.phonenumbers.metadata.table; 17 18 import static com.google.common.base.Preconditions.checkArgument; 19 20 import com.google.auto.value.AutoValue; 21 import com.google.common.base.Splitter; 22 import java.util.List; 23 import java.util.Optional; 24 import javax.annotation.Nullable; 25 26 /** 27 * A single assignment of a column to a value. This can be used to change values in a 28 * {@code RangeTable} and well as query for ranges with its value. 29 */ 30 @AutoValue 31 public abstract class Assignment<T extends Comparable<T>> { 32 private static final Splitter SPLITTER = Splitter.on("=").limit(2).trimResults(); 33 34 /** 35 * Parses a string of the form {@code "<column>=<value>"} to create an assignment using the given 36 * schema. The named column must exist in the schema, and the associated value must be a valid 37 * value within that column. 38 * <p> 39 * Whitespace before and after the column or value is ignored. If the value is omitted, then an 40 * unassignment is returned. 41 */ parse(String s, Schema schema)42 public static Assignment<?> parse(String s, Schema schema) { 43 List<String> parts = SPLITTER.splitToList(s); 44 checkArgument(parts.size() == 2, "invalid assigment string: %s", s); 45 Column<?> column = schema.getColumn(parts.get(0)); 46 return create(column, column.parse(parts.get(1))); 47 } 48 49 // Type capture around AutoValue is a little painful, so this static helper ... helps. create(Column<T> c, @Nullable Object v)50 private static <T extends Comparable<T>> Assignment<T> create(Column<T> c, @Nullable Object v) { 51 T value = c.cast(v); 52 return new AutoValue_Assignment<>(c, Optional.ofNullable(value)); 53 } 54 55 /** 56 * Returns an assignment in the given column for the specified, non null, value. 57 * <p> 58 * Note that an assignment for the default value of a column will return an explicit assignment 59 * for that value, rather than an "unassignment" in that column; so 60 * {@code Assignment.of(c, c.defaultValue())} is not equal to {@code unassign(c)}, even though 61 * they may have the same effect when applied to a range table, and may even have the same 62 * {@link #toString()} representation (in the case of String columns). 63 */ of(Column<T> c, Object v)64 public static <T extends Comparable<T>> Assignment<T> of(Column<T> c, Object v) { 65 return new AutoValue_Assignment<>(c, Optional.of(c.cast(v))); 66 } 67 68 @SuppressWarnings("unchecked") ofOptional(Column<T> c, Optional<?> v)69 public static <T extends Comparable<T>> Assignment<T> ofOptional(Column<T> c, Optional<?> v) { 70 // Casting the value makes the optional cast below safe. 71 v.ifPresent(c::cast); 72 return new AutoValue_Assignment<>(c, (Optional<T>) v); 73 } 74 75 /** 76 * Returns an unassignment in the given column. The {@link #value()} of this assignment is empty. 77 */ unassign(Column<T> c)78 public static <T extends Comparable<T>> Assignment<T> unassign(Column<T> c) { 79 return new AutoValue_Assignment<>(c, Optional.empty()); 80 } 81 82 /** The column in which the assignment applies. */ column()83 public abstract Column<T> column(); 84 85 /** The value in the column, or empty to signify unassignment. */ value()86 public abstract Optional<T> value(); 87 88 @Override toString()89 public final String toString() { 90 return String.format("%s=%s", column().getName(), value().map(Object::toString).orElse("")); 91 } 92 } 93