get<T extends Object> method

Option<Resolvable<T>> get<T extends Object>({
  1. Entity groupEntity = const DefaultEntity(),
  2. bool traverse = true,
})

Retrieves a dependency from the container.

Implementation

Option<Resolvable<T>> get<T extends Object>({
  Entity groupEntity = const DefaultEntity(),
  bool traverse = true,
}) {
  assert(T != Object, 'T must be specified and cannot be Object.');
  final g = groupEntity.preferOverDefault(focusGroup);
  final option = getDependency<T>(groupEntity: g, traverse: traverse);
  // Outer pattern: collapse the Option<Result<Dependency<T>>>. Each branch
  // is structural — no .unwrap() on a None or Err sits between us and the
  // dependency.
  return switch (option) {
    None() => const None(),
    Some(value: Err(:final error, :final stackTrace)) => Some(
        Sync<T>.err(Err<T>(error, stackTrace: stackTrace)),
      ),
    Some(value: Ok(value: final dep)) => switch (dep.value) {
        Sync<T>() => Some(dep.value),
        Async<T>(value: final fut) => Some(
            Async<T>(
              () => fut.then((e) {
                // If the async slot resolved to Err, propagate by throwing —
                // the surrounding `Async()` constructor absorbs the throw
                // into an Err Result on its own value.
                final value = switch (e) {
                  Ok(value: final v) => v,
                  Err(:final error, :final stackTrace) =>
                    throw Err<T>(error, stackTrace: stackTrace),
                };
                // Replace the Async slot with a Sync slot holding the
                // resolved value (memoisation). The remove may already
                // be a no-op if a concurrent unregister won the race; the
                // re-register skips its dup-check by design.
                registry.removeDependency<T>(groupEntity: g).end();
                switch (registerDependency<T>(
                  dependency: Dependency<T>(
                    Sync<T>.okValue(value),
                    metadata: dep.metadata,
                  ),
                  checkExisting: false,
                )) {
                  case Ok():
                    break;
                  case Err(:final error):
                    // Should be unreachable with checkExisting: false; if it
                    // still fires we surface the cause rather than silently
                    // returning the resolved value with stale registry state.
                    throw error;
                }
                return value;
              }),
            ),
          ),
      },
  };
}