// Copyright 2014 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.

// This file contains types/constants and functions specific to data pipes.
//
// Note: This header should be compilable as C.

#ifndef MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_
#define MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_

#include <stdint.h>

#include "mojo/public/c/system/macros.h"
#include "mojo/public/c/system/system_export.h"
#include "mojo/public/c/system/types.h"

// Flags passed to |MojoCreateDataPipe()| via |MojoCreateDataPipeOptions|. See
// values defined below.
typedef uint32_t MojoCreateDataPipeFlags;

// No flags. Default behavior.
#define MOJO_CREATE_DATA_PIPE_FLAG_NONE ((uint32_t)0)

// Options passed to |MojoCreateDataPipe()|.
struct MOJO_ALIGNAS(8) MojoCreateDataPipeOptions {
  // The size of this structure, used for versioning.
  uint32_t struct_size;

  // See |MojoCreateDataPipeFlags|.
  MojoCreateDataPipeFlags flags;

  // The size of an element in bytes. All transactions and buffer sizes must
  // consist of an integral number of elements. Must be non-zero.
  uint32_t element_num_bytes;

  // The capacity of the data pipe in bytes. Must be a multiple of
  // |element_num_bytes|. If successfully created, the pipe will always be able
  // to queue at least this much data. If zero, the pipe buffer will be of a
  // system-dependent capacity of at least one element in size.
  uint32_t capacity_num_bytes;
};
MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) <= 8, "int64_t has weird alignment");
MOJO_STATIC_ASSERT(sizeof(MojoCreateDataPipeOptions) == 16,
                   "MojoCreateDataPipeOptions has wrong size");

// Flags passed to |MojoWriteData()| via |MojoWriteDataOptions|. See values
// defined below.
typedef uint32_t MojoWriteDataFlags;

// No flags. Default behavior.
#define MOJO_WRITE_DATA_FLAG_NONE ((uint32_t)0)

// Requires that all provided data must fit into the pipe's available capacity
// in order for the write to succeed. Otherwise the write fails and no data is
// written into the pipe.
#define MOJO_WRITE_DATA_FLAG_ALL_OR_NONE ((uint32_t)1 << 0)

// Options passed to |MojoWriteData()|.
struct MOJO_ALIGNAS(8) MojoWriteDataOptions {
  // The size of this structure, used for versioning.
  uint32_t struct_size;

  // See |MojoWriteDataFlags|.
  MojoWriteDataFlags flags;
};
MOJO_STATIC_ASSERT(sizeof(MojoWriteDataOptions) == 8,
                   "MojoWriteDataOptions has wrong size");

// Flags passed to |MojoBeginWriteData()| via |MojoBeginWriteDataOptions|. See
// values defined below.
typedef uint32_t MojoBeginWriteDataFlags;

// No flags. Default behavior.
#define MOJO_BEGIN_WRITE_DATA_FLAG_NONE ((uint32_t)0)

// Options passed to |MojoBeginWriteData()|.
struct MOJO_ALIGNAS(8) MojoBeginWriteDataOptions {
  // The size of this structure, used for versioning.
  uint32_t struct_size;

  // See |MojoBeginWriteDataFlags|.
  MojoBeginWriteDataFlags flags;
};
MOJO_STATIC_ASSERT(sizeof(MojoBeginWriteDataOptions) == 8,
                   "MojoBeginWriteDataOptions has wrong size");

// Flags passed to |MojoEndWriteData()| via |MojoEndWriteDataOptions|. See
// values defined below.
typedef uint32_t MojoEndWriteDataFlags;

// No flags. Default behavior.
#define MOJO_END_WRITE_DATA_FLAG_NONE ((uint32_t)0)

// Options passed to |MojoEndWriteData()|.
struct MOJO_ALIGNAS(8) MojoEndWriteDataOptions {
  // The size of this structure, used for versioning.
  uint32_t struct_size;

  // See |MojoEndWriteDataFlags|.
  MojoEndWriteDataFlags flags;
};
MOJO_STATIC_ASSERT(sizeof(MojoEndWriteDataOptions) == 8,
                   "MojoEndWriteDataOptions has wrong size");

// Flags passed to |MojoReadData()| via |MojoReadDataOptions|.
typedef uint32_t MojoReadDataFlags;

// No flags. Default behavior.
#define MOJO_READ_DATA_FLAG_NONE ((uint32_t)0)

// Requires that all request bytes can be read from the data pipe in order for
// the read to succeed. If that many bytes are not available for reading, the
// read will fail and no bytes will be read. Ignored of
// |MOJO_READ_DATA_FLAG_QUERY| is also set.
#define MOJO_READ_DATA_FLAG_ALL_OR_NONE ((uint32_t)1 << 0)

// Discards the data read rather than copying it into the caller's provided
// buffer. May not be combined with |MOJO_READ_DATA_FLAG_PEEK| or
// |MOJO_READ_DATA_FLAG_QUERY|.
#define MOJO_READ_DATA_FLAG_DISCARD ((uint32_t)1 << 1)

// Queries the number of bytes available for reading without actually reading
// the data. May not be combined with |MOJO_READ_DATA_FLAG_DISCARD| or
// |MOJO_READ_DATA_FLAG_PEEK|. |MOJO_READ_DATA_FLAG_ALL_OR_NONE| is ignored if
// this is set.
#define MOJO_READ_DATA_FLAG_QUERY ((uint32_t)1 << 2)

// Reads data from the pipe and copies it to the caller's provided buffer
// without actually removing the data from the pipe. May not be combined with
// |MOJO_READ_DATA_FLAG_DISCARD| or |MOJO_READ_DATA_FLAG_QUERY|.
#define MOJO_READ_DATA_FLAG_PEEK ((uint32_t)1 << 3)

// Options passed to |MojoReadData()|.
struct MOJO_ALIGNAS(8) MojoReadDataOptions {
  // The size of this structure, used for versioning.
  uint32_t struct_size;

  // See |MojoReadDataFlags|.
  MojoReadDataFlags flags;
};
MOJO_STATIC_ASSERT(sizeof(MojoReadDataOptions) == 8,
                   "MojoReadDataOptions has wrong size");

// Flags passed to |MojoBeginReadData()| via |MojoBeginReadDataOptions|. See
// values defined below.
typedef uint32_t MojoBeginReadDataFlags;

// No flags. Default behavior.
#define MOJO_BEGIN_READ_DATA_FLAG_NONE ((uint32_t)0)

// Options passed to |MojoBeginReadData()|.
struct MOJO_ALIGNAS(8) MojoBeginReadDataOptions {
  // The size of this structure, used for versioning.
  uint32_t struct_size;

  // See |MojoBeginReadDataFlags|.
  MojoBeginReadDataFlags flags;
};
MOJO_STATIC_ASSERT(sizeof(MojoBeginReadDataOptions) == 8,
                   "MojoBeginReadDataOptions has wrong size");

// Flags passed to |MojoEndReadData()| via |MojoEndReadDataOptions|. See
// values defined below.
typedef uint32_t MojoEndReadDataFlags;

// No flags. Default behavior.
#define MOJO_END_READ_DATA_FLAG_NONE ((uint32_t)0)

// Options passed to |MojoEndReadData()|.
struct MOJO_ALIGNAS(8) MojoEndReadDataOptions {
  // The size of this structure, used for versioning.
  uint32_t struct_size;

  // See |MojoEndReadDataFlags|.
  MojoEndReadDataFlags flags;
};
MOJO_STATIC_ASSERT(sizeof(MojoEndReadDataOptions) == 8,
                   "MojoEndReadDataOptions has wrong size");

#ifdef __cplusplus
extern "C" {
#endif

// Creates a data pipe, which is a unidirectional communication channel for
// unframed data. Data must be read and written in multiples of discrete
// discrete elements of size given in |options|.
//
// See |MojoCreateDataPipeOptions| for a description of the different options
// available for data pipes.
//
// |options| may be set to null for a data pipe with the default options (which
// will have an element size of one byte and have some system-dependent
// capacity).
//
// On success, |*data_pipe_producer_handle| will be set to the handle for the
// producer and |*data_pipe_consumer_handle| will be set to the handle for the
// consumer. On failure they are not modified.
//
// Returns:
//   |MOJO_RESULT_OK| on success.
//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid, e.g.,
//       |*options| is invalid, specified capacity or element size is zero, or
//       the specified element size exceeds the specified capacity.
//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has
//       been reached (e.g., if the requested capacity was too large, or if the
//       maximum number of handles was exceeded).
//   |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|.
MOJO_SYSTEM_EXPORT MojoResult
MojoCreateDataPipe(const struct MojoCreateDataPipeOptions* options,
                   MojoHandle* data_pipe_producer_handle,
                   MojoHandle* data_pipe_consumer_handle);

// Writes the data pipe producer given by |data_pipe_producer_handle|.
//
// |elements| points to data of size |*num_bytes|; |*num_bytes| must be a
// multiple of the data pipe's element size.
//
// On success |*num_bytes| is set to the amount of data that was actually
// written. On failure it is unmodified.
//
// |options| may be null for default options. See |MojoWriteDataOptions| for
// the effect of various options on the behavior of this function.
//
// Returns:
//   |MOJO_RESULT_OK| on success.
//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
//       |data_pipe_producer_dispatcher| is not a handle to a data pipe
//       producer or |*num_bytes| is not a multiple of the data pipe's element
//       size.)
//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer handle has been
//       closed.
//   |MOJO_RESULT_OUT_OF_RANGE| if |options->flags| has
//       |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set and the required amount of data
//       (specified by |*num_bytes|) could not be written.
//   |MOJO_RESULT_BUSY| if there is a two-phase write ongoing with
//       |data_pipe_producer_handle| (i.e., |MojoBeginWriteData()| has been
//       called, but not yet the matching |MojoEndWriteData()|).
//   |MOJO_RESULT_SHOULD_WAIT| if no data can currently be written (and the
//       consumer is still open) and |options->flags| does *not* have
//       |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set.
MOJO_SYSTEM_EXPORT MojoResult
MojoWriteData(MojoHandle data_pipe_producer_handle,
              const void* elements,
              uint32_t* num_bytes,
              const struct MojoWriteDataOptions* options);

// Begins a two-phase write to the data pipe producer given by
// |data_pipe_producer_handle|. On success |*buffer| will be a pointer to which
// the caller can write up to |*buffer_num_bytes| bytes of data.
//
// During a two-phase write, |data_pipe_producer_handle| is *not* writable.
// If another caller tries to write to it by calling |MojoWriteData()| or
// |MojoBeginWriteData()|, their request will fail with |MOJO_RESULT_BUSY|.
//
// If |MojoBeginWriteData()| returns MOJO_RESULT_OK and once the caller has
// finished writing data to |*buffer|, |MojoEndWriteData()| must be called to
// indicate the amount of data actually written and to complete the two-phase
// write operation. |MojoEndWriteData()| need not be called when
// |MojoBeginWriteData()| fails.
//
// |options| may be null for default options.
//
// Returns:
//   |MOJO_RESULT_OK| on success.
//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
//       |data_pipe_producer_handle| is not a handle to a data pipe producer or
//       |*options| is invalid.
//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer handle has been
//       closed.
//   |MOJO_RESULT_BUSY| if there is already a two-phase write ongoing with
//       |data_pipe_producer_handle| (i.e., |MojoBeginWriteData()| has been
//       called, but not yet the matching |MojoEndWriteData()|).
//   |MOJO_RESULT_SHOULD_WAIT| if no data can currently be written (and the
//       consumer is still open).
MOJO_SYSTEM_EXPORT MojoResult
MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
                   const struct MojoBeginWriteDataOptions* options,
                   void** buffer,
                   uint32_t* buffer_num_bytes);

// Ends a two-phase write that was previously initiated by
// |MojoBeginWriteData()| for the same |data_pipe_producer_handle|.
//
// |num_bytes_written| must indicate the number of bytes actually written into
// the two-phase write buffer. It must be less than or equal to the value of
// |*buffer_num_bytes| output by |MojoBeginWriteData()|, and it must be a
// multiple of the data pipe's element size.
//
// On failure, the two-phase write (if any) is ended (so the handle may become
// writable again if there's space available) but no data written to |*buffer|
// is "put into" the data pipe.
//
// |options| may be null for default options.
//
// Returns:
//   |MOJO_RESULT_OK| on success.
//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
//       |data_pipe_producer_handle| is not a handle to a data pipe producer or
//       |num_bytes_written| is invalid (greater than the maximum value provided
//       by |MojoBeginWriteData()| or not a multiple of the element size).
//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer is not in a
//       two-phase write (e.g., |MojoBeginWriteData()| was not called or
//       |MojoEndWriteData()| has already been called).
MOJO_SYSTEM_EXPORT MojoResult
MojoEndWriteData(MojoHandle data_pipe_producer_handle,
                 uint32_t num_bytes_written,
                 const struct MojoEndWriteDataOptions* options);

// Reads data from the data pipe consumer given by |data_pipe_consumer_handle|.
// May also be used to discard data or query the amount of data available.
//
// If |options->flags| has neither |MOJO_READ_DATA_FLAG_DISCARD| nor
// |MOJO_READ_DATA_FLAG_QUERY| set, this tries to read up to |*num_bytes| (which
// must be a multiple of the data pipe's element size) bytes of data to
// |elements| and set |*num_bytes| to the amount actually read. If flags has
// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set, it will either read exactly
// |*num_bytes| bytes of data or none. Additionally, if flags has
// |MOJO_READ_DATA_FLAG_PEEK| set, the data read will remain in the pipe and be
// available to future reads.
//
// If flags has |MOJO_READ_DATA_FLAG_DISCARD| set, it discards up to
// |*num_bytes| (which again must be a multiple of the element size) bytes of
// data, setting |*num_bytes| to the amount actually discarded. If flags has
// |MOJO_READ_DATA_FLAG_ALL_OR_NONE|, it will either discard exactly
// |*num_bytes| bytes of data or none. In this case, |MOJO_READ_DATA_FLAG_QUERY|
// must not be set, and |elements| is ignored (and should typically be set to
// null).
//
// If flags has |MOJO_READ_DATA_FLAG_QUERY| set, it queries the amount of data
// available, setting |*num_bytes| to the number of bytes available. In this
// case, |MOJO_READ_DATA_FLAG_DISCARD| must not be set, and
// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| is ignored, as are |elements| and the input
// value of |*num_bytes|.
//
// |options| may be null for default options.
//
// Returns:
//   |MOJO_RESULT_OK| on success (see above for a description of the different
//       operations).
//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
//       |data_pipe_consumer_handle| is invalid, the combination of flags in
//       |options->flags| is invalid, or |*options| itself is invalid).
//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer handle has been
//       closed and data (or the required amount of data) was not available to
//       be read or discarded.
//   |MOJO_RESULT_OUT_OF_RANGE| if |options->flags| has
//       |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set and the required amount of data
//       is not available to be read or discarded and the producer is still
//       open.
//   |MOJO_RESULT_BUSY| if there is a two-phase read ongoing with
//       |data_pipe_consumer_handle| (i.e., |MojoBeginReadData()| has been
//       called, but not yet the matching |MojoEndReadData()|).
//   |MOJO_RESULT_SHOULD_WAIT| if there is no data to be read or discarded (and
//       the producer is still open) and |options->flags| does *not* have
//       |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set.
MOJO_SYSTEM_EXPORT MojoResult
MojoReadData(MojoHandle data_pipe_consumer_handle,
             const struct MojoReadDataOptions* options,
             void* elements,
             uint32_t* num_bytes);

// Begins a two-phase read from the data pipe consumer given by
// |data_pipe_consumer_handle|. On success, |*buffer| will be a pointer from
// which the caller can read up to |*buffer_num_bytes| bytes of data.
//
// During a two-phase read, |data_pipe_consumer_handle| is *not* readable.
// If another caller tries to read from it by calling |MojoReadData()| or
// |MojoBeginReadData()|, their request will fail with |MOJO_RESULT_BUSY|.
//
// Once the caller has finished reading data from |*buffer|, |MojoEndReadData()|
// must be called to indicate the number of bytes read and to complete the
// two-phase read operation.
//
// |options| may be null for default options.
//
// Returns:
//   |MOJO_RESULT_OK| on success.
//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
//       |data_pipe_consumer_handle| is not a handle to a data pipe consumer,
//       or |*options| is invalid.)
//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer handle has been
//       closed.
//   |MOJO_RESULT_BUSY| if there is already a two-phase read ongoing with
//       |data_pipe_consumer_handle| (i.e., |MojoBeginReadData()| has been
//       called, but not yet the matching |MojoEndReadData()|).
//   |MOJO_RESULT_SHOULD_WAIT| if no data can currently be read (and the
//       producer is still open).
MOJO_SYSTEM_EXPORT MojoResult
MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
                  const struct MojoBeginReadDataOptions* options,
                  const void** buffer,
                  uint32_t* buffer_num_bytes);

// Ends a two-phase read from the data pipe consumer given by
// |data_pipe_consumer_handle| that was begun by a call to |MojoBeginReadData()|
// on the same handle. |num_bytes_read| should indicate the amount of data
// actually read; it must be less than or equal to the value of
// |*buffer_num_bytes| output by |MojoBeginReadData()| and must be a multiple of
// the element size.
//
// On failure, the two-phase read (if any) is ended (so the handle may become
// readable again) but no data is "removed" from the data pipe.
//
// |options| may be null for default options.
//
// Returns:
//   |MOJO_RESULT_OK| on success.
//   |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g.,
//       |data_pipe_consumer_handle| is not a handle to a data pipe consumer or
//       |num_bytes_written| is greater than the maximum value provided by
//       |MojoBeginReadData()| or not a multiple of the element size).
//   |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer is not in a
//       two-phase read (e.g., |MojoBeginReadData()| was not called or
//       |MojoEndReadData()| has already been called).
MOJO_SYSTEM_EXPORT MojoResult
MojoEndReadData(MojoHandle data_pipe_consumer_handle,
                uint32_t num_bytes_read,
                const struct MojoEndReadDataOptions* options);

#ifdef __cplusplus
}  // extern "C"
#endif

#endif  // MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_