Match URL parts to a registered pattern.

        This function is basically where all\
        the CPU-heavy work is done.

        :param parts: URL parts
        :return: Matched route
        :raises kua.routes.RouteError: If there is no match

        :private:

def _match(self, parts: Sequence[str]) -> RouteResolved:
        """
        Match URL parts to a registered pattern.

        This function is basically where all\
        the CPU-heavy work is done.

        :param parts: URL parts
        :return: Matched route
        :raises kua.routes.RouteError: If there is no match

        :private:
        """
        route_match = None  # type: RouteResolved
        route_variable_parts = tuple()  # type: VariablePartsType
        # (route_partial, variable_parts, depth)
        to_visit = [(self._routes, tuple(), 0)]  # type: List[Tuple[dict, tuple, int]]

        # Walk through the graph,
        # keep track of all possible
        # matching branches and do
        # backtracking if needed
        while to_visit:
            curr, curr_variable_parts, depth = to_visit.pop()

            try:
                part = parts[depth]
            except IndexError:
                if self._ROUTE_NODE in curr:
                    route_match = curr[self._ROUTE_NODE]
                    route_variable_parts = curr_variable_parts
                    break
                else:
                    continue

            if self._VAR_ANY_NODE in curr:
                to_visit.append((
                    {self._VAR_ANY_NODE: curr[self._VAR_ANY_NODE]},
                    (curr_variable_parts,
                     (self._VAR_ANY_NODE, part)),
                    depth + 1))
                to_visit.append((
                    curr[self._VAR_ANY_NODE],
                    (curr_variable_parts,
                     (self._VAR_ANY_BREAK, part)),
                    depth + 1))

            if self._VAR_NODE in curr:
                to_visit.append((
                    curr[self._VAR_NODE],
                    (curr_variable_parts,
                     (self._VAR_NODE, part)),
                    depth + 1))

            if part in curr:
                to_visit.append((
                    curr[part],
                    curr_variable_parts,
                    depth + 1))

        if not route_match:
            raise RouteError('No match')

        return RouteResolved(
            params=make_params(
                key_parts=route_match.key_parts,
                variable_parts=route_variable_parts),
            anything=route_match.anything)