// Copyright 2017 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 MOJO_PUBLIC_CPP_SYSTEM_STRING_DATA_PIPE_PRODUCER_H_
#define MOJO_PUBLIC_CPP_SYSTEM_STRING_DATA_PIPE_PRODUCER_H_

#include <string>

#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "mojo/public/cpp/system/system_export.h"

namespace mojo {

// Helper class which takes ownership of a ScopedDataPipeProducerHandle and
// assumes responsibility for feeding it the contents of a given string. This
// takes care of waiting for pipe capacity as needed, and can notify callers
// asynchronously when the operation is complete.
//
// Note that the StringDataPipeProducer must be kept alive until notified of
// completion to ensure that all of the string's data is written to the pipe.
// Premature destruction may result in partial or total truncation of data made
// available to the consumer.
class MOJO_CPP_SYSTEM_EXPORT StringDataPipeProducer {
 public:
  using CompletionCallback = base::OnceCallback<void(MojoResult result)>;

  // Constructs a new StringDataPipeProducer which will write data to
  // |producer|.
  explicit StringDataPipeProducer(ScopedDataPipeProducerHandle producer);
  ~StringDataPipeProducer();

  // Describes what happens to the data when an async writing situation occurs
  // (where the pipe cannot immediately accept all of the data).
  enum class AsyncWritingMode {
    // The |data| given to Write() may be invalidated before completion
    // |callback| is called. The pending |data| is copied and owned by this
    // class until all bytes are written.
    STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION,
    // The |data| given to Write() stays valid until the completion |callback|
    // is called.
    STRING_STAYS_VALID_UNTIL_COMPLETION
  };

  // Attempts to eventually write all of |data|. Invokes |callback|
  // asynchronously when done. Note that |callback| IS allowed to delete this
  // StringDataPipeProducer.
  //
  // If the data cannot be entirely written synchronously, then the |mode|
  // determines how this class holds the pending data.
  //
  // If the write is successful |result| will be |MOJO_RESULT_OK|. Otherwise
  // (e.g. if the producer detects the consumer is closed and the pipe has no
  // remaining capacity) |result| will be |MOJO_RESULT_ABORTED|.
  //
  // Note that if the StringDataPipeProducer is destroyed before |callback| can
  // be invoked, |callback| is *never* invoked, and the write will be
  // permanently interrupted (and the producer handle closed) after making
  // potentially only partial progress.
  //
  // Multiple writes may be performed in sequence (each one after the last
  // completes), but Write() must not be called before the |callback| for the
  // previous call to Write() (if any) has returned.
  void Write(const base::StringPiece& data,
             AsyncWritingMode mode,
             CompletionCallback callback);

 private:
  void InvokeCallback(MojoResult result);
  void OnProducerHandleReady(MojoResult ready_result,
                             const HandleSignalsState& state);

  ScopedDataPipeProducerHandle producer_;
  std::string data_;
  base::StringPiece data_view_;
  CompletionCallback callback_;
  SimpleWatcher watcher_;
  base::WeakPtrFactory<StringDataPipeProducer> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(StringDataPipeProducer);
};

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_SYSTEM_STRING_DATA_PIPE_PRODUCER_H_