// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_MESSAGE_LOOP_WATCHABLE_IO_MESSAGE_PUMP_POSIX_H_
#define BASE_MESSAGE_LOOP_WATCHABLE_IO_MESSAGE_PUMP_POSIX_H_

#include "base/location.h"
#include "base/macros.h"

namespace base {

class WatchableIOMessagePumpPosix {
 public:
  // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
  // of a file descriptor.
  class FdWatcher {
   public:
    virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
    virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;

   protected:
    virtual ~FdWatcher() = default;
  };

  class FdWatchControllerInterface {
   public:
    explicit FdWatchControllerInterface(const Location& from_here);
    // Subclasses must call StopWatchingFileDescriptor() in their destructor
    // (this parent class cannot generically do it for them as it must usually
    // be invoked before they destroy their state which happens before the
    // parent destructor is invoked).
    virtual ~FdWatchControllerInterface();

    // NOTE: This method isn't called StopWatching() to avoid confusion with the
    // win32 ObjectWatcher class. While this doesn't really need to be virtual
    // as there's only one impl per platform and users don't use pointers to the
    // base class. Having this interface forces implementers to share similar
    // implementations (a problem in the past).

    // Stop watching the FD, always safe to call.  No-op if there's nothing to
    // do.
    virtual bool StopWatchingFileDescriptor() = 0;

    const Location& created_from_location() const {
      return created_from_location_;
    }

   private:
    const Location created_from_location_;

    DISALLOW_COPY_AND_ASSIGN(FdWatchControllerInterface);
  };

  enum Mode {
    WATCH_READ = 1 << 0,
    WATCH_WRITE = 1 << 1,
    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
  };

  // Every subclass of WatchableIOMessagePumpPosix must provide a
  // WatchFileDescriptor() which has the following signature where
  // |FdWatchController| must be the complete type based on
  // FdWatchControllerInterface.

  // Registers |delegate| with the current thread's message loop so that its
  // methods are invoked when file descriptor |fd| becomes ready for reading or
  // writing (or both) without blocking.  |mode| selects ready for reading, for
  // writing, or both.  See "enum Mode" above.  |controller| manages the
  // lifetime of registrations. ("Registrations" are also ambiguously called
  // "events" in many places, for instance in libevent.)  It is an error to use
  // the same |controller| for different file descriptors; however, the same
  // controller can be reused to add registrations with a different |mode|.  If
  // |controller| is already attached to one or more registrations, the new
  // registration is added onto those.  If an error occurs while calling this
  // method, any registration previously attached to |controller| is removed.
  // Returns true on success.  Must be called on the same thread the MessagePump
  // is running on.
  // bool WatchFileDescriptor(int fd,
  //                          bool persistent,
  //                          int mode,
  //                          FdWatchController* controller,
  //                          FdWatcher* delegate) = 0;
};

}  // namespace base

#endif  // BASE_MESSAGE_LOOP_WATCHABLE_IO_MESSAGE_PUMP_POSIX_H_