001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2026 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.assign;
015
016import java.util.Collection;
017import java.util.SequencedSet;
018
019import javax.lang.model.element.Element;
020
021import javax.lang.model.AnnotatedConstruct;
022
023import java.util.function.Function;
024
025import static java.util.Collections.unmodifiableSequencedSet;
026
027import static java.util.LinkedHashSet.newLinkedHashSet;
028
029/**
030 * An object with {@linkplain #dependencies() dependencies}.
031 *
032 * <p>By default, {@link Aggregate}s have {@linkplain #EMPTY_DEPENDENCIES no dependencies}.</p>
033 *
034 * @author <a href="https://about.me/lairdnelson/" target="_top">Laird Nelson</a>
035 *
036 * @see #dependencies()
037 */
038public interface Aggregate {
039
040
041  /*
042   * Static fields.
043   */
044
045
046  /**
047   * An immutable, empty {@link SequencedSet} of {@link Assignment}s.
048   */
049  public static final SequencedSet<Assignment<?>> EMPTY_ASSIGNMENTS = unmodifiableSequencedSet(newLinkedHashSet(0));
050
051  /**
052   * An immutable, empty {@link SequencedSet} of {@link Element}s.
053   */
054  public static final SequencedSet<Annotated<Element>> EMPTY_DEPENDENCIES = unmodifiableSequencedSet(newLinkedHashSet(0));
055
056
057  /*
058   * Default instance methods.
059   */
060
061
062  /**
063   * Returns an immutable, determinate, {@link SequencedSet} of {@link Annotated Annotated&lt;? extends Element&gt;}
064   * instances.
065   *
066   * <p>If an {@link Annotated Annotated&lt;? extends Element&gt;} in the set represents this very {@link Aggregate}
067   * implementation, undefined behavior, including the possibility of infinite loops, may result (an {@link Aggregate}
068   * may not have itself as a dependency).</p>
069   *
070   * <p>Note that it is permissible for an {@link Annotated Annotated&lt;? extends Element&gt;} in the set to represent
071   * another type.</p>
072   *
073   * <p>The default implementation of this method returns the value of the {@link #EMPTY_DEPENDENCIES} field.</p>
074   *
075   * @return an immutable, determinate, {@link SequencedSet} of {@link Annotated Annotated&lt;? extends Element&gt;}
076   * instances; never {@code null}
077   *
078   * @see Annotated
079   *
080   * @see Annotated#of(AnnotatedConstruct)
081   */
082  public default SequencedSet<? extends Annotated<? extends Element>> dependencies() {
083    return EMPTY_DEPENDENCIES;
084  }
085
086  /**
087   * A convenience method that assigns a contextual reference to each of this {@link Aggregate}'s {@link Annotated
088   * Annotated&lt;? extends Element&gt;}-typed {@linkplain #dependencies() dependencies} and returns the resulting
089   * {@link SequencedSet} of {@link Assignment}s.
090   *
091   * <p><strong>Note:</strong> Undefined behavior may result if an {@link Annotated Annotated&lt;? extends Element&gt;}
092   * in the {@linkplain #dependencies() dependencies} represents this {@link Aggregate} implementation (an {@link
093   * Aggregate} may not have itself as a dependency).</p>
094   *
095   * <p>Typically there is no need to override this method.</p>
096   *
097   * <p>Usage of this method is not required.</p>
098   *
099   * @param r a {@link Function} that retrieves a contextual reference suitable for an {@link Annotated Annotated&lt;?
100   * extends AnnotatedConstruct&gt;}; if {@link #dependencies()} returns a non-empty {@link SequencedSet} then this
101   * argument must not be {@code null}
102   *
103   * @return an immutable {@link SequencedSet} of {@link Assignment} instances; never {@code null}
104   *
105   * @exception NullPointerException if {@code r} is {@code null}
106   */
107  // (Convenience.)
108  public default SequencedSet<? extends Assignment<?>> assign(final Function<? super Annotated<? extends AnnotatedConstruct>, ?> r) {
109    final Collection<? extends Annotated<? extends Element>> ds = this.dependencies();
110    if (ds == null || ds.isEmpty()) {
111      return EMPTY_ASSIGNMENTS;
112    }
113    final SequencedSet<Assignment<?>> assignments = newLinkedHashSet(ds.size());
114    ds.forEach(d -> assignments.add(new Assignment<>(d, r.apply(d))));
115    return unmodifiableSequencedSet(assignments);
116  }
117
118}