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<? extends Element>} 064 * instances. 065 * 066 * <p>If an {@link Annotated Annotated<? extends Element>} 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<? extends Element>} 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<? extends Element>} 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<? extends Element>}-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<? extends Element>} 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<? 100 * extends AnnotatedConstruct>}; 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}