Create a sitemap template from the given sitemap.

    The `sitemap` should be a mapping where the key is a string which
    represents a single URI segment, and the value is either another mapping
    or a callable (e.g. function) object.

    Args:
        sitemap: The definition of the routes and their views
        prefix: The base url segment which gets prepended to the given map.

    Examples:
        The sitemap should follow the following format:
        >>> {
        >>>     'string_literal': {
        >>>         '': func1,
        >>>         '{arg}': func2,
        >>>     },
        >>> }

        The key points here are thus:
            - Any string key not matched by the following rule will be matched
              literally
            - Any string key surrounded by curly brackets matches a url segment
              which represents a parameter whose name is the enclosed string
              (i.e. should be a valid keyword argument)
            - *note* a side effect of this is that an empty string key will
              match all routes leading up to the current given mapping

        The above sitemap would compile to the following url mappings:
            - /string_literal/ -> calls `func1()`
            - /string_literal/{arg}/ -> calls `func2(arg=<the matched value>)`

def generate_sitemap(sitemap: typing.Mapping, prefix: list=None):
    """Create a sitemap template from the given sitemap.

    The `sitemap` should be a mapping where the key is a string which
    represents a single URI segment, and the value is either another mapping
    or a callable (e.g. function) object.

    Args:
        sitemap: The definition of the routes and their views
        prefix: The base url segment which gets prepended to the given map.

    Examples:
        The sitemap should follow the following format:
        >>> {
        >>>     'string_literal': {
        >>>         '': func1,
        >>>         '{arg}': func2,
        >>>     },
        >>> }

        The key points here are thus:
            - Any string key not matched by the following rule will be matched
              literally
            - Any string key surrounded by curly brackets matches a url segment
              which represents a parameter whose name is the enclosed string
              (i.e. should be a valid keyword argument)
            - *note* a side effect of this is that an empty string key will
              match all routes leading up to the current given mapping

        The above sitemap would compile to the following url mappings:
            - /string_literal/ -> calls `func1()`
            - /string_literal/{arg}/ -> calls `func2(arg=<the matched value>)`
    """
    # Ensures all generated urls are prefixed with a the prefix string
    if prefix is None:
        prefix = []

    for segment, sub_segment in sitemap.items():
        if isinstance(sub_segment, collections.abc.Mapping):
            yield from generate_sitemap(sub_segment, prefix + [segment])
        elif isinstance(sub_segment, collections.abc.Callable):
            if segment:
                prefix = prefix + [segment]
            yield (prefix, sub_segment)
        else:
            raise ValueError('Invalid datatype for sitemap')