3636import works .bosk .exceptions .ReferenceBindingException ;
3737import works .bosk .util .Classes ;
3838
39+ import static java .lang .Thread .holdsLock ;
3940import static java .util .Collections .unmodifiableCollection ;
4041import static java .util .Objects .requireNonNull ;
4142import static java .util .UUID .randomUUID ;
@@ -109,9 +110,9 @@ public class Bosk<R extends StateTreeNode> implements BoskInfo<R> {
109110 @ SuppressWarnings ("this-escape" )
110111 public Bosk (String name , Type rootType , DefaultRootFunction <R > defaultRootFunction , DriverFactory <R > driverFactory ) {
111112 this .name = name ;
113+ this .pathCompiler = PathCompiler .withSourceType (rootType ); // Required before rootRef
112114 this .localDriver = new LocalDriver (defaultRootFunction );
113115 this .rootRef = new RootRef (rootType );
114- this .pathCompiler = PathCompiler .withSourceType (rootType );
115116 try {
116117 validateType (rootType );
117118 } catch (InvalidTypeException e ) {
@@ -223,9 +224,9 @@ public <T> void submitConditionalReplacement(Reference<T> target, T newValue, Re
223224 }
224225
225226 @ Override
226- public <T > void submitInitialization (Reference <T > target , T newValue ) {
227+ public <T > void submitConditionalCreation (Reference <T > target , T newValue ) {
227228 assertCorrectBosk (target );
228- downstream .submitInitialization (target , newValue );
229+ downstream .submitConditionalCreation (target , newValue );
229230 }
230231
231232 @ Override
@@ -277,11 +278,13 @@ private <T> void assertCorrectBosk(Reference<T> target) {
277278 * When it comes to hooks, this provides three guarantees:
278279 *
279280 * <ol><li>
280- * All updates submitted to this driver are applied to the Bosk state in order.
281+ * Updates submitted to this driver are applied to the Bosk state in the order they were submitted .
281282 * </li><li>
282283 * Hooks are run sequentially: no hook begins until the previous one finishes.
283284 * </li><li>
284- * Hooks are run in breadth-first fashion.
285+ * Hooks are run in <em>breadth-first</em> fashion:
286+ * hooks triggered by one update run before any hooks triggered by subsequent updates,
287+ * even if those hooks themselves submit more updates.
285288 * </li></ol>
286289 *
287290 * Satisfying all of these simultaneously is tricky, especially because we can't just put
@@ -320,7 +323,7 @@ public <T> void submitReplacement(Reference<T> target, T newValue) {
320323 }
321324
322325 @ Override
323- public <T > void submitInitialization (Reference <T > target , T newValue ) {
326+ public <T > void submitConditionalCreation (Reference <T > target , T newValue ) {
324327 synchronized (this ) {
325328 boolean preconditionsSatisfied ;
326329 try (@ SuppressWarnings ("unused" ) ReadContext executionContext = supersedingReadContext ()) {
@@ -404,7 +407,8 @@ void triggerEverywhere(HookRegistration<?> reg) {
404407 /**
405408 * @return false if the update was ignored
406409 */
407- private synchronized <T > boolean tryGraftReplacement (Reference <T > target , T newValue ) {
410+ private <T > boolean tryGraftReplacement (Reference <T > target , T newValue ) {
411+ assert holdsLock (this );
408412 Dereferencer dereferencer = dereferencerFor (target );
409413 try {
410414 LOGGER .debug ("Applying replacement at {}" , target );
@@ -428,7 +432,8 @@ private synchronized <T> boolean tryGraftReplacement(Reference<T> target, T newV
428432 /**
429433 * @return false if the update was ignored
430434 */
431- private synchronized <T > boolean tryGraftDeletion (Reference <T > target ) {
435+ private <T > boolean tryGraftDeletion (Reference <T > target ) {
436+ assert holdsLock (this );
432437 Path targetPath = target .path ();
433438 assert !targetPath .isEmpty ();
434439 Dereferencer dereferencer = dereferencerFor (target );
@@ -977,6 +982,11 @@ public <TT> Reference<Reference<TT>> thenReference(Class<TT> targetClass, Path p
977982 return this .then (Classes .reference (targetClass ), path );
978983 }
979984
985+ @ Override
986+ public <TT extends VariantCase > Reference <TaggedUnion <TT >> thenTaggedUnion (Class <TT > variantCaseClass , Path path ) throws InvalidTypeException {
987+ return this .then (Classes .taggedUnion (variantCaseClass ), path );
988+ }
989+
980990 @ Override
981991 public BoskDiagnosticContext diagnosticContext () {
982992 return diagnosticContext ;
@@ -1035,6 +1045,11 @@ public final <TT> Reference<Reference<TT>> thenReference(Class<TT> targetClass,
10351045 return rootReference ().thenReference (targetClass , path .then (segments ));
10361046 }
10371047
1048+ @ Override
1049+ public <TT extends VariantCase > Reference <TaggedUnion <TT >> thenTaggedUnion (Class <TT > variantCaseClass , String ... segments ) throws InvalidTypeException {
1050+ return rootReference ().thenTaggedUnion (variantCaseClass , path .then (segments ));
1051+ }
1052+
10381053 @ SuppressWarnings ("unchecked" )
10391054 @ Override
10401055 public final <TT > Reference <TT > enclosingReference (Class <TT > targetClass ) {
@@ -1103,7 +1118,7 @@ public final String toString() {
11031118 * A {@link Reference} with no unbound parameters.
11041119 */
11051120 private sealed class DefiniteReference <T > extends ReferenceImpl <T > {
1106- @ Getter ( lazy = true ) private final Dereferencer dereferencer = compileVettedPath (path );
1121+ private final Dereferencer dereferencer = compileVettedPath (path );
11071122
11081123 public DefiniteReference (Path path , Type targetType ) {
11091124 super (path , targetType );
@@ -1131,6 +1146,10 @@ public void forEachValue(BiConsumer<T, BindingEnvironment> action, BindingEnviro
11311146 action .accept (value , existingEnvironment );
11321147 }
11331148 }
1149+
1150+ public Dereferencer dereferencer () {
1151+ return this .dereferencer ;
1152+ }
11341153 }
11351154
11361155 /**
0 commit comments