"""Asynchronous support for garage.threads.actors."""

__all__ = [
    'StubAdapter',
]

from garage.asyncs import futures


class StubAdapter:
    """Wrap all method calls, adding FutureAdapter on their result.

    While this simple adapter does not work for all corner cases, for
    common cases, it should work fine.
    """

    def __init__(self, stub):
        super().__setattr__('_stub', stub)

    def __getattr__(self, name):
        method = getattr(self._stub, name)
        # Simple foolproof detection of non-message-sending access
        if name.startswith('_'):
            return method
        return lambda *args, **kwargs: \
            futures.FutureAdapter(method(*args, **kwargs))

    def _get_future(self):
        return futures.FutureAdapter(self._stub._get_future())

    def _send_message(self, func, args, kwargs):
        """Enqueue a message into actor's message queue.

        Since this does not block, it may raise Full when the message
        queue is full.
        """
        future = self._stub._send_message(func, args, kwargs, block=False)
        return futures.FutureAdapter(future)

"""Asynchronous support for garage.threads.actors."""

__all__ = [
    'StubAdapter',
]

from garage.asyncs import futures


class StubAdapter:
    """Wrap all method calls, adding FutureAdapter on their result.

    While this simple adapter does not work for all corner cases, for
    common cases, it should work fine.
    """

    def __init__(self, stub):
        super().__setattr__('_stub', stub)

    def __getattr__(self, name):
        method = getattr(self._stub, name)
        # Simple foolproof detection of non-message-sending access
        if name.startswith('_'):
            return method
        return lambda *args, **kwargs: \
            futures.FutureAdapter(method(*args, **kwargs))

    def _get_future(self):
        return futures.FutureAdapter(self._stub._get_future())

    def _send_message(self, func, args, kwargs):
        """Enqueue a message into actor's message queue.

        Since this does not block, it may raise Full when the message
        queue is full.
        """
        future = self._stub._send_message(func, args, kwargs, block=False)
        return futures.FutureAdapter(future)

    async def _kill_and_join(self, graceful=True):
        self._kill(graceful=graceful)
        await self._get_future().result()

Add _kill_and_join to async actor stub
Add _kill_and_join to async actor stub

  """Asynchronous support for garage.threads.actors."""
  
  __all__ = [
      'StubAdapter',
  ]
  
  from garage.asyncs import futures
  
  
  class StubAdapter:
      """Wrap all method calls, adding FutureAdapter on their result.
  
      While this simple adapter does not work for all corner cases, for
      common cases, it should work fine.
      """
  
      def __init__(self, stub):
          super().__setattr__('_stub', stub)
  
      def __getattr__(self, name):
          method = getattr(self._stub, name)
          # Simple foolproof detection of non-message-sending access
          if name.startswith('_'):
              return method
          return lambda *args, **kwargs: \
              futures.FutureAdapter(method(*args, **kwargs))
  
      def _get_future(self):
          return futures.FutureAdapter(self._stub._get_future())
  
      def _send_message(self, func, args, kwargs):
          """Enqueue a message into actor's message queue.
  
          Since this does not block, it may raise Full when the message
          queue is full.
          """
          future = self._stub._send_message(func, args, kwargs, block=False)
          return futures.FutureAdapter(future)
  
+     async def _kill_and_join(self, graceful=True):
+         self._kill(graceful=graceful)
+         await self._get_future().result()
+ 
Add _kill_and_join to async actor stub
## Code Before:
"""Asynchronous support for garage.threads.actors."""

__all__ = [
    'StubAdapter',
]

from garage.asyncs import futures


class StubAdapter:
    """Wrap all method calls, adding FutureAdapter on their result.

    While this simple adapter does not work for all corner cases, for
    common cases, it should work fine.
    """

    def __init__(self, stub):
        super().__setattr__('_stub', stub)

    def __getattr__(self, name):
        method = getattr(self._stub, name)
        # Simple foolproof detection of non-message-sending access
        if name.startswith('_'):
            return method
        return lambda *args, **kwargs: \
            futures.FutureAdapter(method(*args, **kwargs))

    def _get_future(self):
        return futures.FutureAdapter(self._stub._get_future())

    def _send_message(self, func, args, kwargs):
        """Enqueue a message into actor's message queue.

        Since this does not block, it may raise Full when the message
        queue is full.
        """
        future = self._stub._send_message(func, args, kwargs, block=False)
        return futures.FutureAdapter(future)

## Instruction:
Add _kill_and_join to async actor stub
## Code After:
"""Asynchronous support for garage.threads.actors."""

__all__ = [
    'StubAdapter',
]

from garage.asyncs import futures


class StubAdapter:
    """Wrap all method calls, adding FutureAdapter on their result.

    While this simple adapter does not work for all corner cases, for
    common cases, it should work fine.
    """

    def __init__(self, stub):
        super().__setattr__('_stub', stub)

    def __getattr__(self, name):
        method = getattr(self._stub, name)
        # Simple foolproof detection of non-message-sending access
        if name.startswith('_'):
            return method
        return lambda *args, **kwargs: \
            futures.FutureAdapter(method(*args, **kwargs))

    def _get_future(self):
        return futures.FutureAdapter(self._stub._get_future())

    def _send_message(self, func, args, kwargs):
        """Enqueue a message into actor's message queue.

        Since this does not block, it may raise Full when the message
        queue is full.
        """
        future = self._stub._send_message(func, args, kwargs, block=False)
        return futures.FutureAdapter(future)

    async def _kill_and_join(self, graceful=True):
        self._kill(graceful=graceful)
        await self._get_future().result()
