.. _readme-protoGenCodeGuide:

================================================
Protocol Buffers Support - Generated Chapel Code
================================================

This page describes exactly what Chapel code the protocol buffer compiler
generates for protocol definitions using ``proto3`` syntax. Please see
:ref:`readme-protobuf` for information about how to use the protocol
buffer support. Additionally, this document assumes familiarity with the
`proto3 language guide`_.

.. note::

  The aim of this documentation is to provide a better understanding of the
  generated code. The user is not expected to modify the generated file.

Compiler Invocation
-------------------
The protocol buffer compiler produces Chapel output when invoked with the ``--chpl_out``
command-line flag. The parameter to the ``--chpl_out`` option is the directory where
you want the compiler to write your Chapel output. The compiler creates a single
source file for each ``.proto`` file input, having a ``.chpl`` extension.

Only ``proto3`` messages are supported by the Chapel code generator. Ensure
that each ``.proto`` file begins with a declaration of:

.. code-block:: proto

  syntax = "proto3";

Output Module Name
------------------
The name of the output file/module will be same as the ``package`` name. If the
``package`` name is not specified, the module takes the name of the proto
file with all non-alphanumeric characters replaced by an ``underscore``.

For example a file called ``address.proto`` without the package specifier will
result in an output file called ``address.chpl`` with the generated code wrapped
in a module of the same name. (Full implementation is not shown here.)

``address.proto``

.. code-block:: proto

  syntax = "proto3";

  message messageName {
  ...
  }

``address.chpl``

.. code-block:: chpl

  module address {
    record messageName {
    ...
    }
  }

The same proto file with a package declaration ``package myPackage;`` will
result in a file called ``myPackage.chpl``.

``address.proto``

.. code-block:: proto

  syntax = "proto3";

  package myPackage;

  message messageName {
  ...
  }

``myPackage.chpl``

.. code-block:: chpl

  module myPackage {
    record messageName {
    ...
    }
  }

Messages
--------
Given a simple message declaration:

.. code-block:: proto
  
  message Foo {
    int32 num = 1;
  }
  
The protocol buffer compiler generates a record called ``Foo``, which has message
field initializers and serialization/parsing methods for wire-type encoding.
(Full implementation is not shown here.)

 .. code-block:: chpl
  
  record Foo {

    /*
      Returns the package name of the proto file. If not declared the method returns
      an empty string.
    */
    proc packageName param { return "packageName"; }

    /*
      Returns the name of the proto message the record is derived from.
    */
    proc messageName param { return "Foo"; }

    /*
      Record fields will be generated corresponding to each proto message field.
    */
    var num: int(32);
    
    /*
      Used to store encoded byte stream of unknown fields encountered while parsing.

      As per proto3 documentation, unknown fields should be preserved and appended
      to the generated message byte stream.
    */
    var unknownFieldStream: bytes = "";
    
    /*
      User exposed method for serializing data to protobuf wire format.

      This is a wrapper method to the actual method.
    */
    proc serialize(ch) throws { ... }
    
    /*
      Contains the actual implementation for serializing data.

      Calls the `Append` functions of the user support library. It appends the
      `unknownFieldStream` at the end of the message.

      This should end up as a private method when supported, so a user should not
      call it directly.
    */
    proc _serialize(binCh) throws { ... }
    
    /*
      User exposed method for parsing data from protobuf wire format.

      This is a wrapper method to the actual method.
    */
    proc deserialize(ch) throws { ... }
    
    /*
      Contains the actual implementation for parsing data.

      Calls the `Consume` functions of the user support library. Appends unknown
      fields encountered to the `unknownFieldStream` variable.

      This should end up as a private method when supported, so a user should not
      call it directly.
    */
    proc _deserialize(binCh) throws { ... }
  
  }

Any Message Type
^^^^^^^^^^^^^^^^
For Any messages, you can call ``pack`` to pack a specified message into the
current Any message, or ``unpack`` to unpack the current Any message to a specified
message. Corresponding to an any message type field the plugin will generate a record
field of ``Any`` type.

.. code-block:: chpl
  
  // Field "a"
  var a: Any;

Fields
------
The protocol buffer compiler generates a Chapel record field for each field defined
within a message. Methods equivalent to `get` and `set` in other languages are
implicitly generated by the Chapel compiler, so do not need to be generated by
the protocol buffer compiler.

Scalar Value Types
^^^^^^^^^^^^^^^^^^
A scalar message field can have one of the following types, the table shows the
type specified in the ``.proto`` file, and the corresponding generated Chapel type:

..
  This table is intended to match the order given by the proto3 language documentation.

.. list-table::
   :widths: 50 50
   :header-rows: 1

   * - .proto Type
     - Chapel Type
   * - double
     - real(64)
   * - float
     - real(32)
   * - int32
     - int(32)
   * - int64
     - int(64)
   * - uint32
     - uint(32)
   * - uint64
     - uint(64)
   * - sint32
     - int(32)
   * - sint64
     - int(64)
   * - fixed32
     - uint(32)
   * - fixed64
     - uint(64)
   * - sfixed32
     - int(32)
   * - sfixed64
     - int(64)
   * - bool
     - bool
   * - string
     - string
   * - bytes
     - bytes

Singular Fields
^^^^^^^^^^^^^^^
Every `singular`_ message field generates a record field variable of an appropriate Chapel type.
Fetching a value from a field which hasn't been explicitly set will return the 
default chapel value for that type. For example, a boolean field ``a`` will generate a
variable of ``bool`` type, with default value of ``false``:

.. code-block:: chpl
  
  // Field "a"
  var a: bool;
  
Repeated Fields
^^^^^^^^^^^^^^^
Every `repeated`_ message field generates a list type. Fetching a value from a field which
hasn't been explicitly set will return an empty list. For example, a repeated
string field ``a`` will generate a list of type ``string``:

.. code-block:: chpl
  
  // Field "a"
  var a: list(string);

Map Fields
^^^^^^^^^^
Given this message definition:

.. code-block:: proto

  message Foo {
    map<int32, bool> mapfield = 1;
  }

The plugin will generate a Chapel ``map(int(32), bool)`` type field:

.. code-block:: chpl

  // Field "mapfield"
  var mapfield: map(int(32), bool);

Enumerations
------------
Given an enumeration definition like:

.. code-block:: proto
  
  enum Color {
    RED = 0;
    GREEN = 5;
    BLUE = 1234;
  }
  
The protocol buffer compiler will generate a Chapel enum type called ``Color`` with the
same set of values.

The ``Color`` proto enum above would therefore become the following Chapel code:

.. code-block:: chpl
  
  enum Color {
    RED = 0,
    GREEN = 5,
    BLUE = 1234,
  }

Oneof
-----
Given a message with a oneof:

.. code-block:: proto

  message Foo {
    oneof test_oneof {
       string name = 1;
       int32 serial_number = 2;
    }
  }

The Chapel record corresponding to ``Foo`` will have ``name_`` and ``serial_number_``
fields along with explicit ``get/set`` type methods:

.. code-block:: chpl

  // Field "name"
  var name_: string;
  proc name {
    ...
  }
  proc ref name ref {
    ...
  }

  // Field "serial_number"
  var serial_number_: int(32);
  proc serial_number {
    ...
  }
  proc ref serial_number ref {
    ...
  }

The explicit methods are declared to allow the user to set at most one of the
fields in a oneof at a time. For example:

.. code-block:: chpl

  messageObj.name = "chapel";
  messageObj.serial_number = 23;

Setting the value of ``serial_number`` after ``name`` will set ``name`` to its
default value("" in case of string).

Nested Types
------------
A message can be declared inside another message. For example:

.. code-block:: proto

  message Foo {
    message Bar {
      ...
    }
  }

In this case, or if a message contains a nested enum declaration, the compiler will generate
module level record/enum per nested type. This generated record or enum will have a name prefixed
by the parent message name:

.. code-block:: chpl
  
  record Foo {
   ...
  }

  // Nested Types
  record Foo_Bar {
    ...
  }

.. note::

  Nested records or declaration of enums in records are currently not supported in
  Chapel. Once we have support for these, we can declare nested types in the parent
  record and thus avoid the name prefix.

.. _proto3 language guide: https://developers.google.com/protocol-buffers/docs/proto3
.. _singular: https://developers.google.com/protocol-buffers/docs/proto3#specifying_field_rules
.. _repeated: `singular`_
