# Protobuf customization

## Introduction

The protobuf code generator comes with support for customizing the generated C++ code, for instance to create extra helper methods or define custom types to make it easier to use the generated classes.

Customization is managed by using protobuf options on messages, fields or other protobuf elements. The options are either specified directly in the proto file or by using a cpp.conf file in the module. The config file has several sections and each config key refers to a specific protobuf element (message, field, etc.). Using a config file is recommended when the proto file will be used externally and should not contain implementation details (such as scope services), otherwise the options can be set directly in the proto file as this is easier.

The config value is a semi-colon separated list of option names/values, ie.

    <name1>: <value1>; <name2>: <value2> ...

It can also span multiple lines and the last element may end in a semi-colon:

    option_name = <name1>: <value1>;
                  <name2>: <value2>;

If you want to set a default option for a specific element type (e.g. Message or Field) then create an entry with the element name prefixed with an underscore. e.g.

    _Package   = my_option: my_value
    _Message   = my_option: my_value
    _Field     = my_option: my_value
    _Enum      = my_option: my_value
    _EnumValue = my_option: my_value
    _Service   = my_option: my_value
    _Command   = my_option: my_value
    _Request   = my_option: my_value
    _Event     = my_option: my_value

## Options specific to fields

### cpp_method

Controls which helper methods are generated for a given field, available values are:

GetRef
  Get a reference, default for most fields
SetMessage, SetMessageL
  Message helper methods
SetString, SetUniStringPtr, SetStringPtr
  String helper methods
SetByteBuffer, SetBytePtr
  Bytes helper methods

Helper methods for repeated fields

AppendTo, AppendNew, AppendNewL
  Message helper methods
AppendString, AppendUniStringPtr, AppendStringPtr
  String helper methods
AppendByteBuffer, AppendBytePtr
  Bytes helper methods

If an asterix is placed as the option it will make all methods available.

### cpp_datatype

Determines the storage datatype used in the C++ code, by default it will pick a type suitable for the intended use, e.g. a scope service gets OpString and ByteBuffer.

For byte fields choose from:

- OpData (default when services are not created)
- ByteBuffer (default when services are created)

For string fields choose from:

- UniString (default when services are not created)
- OpString (default when services are created)
- TempBuffer

Other types such as int32, etc. does not support this option yet.

### cpp_exttype

Overrides the external datatype (not storage datatype). This is the type used when passing data to setters or when returned from getters. This can be useful to map integers to existing enums or other compatible types.

This option either directly defines the C++ type to use or specifies the name of a type which is defined in a cpp.conf file. See the section below called 'Custom types' for more details.

## Options specific to messages

### cpp_opmessage

Determines whether it should create OpMessage classes for this message. If unset it uses the options defined in the package. Use either true or false.

### cpp_opmessage_prefix

The prefix to use for the OpMessage classe, the default is "Op". This can also be set in the package.

### cpp_opmessage_suffix

The suffix to use for the OpMessage classes, the default is "Message". This can also be set in the package.

### cpp_defines

Additional defines to place around the generated code This is a comma separated list of defines, whitespace around each entry will be stripped.

For instance:

    cpp_defines=API_XYZ, SELFTEST

Will result in C++ code like this:

    #if defined(API_XYZ) && defined(SELFTEST)

## Options specific to OpMessages

### cpp_opmessage_allocate

Controls how the generated OpMessage is allocated/created. Can contain one of:

new
  Message is created with OP_NEW, Deallocation with OP_DELETE. This is the default.
OpMemoryPool
  The message-class declares operator new and operator delete which can be used with OP_NEW and OP_DELETE. The operators need to be implemented in some source-file by using the macro OP_USE_MEMORY_POOL_IMPL() specifying the memory pool instance and the message class name.

## Options specific to enum fields

### cpp_name

Overrides the generated c++ name for the selected item. Currently only support for enums and enum values.

## Options specific to packages

### cpp_opmessage

Determines whether it should create OpMessage classes for the top-level messages. Default is not to create them. Use either true or false. This can also be set per message.

### cpp_opmessage_set

Determines if the generated OpMessage classes are placed in an outer class or not. The outer class only act as a namespace to ensture unique class names. Use either true or false.

### cpp_opmessage_prefix

The prefix to use for the OpMessage classes, the default is "Op". This can also be set per message.

### cpp_opmessage_suffix

The suffix to use for the OpMessage classes, the default is "Message". This can also be set per message.

### cpp_class

Name of the C++ class to use for the message set wrapper, e.g. OpHardcoreMessages If this is not specified the generator will pick a unique name that avoids any conflicts with other classes. The name uses the following syntax:

     <prefix><base>_MessageSet

Where prefix is taken from cpp_prefix and base is the module name plus the name of the proto file converted to camel-case.

### cpp_prefix

The prefix to use for all generated class names in this package. Defaults to Op.

### cpp_defines

Additional defines to place around the generated code. This is a comma separated list of defines, whitespace around each entry will be stripped. For instance:

    cpp_defines=API_XYZ, SELFTEST

Will result in C++ code like this:

    #if defined(API_XYZ) && defined(SELFTEST)

## Options specific to services

### cpp_file

Base name for the service files, use to determine include files e.g. scope_http_logger will result in an include of modules/scope/src/generated/g_scope_http_logger.h and for the non-generated header file: modules/scope/src/scope_http_logger.h. See also cpp_hfile.

### cpp_hfile

Similar to cpp_file but specifies the full path to the include file of the non-generated header file only. e.g. modules/scope/src/scope_resource_manager.h. Overrides cpp_file

### cpp_class

Name of the C++ class to use for the service, e.g. OpScopeHttpLogger. This option is required.

### cpp_feature

Name of feature that the service requires to be compiled. The name is used in an #ifdef in the generated code This option is required.

### cpp_is_essential

Controls whether the service is required for the entire scope module to work. Normally if a service fails to be initialized it will skip the service (except when out of memory). If this is set to true then it will exit if the service fails to initialize.

### cpp_instance

Whether the service should be instantied or not. If set to false then the service is not part of the active service list. This is mostly useful for generating the code for messages in a .proto file and accessing them from C++ code manually.

### cpp_construct

Define extra parameters for the constructor. The exact value of this option is placed in the call to Construct(). It is possible to define shared member variables using Manager.shared_fields and then pass them with this option. e.g. using "shared_id_list" will result in a call like:

    service->Construct(shared_id_list);

### cpp_defines

Additional defines to place around the generated code This is a comma separated list of defines, whitespace around each entry will be stripped. For instance:

    cpp_defines=API_XYZ, SELFTEST; cpp_feature=FEATURE_FOO

Will result in C++ code like this:

    #if defined(FEATURE_FOO) && defined(API_XYZ) && defined(SELFTEST)

### cpp_generate

Determines if a service should generate files or not. The default value is true which enables file generation. For instance to disable generation do:

    cpp_generate=false;

## Customizing services

Create a block for the service you want to override options by adding the block [<service-name>.options] and then reference the item you want to override as config entries, e.g. MyMessage.field1 would access the global message MyMessage and the field field1 and override options for it.