package org.stianloader.smatterdi; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; public class SimpleInjectionContextImpl implements InjectionContext { private static final class InstanceValue { @NotNull private final Lazy value = new Lazy<>(() -> { return this.supplier.get(); }); @NotNull private Supplier supplier; public InstanceValue(@NotNull Supplier supplier) { this.supplier = supplier; } @Contract(mutates = "this", pure = false, value = "-> this") public InstanceValue set() { this.value.get(); return this; } } @NotNull private final Map, InstanceValue> instances; public SimpleInjectionContextImpl() { this.instances = new ConcurrentHashMap<>(); } public SimpleInjectionContextImpl(@NotNull SimpleInjectionContextImpl impl) { this.instances = new ConcurrentHashMap<>(impl.instances); } @Override public T getInstance(Class type) { @SuppressWarnings("unchecked") InstanceValue instance = (InstanceValue) this.instances.get(type); if (instance == null) { throw new IllegalArgumentException("No implementation of template type '" + type + "'!"); } return instance.value.get(); } public void setImplementation(@NotNull Class type, @NotNull T value) { this.instances.compute(type, (ignore, instanceValue) -> { if (instanceValue != null && !instanceValue.value.isDone()) { instanceValue.supplier = () -> value; if (!instanceValue.value.isDone()) { return instanceValue; } } return new InstanceValue<>(() -> value); }); } @SuppressWarnings({ "unchecked" }) public void setProvider(@NotNull Class type, @NotNull Supplier value) { this.instances.compute(type, (ignore, instanceValue) -> { if (instanceValue != null && !instanceValue.value.isDone()) { instanceValue.supplier = (Supplier) value; if (!instanceValue.value.isDone()) { return instanceValue; } } return new InstanceValue<>((Supplier) value); }); } public void removeImplementation(@NotNull Class type) { this.instances.remove(type); } @Override public void autowire(Class type, T instance) { this.instances.putIfAbsent(type, new InstanceValue(() -> instance).set()); } }