1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2021 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.spi.model; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static com.google.common.base.Preconditions.checkState; 20*f585d8a3SJacky Wang import static com.google.common.collect.Iterables.getLast; 21*f585d8a3SJacky Wang import static java.util.stream.Collectors.joining; 22*f585d8a3SJacky Wang 23*f585d8a3SJacky Wang import com.google.auto.value.AutoValue; 24*f585d8a3SJacky Wang import com.google.auto.value.extension.memoized.Memoized; 25*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList; 26*f585d8a3SJacky Wang 27*f585d8a3SJacky Wang /** A path containing a component and all of its ancestor components. */ 28*f585d8a3SJacky Wang @AutoValue 29*f585d8a3SJacky Wang public abstract class ComponentPath { 30*f585d8a3SJacky Wang /** Returns a new {@link ComponentPath} from {@code components}. */ create(Iterable<DaggerTypeElement> components)31*f585d8a3SJacky Wang public static ComponentPath create(Iterable<DaggerTypeElement> components) { 32*f585d8a3SJacky Wang return new AutoValue_ComponentPath(ImmutableList.copyOf(components)); 33*f585d8a3SJacky Wang } 34*f585d8a3SJacky Wang 35*f585d8a3SJacky Wang /** 36*f585d8a3SJacky Wang * Returns the component types, starting from the {@linkplain #rootComponent() root 37*f585d8a3SJacky Wang * component} and ending with the {@linkplain #currentComponent() current component}. 38*f585d8a3SJacky Wang */ components()39*f585d8a3SJacky Wang public abstract ImmutableList<DaggerTypeElement> components(); 40*f585d8a3SJacky Wang 41*f585d8a3SJacky Wang /** 42*f585d8a3SJacky Wang * Returns the root {@code Component}- or {@code ProductionComponent}-annotated type 43*f585d8a3SJacky Wang */ rootComponent()44*f585d8a3SJacky Wang public final DaggerTypeElement rootComponent() { 45*f585d8a3SJacky Wang return components().get(0); 46*f585d8a3SJacky Wang } 47*f585d8a3SJacky Wang 48*f585d8a3SJacky Wang /** Returns the component at the end of the path. */ 49*f585d8a3SJacky Wang @Memoized currentComponent()50*f585d8a3SJacky Wang public DaggerTypeElement currentComponent() { 51*f585d8a3SJacky Wang return getLast(components()); 52*f585d8a3SJacky Wang } 53*f585d8a3SJacky Wang 54*f585d8a3SJacky Wang /** 55*f585d8a3SJacky Wang * Returns the parent of the {@linkplain #currentComponent()} current component}. 56*f585d8a3SJacky Wang * 57*f585d8a3SJacky Wang * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component} 58*f585d8a3SJacky Wang */ parentComponent()59*f585d8a3SJacky Wang public final DaggerTypeElement parentComponent() { 60*f585d8a3SJacky Wang checkState(!atRoot()); 61*f585d8a3SJacky Wang return components().reverse().get(1); 62*f585d8a3SJacky Wang } 63*f585d8a3SJacky Wang 64*f585d8a3SJacky Wang /** 65*f585d8a3SJacky Wang * Returns this path's parent path. 66*f585d8a3SJacky Wang * 67*f585d8a3SJacky Wang * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component} 68*f585d8a3SJacky Wang */ 69*f585d8a3SJacky Wang // TODO(ronshapiro): consider memoizing this parent()70*f585d8a3SJacky Wang public final ComponentPath parent() { 71*f585d8a3SJacky Wang checkState(!atRoot()); 72*f585d8a3SJacky Wang return create(components().subList(0, components().size() - 1)); 73*f585d8a3SJacky Wang } 74*f585d8a3SJacky Wang 75*f585d8a3SJacky Wang /** Returns the path from the root component to the {@code child} of the current component. */ childPath(DaggerTypeElement child)76*f585d8a3SJacky Wang public final ComponentPath childPath(DaggerTypeElement child) { 77*f585d8a3SJacky Wang return create( 78*f585d8a3SJacky Wang ImmutableList.<DaggerTypeElement>builder().addAll(components()).add(child).build()); 79*f585d8a3SJacky Wang } 80*f585d8a3SJacky Wang 81*f585d8a3SJacky Wang /** 82*f585d8a3SJacky Wang * Returns {@code true} if the {@linkplain #currentComponent()} current component} is the 83*f585d8a3SJacky Wang * {@linkplain #rootComponent()} root component}. 84*f585d8a3SJacky Wang */ atRoot()85*f585d8a3SJacky Wang public final boolean atRoot() { 86*f585d8a3SJacky Wang return components().size() == 1; 87*f585d8a3SJacky Wang } 88*f585d8a3SJacky Wang 89*f585d8a3SJacky Wang @Override toString()90*f585d8a3SJacky Wang public final String toString() { 91*f585d8a3SJacky Wang return components().stream().map(Key::qualifiedName).collect(joining(" → ")); 92*f585d8a3SJacky Wang } 93*f585d8a3SJacky Wang 94*f585d8a3SJacky Wang @Memoized 95*f585d8a3SJacky Wang @Override hashCode()96*f585d8a3SJacky Wang public abstract int hashCode(); 97*f585d8a3SJacky Wang 98*f585d8a3SJacky Wang @Override equals(Object obj)99*f585d8a3SJacky Wang public abstract boolean equals(Object obj); 100*f585d8a3SJacky Wang } 101