Skip to content
Gregory Szorc edited this page Sep 6, 2010 · 2 revisions

Lua API

This page documents the API by which protocol buffers are used in Lua.

Protocol Buffer Support

The following table describes the level of support for protocol buffer message features:

Definitions Support Level
Optional Fields Full
Required Fields Full
Repeated Fields Full
Default Values Full
Enumerations Full
Nested Types Full
Groups Won't Implement (deprecated)
Extensions Planned
Nested Extensions TBD
Services Planned
Options Planned

The following table describes support for the scalar field types on messages:

Type Supported? Lua Type
double Yes number
float Yes number
int32 Yes number
int64 Not Robust number
uint32 Yes number
uint64 Not Robust number
sint32 Yes number
sint64 Not Robust number
fixed32 Yes number
fixed64 Not Robust number
sfixed32 Yes number
sfixed64 Not Robust number
bool Yes boolean
string Yes string
bytes Yes string

Message Types

Each protocol buffer message is registered as a Lua type. The type name is

"protobuf." + :package + "." + :message_name

For example, the messages in the following protocol buffer definition:

package acme.example;

message msgA {
    optional string name = 1;
}

message lua {
    repeated uint32 value = 1;
}

correspond to the Lua types:

protobuf.acme.example.msgA
protobuf.acme.example.lua

Constructing Messages

From Lua, you can create protocol buffer messages by calling the new function of the Lua message type:

-- create an empty msgA message from the acme.example package
msg = protobuf.acme.example.msgA.new()

This is equivalent to calling the C++ constructor with no arguments.

If you have a string containing the serialized content of a message, call the parsefromstring function of the Lua message type:

-- parse message from contents of a variable, serialized
msg = protobuf.acme.example.msgA.parsefromstring(serialized)

Common Message Instance Functions

Each Lua message type has a handful of common functions:

-- message in variable 'msg'

-- obtain serialized value of message, as a string
serialized = msg:serialized()

-- clear all fields from message
msg:clear()

Message Fields

Each message field defines a number of accessor and mutator methods.

The name of these functions is the form:

:action + "_" + :field

All field labels (required, optional, repeated) have the clear, get, and set actions:

msg:clear_name()

value = msg:get_name()
msg:set_name("new value")

For repeated fields, get and set add a required argument, which is the offset to get/set. By Lua convention, the first element is offset 1.

value1, value2 = msg:get_name(1), msg:get_name(2)

msg:set_name(1, "new value")

-- this will result in error b/c the offset is invalid
value = msg:get_name(0)

-- you will also get an error if you attempt to retrieve an offset that doesn't exist
-- assume msg:size_name() == 2
-- this will error:
msg:get_name(3)

This function does not return any values.

required and optional fields have the has action:

bool = msg:has_name()

repeated fields have the size action, which returns the number of elements:

size = msg:size_multiple()

Embedded Messages

It is possible to embed one protocol buffer message inside another. This is supported in the Lua interface, but the API is slightly different from scalar values.

First, we mimic the C++ API where the )set_()_ function doesn't exist.

-- this clears a message
msg:set_embedded(nil)

-- this throws an error
msg:set_embedded(msg_instance)

To modify embedded messages, you call the get()_ function and modify the returned object.

embedded = msg:get_embedded()
embedded:set_field(new_value)
-- change reflected in parent message automatically

To add an embedded message to a repeated field:

embedded = msg:add_embedded()
-- do stuff with message

Currently there is a bug dealing with treatment of the mutable pointers Lua is using under the hood. The following will likely crash your process:

embedded = msg:get_embedded()
msg:clear_embedded()

-- crash happens on next line
embedded:get_value()

This will hopefully be fixed in a later version.

Table Access to Fields

Messages can also be treated as tables. Just set the message field name as the table key.

value = msg['name']
msg['name'] = 'new value'

Repeated message fields are themselves tables. However, they are indexed by an integer value, starting from 1, as that is the Lua convention.

value = msg['value'][1]

Table access is not yet available. The syntax is documented here for reference during implementation.

Enumerations

Enumerations are represented as Lua tables. Table keys are the strings which correspond to the enumerated values. Table values are the respective integer values of these keys.

Enumeration type names are assigned from the package, message, and enumeration name.

If the enumeration was defined at file/package scope (outside a message), the Lua type name will be:

:package + "." + :enum

If the enumeration was defined inside a message, the Lua type name will be:

:package + "." + :message + "." + :enum

Let's take the following .proto file as an example:

package acme;

enum Color {
    RED = 0;
    GREEN = 1;
    BLUE = 2;
}

message Car {
    optional Color color = 1;
}

message Sign {
    enum Shape {
        SQUARE = 1;
        ROUND = 2;
    }
    optional Shape shape = 1;
}

Here is how you would interact with the enumerations:

car = protobuf.acme.Car.new()
car.set_color(protobuf.acme.Color['GREEN'])
color = car.get_color()

sign = protobuf.acme.Sign.new()
sign.set_shape(protobuf.acme.Sign.Shape['SQUARE'])

Of course, the "." syntax in Lua is just a shortcut for table access, so if you really wanted:

value = protobuf['acme']['Color']['GREEN']

Clone this wiki locally