<commit_before>/*****************************************************************************
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package com.google.mu.protobuf.util;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.mu.protobuf.util.MoreValues.NULL;
import static com.google.mu.protobuf.util.MoreValues.valueOf;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;

import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.mu.util.stream.BiStream;
import com.google.protobuf.ListValue;
import com.google.protobuf.NullValue;
import com.google.protobuf.Struct;
import com.google.protobuf.Value;

/**
 * A static type-safe builder that supports building heterogeneous {@link Struct} more conveniently,
 * while eliding most of the intermediary and verbose {@link Value} creation.
 *
 * <p>Unlike {@link Struct.Builder}, the {@code add()} methods will throw upon duplicate keys.
 *
 * <p>Compared with {@link MoreStructs#struct}, StructBuilder is more suitable to production code
 * where runtime {@link Value} conversion error caused by unsupported type is undesirable;
 * while MoreStructs is best used in tests and scenarios where runtime conversion error is tolerable.
 *
 * @since 5.8
 */
@CanIgnoreReturnValue
public final class StructBuilder {
  private final LinkedHashMap<String, Value> fields = new LinkedHashMap<>();

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, boolean value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, double value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, String value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}.
   *
   * <p>See {@link MoreValues} for helpers that create common {@link ListValue} conveniently.
   *
   *<p>Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, ListValue value) {
    return add(name, MoreValues.valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Iterable<Value> values) {
    ListValue.Builder listValue = ListValue.newBuilder();
    for (Value v : values) {
      listValue.addValues(v);
    }
    return add(name, listValue.build());
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Struct value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, StructBuilder value) {
    return add(name, value.build());
  }

  /**
   * Adds {@code name} and {@code value}. {@code value} is converted to a nested Struct.
   * Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Map<String, Value> value) {
    return add(name, BiStream.from(value).collect(new StructBuilder(), StructBuilder::add).build());
  }

  /**
   * Adds {@code name} and {@code values}. {@code value} is converted to a nested Struct
   * mapping nested keys to {@code ListValue}.
   *
   * <p>Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Multimap<String, Value> value) {
    return add(
        name, BiStream.from(value.asMap()).collect(new StructBuilder(), StructBuilder::add).build());
  }

  /**
   * Adds {@code name} and {@code value}. {@code value} is converted to a nested Struct
   * mapping nested keys to {@code Struct}.
   *
   * <p>Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Table<String, String, Value> value) {
    return add(
        name, BiStream.from(value.rowMap()).collect(new StructBuilder(), StructBuilder::add).build());
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Value value) {
    checkNotNull(name, "name is null");
    checkNotNull(value, "value is null");
    checkArgument(fields.putIfAbsent(name, value) == null, "Field %s already present", name);
    return this;
  }

  /**
   * Adds {@code name} to be mapped to {@link NullValue}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder addNull(String name) {<commit_msg>listValueOf()<commit_after>/*****************************************************************************
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package com.google.mu.protobuf.util;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.mu.protobuf.util.MoreValues.NULL;
import static com.google.mu.protobuf.util.MoreValues.valueOf;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;

import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.mu.util.stream.BiStream;
import com.google.protobuf.ListValue;
import com.google.protobuf.NullValue;
import com.google.protobuf.Struct;
import com.google.protobuf.Value;

/**
 * A static type-safe builder that supports building heterogeneous {@link Struct} more conveniently,
 * while eliding most of the intermediary and verbose {@link Value} creation.
 *
 * <p>Unlike {@link Struct.Builder}, the {@code add()} methods will throw upon duplicate keys.
 *
 * <p>Compared with {@link MoreStructs#struct}, StructBuilder is more suitable to production code
 * where runtime {@link Value} conversion error caused by unsupported type is undesirable;
 * while MoreStructs is best used in tests and scenarios where runtime conversion error is tolerable.
 *
 * @since 5.8
 */
@CanIgnoreReturnValue
public final class StructBuilder {
  private final LinkedHashMap<String, Value> fields = new LinkedHashMap<>();

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, boolean value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, double value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, String value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}.
   *
   * <p>See {@link MoreValues} for helpers that create common {@link ListValue} conveniently.
   *
   *<p>Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, ListValue value) {
    return add(name, MoreValues.valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Iterable<Value> values) {
    ListValue.Builder listValue = ListValue.newBuilder();
    for (Value v : values) {
      listValue.addValues(v);
    }
    return add(name, listValue.build());
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Struct value) {
    return add(name, valueOf(value));
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, StructBuilder value) {
    return add(name, value.build());
  }

  /**
   * Adds {@code name} and {@code value}. {@code value} is converted to a nested Struct.
   * Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Map<String, Value> value) {
    return add(
        name,
        BiStream.from(value).collect(new StructBuilder(), StructBuilder::add).build());
  }

  /**
   * Adds {@code name} and {@code values}. {@code value} is converted to a nested Struct
   * mapping nested keys to {@code ListValue}.
   *
   * <p>Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Multimap<String, Value> value) {
    return add(
        name,
        BiStream.from(value.asMap()).collect(new StructBuilder(), StructBuilder::add).build());
  }

  /**
   * Adds {@code name} and {@code value}. {@code value} is converted to a nested Struct
   * mapping nested keys to {@code Struct}.
   *
   * <p>Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Table<String, String, Value> value) {
    return add(
        name,
        BiStream.from(value.rowMap()).collect(new StructBuilder(), StructBuilder::add).build());
  }

  /**
   * Adds {@code name} and {@code value}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder add(String name, Value value) {
    checkNotNull(name, "name is null");
    checkNotNull(value, "value is null");
    checkArgument(fields.putIfAbsent(name, value) == null, "Field %s already present", name);
    return this;
  }

  /**
   * Adds {@code name} to be mapped to {@link NullValue}. Returns this.
   *
   * @throws IllegalArgumentException if {@code name} is duplicate
   */
  public StructBuilder addNull(String name) {
{'fraction_non_alphanumeric': 0.14363958960117257, 'fraction_numerical': 0.0009257116408238834, 'mean_word_length': 2.959682345754429, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3404812', 'n_tokens_mistral': 3414, 'n_tokens_neox': 3355, 'n_words': 1149}