private static function getMatchCandidates(
        TrieNode $node,
        array $segments,
        int $segmentIter,
        array $hostSegments,
        array &$routeVars
    ): iterable {
        // Base case.  We iterate to 1 past the past segments there are n + 1 levels of nodes due to the root node.
        if ($segmentIter === \count($segments)) {
            if ($node->hostTrie === null) {
                foreach ($node->routes as $route) {
                    yield new MatchedRouteCandidate($route, $routeVars);
                }
            } else {
                // We have to traverse the host trie now
                $routeVarsCopy = $routeVars;
                yield from self::getMatchCandidates($node->hostTrie, $hostSegments, 0, $hostSegments, $routeVarsCopy);
            }

            return;
        }

        $segment = $segments[$segmentIter];

        // Check for a literal segment match, and recursively check its descendants
        if (($childNode = ($node->literalChildrenByValue[\strtolower($segment)] ?? null)) !== null) {
            $routeVarsCopy = $routeVars;
            yield from self::getMatchCandidates($childNode, $segments, $segmentIter + 1, $hostSegments, $routeVarsCopy);
        }

        // If a variable child is a match, check its descendants
        foreach ($node->variableChildren as $childNode) {
            $routeVarsCopy = $routeVars;

            if ($childNode->isMatch($segment, $routeVarsCopy)) {
                yield from self::getMatchCandidates(
                    $childNode,
                    $segments,
                    $segmentIter + 1,
                    $hostSegments,
                    $routeVarsCopy
                );
            }
        }
    }