def nearest_edges(
    G: nx.MultiDiGraph,
    X: float | Iterable[float],
    Y: float | Iterable[float],
    *,
    return_dist: bool = False,
) -> (
    tuple[int, int, int]
    | npt.NDArray[np.object_]
    | tuple[tuple[int, int, int], float]
    | tuple[npt.NDArray[np.object_], npt.NDArray[np.float64]]
):
    """
    Find the nearest edge to a point or to each of several points.

    If `X` and `Y` are single coordinate values, this function will return the
    nearest edge to that point. If `X` and `Y` are iterables of coordinate
    values, it will return the nearest edge to each point.

    This function is vectorized: if you have many points to search for, pass
    them in one call as numpy arrays (avoid using loops) to maximize runtime
    speed. It uses an R-tree spatial index and minimizes the Euclidean
    distance from each point to the possible matches. For accurate results,
    use a projected graph and projected points.

    Parameters
    ----------
    G
        Graph in which to find nearest edges.
    X
        The points' x (longitude) coordinates, in same CRS/units as graph and
        containing no nulls.
    Y
        The points' y (latitude) coordinates, in same CRS/units as graph and
        containing no nulls.
    return_dist
        If True, optionally also return the distance(s) between point(s) and
        nearest edge(s), in same units as graph and points.

    Returns
    -------
    ne or (ne, dist)
        Nearest edge ID(s) as `(u, v, k)` tuples, or optionally a tuple of
        ID(s) and distance(s) between each point and its nearest edge.
    """
    # make coordinates arrays whether user passed iterable values or not
    if not (isinstance(X, Iterable) and isinstance(Y, Iterable)):
        is_scalar = True
        X_arr = np.array([X])
        Y_arr = np.array([Y])
    else:
        is_scalar = False
        X_arr = np.array(X)
        Y_arr = np.array(Y)

    if np.isnan(X_arr).any() or np.isnan(Y_arr).any():  # pragma: no cover
        msg = "`X` and `Y` cannot contain nulls."
        raise ValueError(msg)
    geoms = convert.graph_to_gdfs(G, nodes=False)["geometry"]
    ne_array: npt.NDArray[np.object_]  # array of tuple[int, int, int]
    dist_array: npt.NDArray[np.float64]

    # build an r-tree spatial index by position for subsequent iloc
    rtree = STRtree(geoms)

    # use the r-tree to find each point's nearest neighbor and distance
    points = [Point(xy) for xy in zip(X_arr, Y_arr)]
    pos, dist_array = rtree.query_nearest(points, all_matches=False, return_distance=True)

    # if user passed X/Y lists, the 2nd subarray contains geom indices
    if len(pos.shape) > 1:
        pos = pos[1]
    ne_array = geoms.iloc[pos].index.to_numpy()

    # convert results to correct types for return
    if is_scalar:
        ne: tuple[int, int, int] = ne_array[0]
        dist = float(dist_array[0])
        if return_dist:
            return ne, dist
        # otherwise
        return ne

    # otherwise
    if return_dist:
        return ne_array, dist_array
    # otherwise
    return ne_array

    Find the nearest edge to a point or to each of several points.

    If `X` and `Y` are single coordinate values, this function will return the
    nearest edge to that point. If `X` and `Y` are iterables of coordinate
    values, it will return the nearest edge to each point.

    This function is vectorized: if you have many points to search for, pass
    them in one call as numpy arrays (avoid using loops) to maximize runtime
    speed. It uses an R-tree spatial index and minimizes the Euclidean
    distance from each point to the possible matches. For accurate results,
    use a projected graph and projected points.

    Parameters
    ----------
    G
        Graph in which to find nearest edges.
    X
        The points' x (longitude) coordinates, in same CRS/units as graph and
        containing no nulls.
    Y
        The points' y (latitude) coordinates, in same CRS/units as graph and
        containing no nulls.
    return_dist
        If True, optionally also return the distance(s) between point(s) and
        nearest edge(s), in same units as graph and points.

    Returns
    -------
    ne or (ne, dist)
        Nearest edge ID(s) as `(u, v, k)` tuples, or optionally a tuple of
        ID(s) and distance(s) between each point and its nearest edge.
    
osmnx/distance.py