prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  empty window intersection
  I've been playing around with the cool windowing functions @brendan-ward put in a while back.  I'm wondering if this is the desired behavior when two windows intersect at a point or along a row/column.  Because of the ways windows work in rasterio, the upper row/column bound is open, so `windows_intersect` is returning `True` but returning an empty array, e.g.
  
  ```
  >>> with rasterio.open('tests/data/RGB.byte.tif') as src:
  ...     w1 = ((0, 2), (0, 2))
  ...     w2 = ((2, 4), (2, 4))
  ...    if windows_intersect((w1, w2)): #returns True
  ...        print(src.read(1, window=window_intersection((w1, w2))))
  []
  ```
  
  True, the windows do intersect at a point, but I assume the way people will use `window_intersection` is to expect a window that they can use in further processing. 
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `rasterio/windows.py`
  Content:
  ```
  1 """Windows and related functions."""
  2 
  3 
  4 def get_data_window(arr, nodata=None):
  5     """Return a window for the non-nodata pixels within the input array.
  6 
  7     Parameters
  8     ----------
  9     arr: numpy ndarray, <= 3 dimensions
  10     nodata: number
  11         If None, will either return a full window if arr is not a masked
  12         array, or will use the mask to determine non-nodata pixels.
  13         If provided, it must be a number within the valid range of the dtype
  14         of the input array.
  15 
  16     Returns
  17     -------
  18     ((row_start, row_stop), (col_start, col_stop))
  19 
  20     """
  21     from rasterio._io import get_data_window
  22     return get_data_window(arr, nodata)
  23 
  24 
  25 def union(windows):
  26     """Union windows and return the outermost extent they cover.
  27 
  28     Parameters
  29     ----------
  30     windows: list-like of window objects
  31         ((row_start, row_stop), (col_start, col_stop))
  32 
  33     Returns
  34     -------
  35     ((row_start, row_stop), (col_start, col_stop))
  36     """
  37     from rasterio._io import window_union
  38     return window_union(windows)
  39 
  40 
  41 def intersection(windows):
  42     """Intersect windows and return the innermost extent they cover.
  43 
  44     Will raise ValueError if windows do not intersect.
  45 
  46     Parameters
  47     ----------
  48     windows: list-like of window objects
  49         ((row_start, row_stop), (col_start, col_stop))
  50 
  51     Returns
  52     -------
  53     ((row_start, row_stop), (col_start, col_stop))
  54     """
  55     from rasterio._io import window_intersection
  56     return window_intersection(windows)
  57 
  58 
  59 def intersect(windows):
  60     """Test if windows intersect.
  61 
  62     Parameters
  63     ----------
  64     windows: list-like of window objects
  65         ((row_start, row_stop), (col_start, col_stop))
  66 
  67     Returns
  68     -------
  69     boolean:
  70         True if all windows intersect.
  71     """
  72     from rasterio._io import windows_intersect
  73     return windows_intersect(windows)
  74
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/rasterio/windows.py b/rasterio/windows.py
  --- a/rasterio/windows.py
  +++ b/rasterio/windows.py
  @@ -1,5 +1,21 @@
   """Windows and related functions."""
   
  +import functools
  +import collections
  +
  +
  +def iter_args(function):
  +    """Decorator to allow function to take either *args or
  +    a single iterable which gets expanded to *args.
  +    """
  +    @functools.wraps(function)
  +    def wrapper(*args, **kwargs):
  +        if len(args) == 1 and isinstance(args[0], collections.Iterable):
  +            return function(*args[0])
  +        else:
  +            return function(*args)
  +    return wrapper
  +
   
   def get_data_window(arr, nodata=None):
       """Return a window for the non-nodata pixels within the input array.
  @@ -22,7 +38,8 @@
       return get_data_window(arr, nodata)
   
   
  -def union(windows):
  +@iter_args
  +def union(*windows):
       """Union windows and return the outermost extent they cover.
   
       Parameters
  @@ -38,7 +55,8 @@
       return window_union(windows)
   
   
  -def intersection(windows):
  +@iter_args
  +def intersection(*windows):
       """Intersect windows and return the innermost extent they cover.
   
       Will raise ValueError if windows do not intersect.
  @@ -56,7 +74,8 @@
       return window_intersection(windows)
   
   
  -def intersect(windows):
  +@iter_args
  +def intersect(*windows):
       """Test if windows intersect.
   
       Parameters
  
verification_info: {"golden_diff": "diff --git a/rasterio/windows.py b/rasterio/windows.py\n--- a/rasterio/windows.py\n+++ b/rasterio/windows.py\n@@ -1,5 +1,21 @@\n \"\"\"Windows and related functions.\"\"\"\n \n+import functools\n+import collections\n+\n+\n+def iter_args(function):\n+    \"\"\"Decorator to allow function to take either *args or\n+    a single iterable which gets expanded to *args.\n+    \"\"\"\n+    @functools.wraps(function)\n+    def wrapper(*args, **kwargs):\n+        if len(args) == 1 and isinstance(args[0], collections.Iterable):\n+            return function(*args[0])\n+        else:\n+            return function(*args)\n+    return wrapper\n+\n \n def get_data_window(arr, nodata=None):\n     \"\"\"Return a window for the non-nodata pixels within the input array.\n@@ -22,7 +38,8 @@\n     return get_data_window(arr, nodata)\n \n \n-def union(windows):\n+@iter_args\n+def union(*windows):\n     \"\"\"Union windows and return the outermost extent they cover.\n \n     Parameters\n@@ -38,7 +55,8 @@\n     return window_union(windows)\n \n \n-def intersection(windows):\n+@iter_args\n+def intersection(*windows):\n     \"\"\"Intersect windows and return the innermost extent they cover.\n \n     Will raise ValueError if windows do not intersect.\n@@ -56,7 +74,8 @@\n     return window_intersection(windows)\n \n \n-def intersect(windows):\n+@iter_args\n+def intersect(*windows):\n     \"\"\"Test if windows intersect.\n \n     Parameters\n", "issue": "empty window intersection\nI've been playing around with the cool windowing functions @brendan-ward put in a while back.  I'm wondering if this is the desired behavior when two windows intersect at a point or along a row/column.  Because of the ways windows work in rasterio, the upper row/column bound is open, so `windows_intersect` is returning `True` but returning an empty array, e.g.\n\n```\n>>> with rasterio.open('tests/data/RGB.byte.tif') as src:\n...     w1 = ((0, 2), (0, 2))\n...     w2 = ((2, 4), (2, 4))\n...    if windows_intersect((w1, w2)): #returns True\n...        print(src.read(1, window=window_intersection((w1, w2))))\n[]\n```\n\nTrue, the windows do intersect at a point, but I assume the way people will use `window_intersection` is to expect a window that they can use in further processing. \n\n", "before_files": [{"content": "\"\"\"Windows and related functions.\"\"\"\n\n\ndef get_data_window(arr, nodata=None):\n    \"\"\"Return a window for the non-nodata pixels within the input array.\n\n    Parameters\n    ----------\n    arr: numpy ndarray, <= 3 dimensions\n    nodata: number\n        If None, will either return a full window if arr is not a masked\n        array, or will use the mask to determine non-nodata pixels.\n        If provided, it must be a number within the valid range of the dtype\n        of the input array.\n\n    Returns\n    -------\n    ((row_start, row_stop), (col_start, col_stop))\n\n    \"\"\"\n    from rasterio._io import get_data_window\n    return get_data_window(arr, nodata)\n\n\ndef union(windows):\n    \"\"\"Union windows and return the outermost extent they cover.\n\n    Parameters\n    ----------\n    windows: list-like of window objects\n        ((row_start, row_stop), (col_start, col_stop))\n\n    Returns\n    -------\n    ((row_start, row_stop), (col_start, col_stop))\n    \"\"\"\n    from rasterio._io import window_union\n    return window_union(windows)\n\n\ndef intersection(windows):\n    \"\"\"Intersect windows and return the innermost extent they cover.\n\n    Will raise ValueError if windows do not intersect.\n\n    Parameters\n    ----------\n    windows: list-like of window objects\n        ((row_start, row_stop), (col_start, col_stop))\n\n    Returns\n    -------\n    ((row_start, row_stop), (col_start, col_stop))\n    \"\"\"\n    from rasterio._io import window_intersection\n    return window_intersection(windows)\n\n\ndef intersect(windows):\n    \"\"\"Test if windows intersect.\n\n    Parameters\n    ----------\n    windows: list-like of window objects\n        ((row_start, row_stop), (col_start, col_stop))\n\n    Returns\n    -------\n    boolean:\n        True if all windows intersect.\n    \"\"\"\n    from rasterio._io import windows_intersect\n    return windows_intersect(windows)\n", "path": "rasterio/windows.py"}], "after_files": [{"content": "\"\"\"Windows and related functions.\"\"\"\n\nimport functools\nimport collections\n\n\ndef iter_args(function):\n    \"\"\"Decorator to allow function to take either *args or\n    a single iterable which gets expanded to *args.\n    \"\"\"\n    @functools.wraps(function)\n    def wrapper(*args, **kwargs):\n        if len(args) == 1 and isinstance(args[0], collections.Iterable):\n            return function(*args[0])\n        else:\n            return function(*args)\n    return wrapper\n\n\ndef get_data_window(arr, nodata=None):\n    \"\"\"Return a window for the non-nodata pixels within the input array.\n\n    Parameters\n    ----------\n    arr: numpy ndarray, <= 3 dimensions\n    nodata: number\n        If None, will either return a full window if arr is not a masked\n        array, or will use the mask to determine non-nodata pixels.\n        If provided, it must be a number within the valid range of the dtype\n        of the input array.\n\n    Returns\n    -------\n    ((row_start, row_stop), (col_start, col_stop))\n\n    \"\"\"\n    from rasterio._io import get_data_window\n    return get_data_window(arr, nodata)\n\n\n@iter_args\ndef union(*windows):\n    \"\"\"Union windows and return the outermost extent they cover.\n\n    Parameters\n    ----------\n    windows: list-like of window objects\n        ((row_start, row_stop), (col_start, col_stop))\n\n    Returns\n    -------\n    ((row_start, row_stop), (col_start, col_stop))\n    \"\"\"\n    from rasterio._io import window_union\n    return window_union(windows)\n\n\n@iter_args\ndef intersection(*windows):\n    \"\"\"Intersect windows and return the innermost extent they cover.\n\n    Will raise ValueError if windows do not intersect.\n\n    Parameters\n    ----------\n    windows: list-like of window objects\n        ((row_start, row_stop), (col_start, col_stop))\n\n    Returns\n    -------\n    ((row_start, row_stop), (col_start, col_stop))\n    \"\"\"\n    from rasterio._io import window_intersection\n    return window_intersection(windows)\n\n\n@iter_args\ndef intersect(*windows):\n    \"\"\"Test if windows intersect.\n\n    Parameters\n    ----------\n    windows: list-like of window objects\n        ((row_start, row_stop), (col_start, col_stop))\n\n    Returns\n    -------\n    boolean:\n        True if all windows intersect.\n    \"\"\"\n    from rasterio._io import windows_intersect\n    return windows_intersect(windows)\n", "path": "rasterio/windows.py"}]}