docstr: Add a recv event, returning the corresponding Future
code: def _add_recv_event(self, kind, kwargs=None, future=None):
      """Add a recv event, returning the corresponding Future"""
      f = future or self._Future()
      if (
          kind.startswith("recv")
          and kwargs.get("flags", 0) & _zmq.DONTWAIT
      ):
          # short-circuit non-blocking calls
          recv = getattr(self._shadow_sock, kind)
          try:
              r = recv(**kwargs)
          except Exception as e:
              f.set_exception(e)
          else:
              f.set_result(r)
          return f
  
      timer = _NoTimer
      if hasattr(_zmq, "RCVTIMEO"):
          timeout_ms = self._shadow_sock.rcvtimeo
          if timeout_ms >= 0:
              timer = self._add_timeout(f, timeout_ms * 1e-3)
  
      # we add it to the list of futures before we add the timeout as the
      # timeout will remove the future from recv_futures to avoid leaks
      self._recv_futures.append(
          _FutureEvent(f, kind, kwargs, msg=None, timer=timer)
      )
  
      # Don't let the Future sit in _recv_events after it's done
      f.add_done_callback(
          lambda f: self._remove_finished_future(f, self._recv_futures)
      )
  
      if self._shadow_sock.get(EVENTS) & POLLIN:
          # recv immediately, if we can
          self._handle_recv()
      if self._recv_futures:
          self._add_io_state(POLLIN)
      return f
  
imports: import warnings
  from asyncio import Future
  from collections import deque
  from itertools import chain
  from typing import Any, Awaitable, Callable, Dict, List, NamedTuple, Optional, Tuple, Type, TypeVar, Union, cast, overload
  import zmq
  from zmq import EVENTS, POLLIN, POLLOUT
  from zmq._typing import Literal
label_desc: Use image node_id 20 for calling the _AsyncSocket obj's underlying member method code with example usage: obj._add_recv_event(kind, kwargs, future) and returns: f, f