Skip to content
Gregory Szorc edited this page Sep 5, 2010 · 1 revision

C API

This section documents how to use the C API of lua-protobuf.

Registering Lua Libraries

In order to use protocol buffer message types from a Lua state, you need to register them. Each produced C++ header file contains functions whose name ends with open(). There exists one open function for each message type and one function for each package. The package open function simply calls all the message functions in that file.

Let's define our example .proto file:

package acme.example;

message Foo {
    optional string name = 1;
}

message Bar {
    optional uint32 value = 1;
}

Taking the .proto file from above having the acme.example package, we would have the following functions:

lua_protobuf_acme_example_open(); -- registers all messages in the 'acme.example' package
lua_protobuf_acme_example_Foo_open(); -- message 'Foo' becomes available
lua_protobuf_acme_example_Bar_open();  -- message 'Bar' becomes available

When you create Lua interpreters, just call the appropriate function(s).

lua_State *L = luaL_newstate();
lua_protobuf_acme_example_open(L);
// all messages from 'acme.example' now available to the interpreter

Pushing Messages to Lua

It is possible to push messages created in C/C++ to the Lua stack. Each protocol buffer message has a couple of functions which can be used for this.

pushcopy()

The pushcopy() function will push a copy of a message instance to the top of the Lua stack. The copy is owned by Lua and garbage collected when it is no longer used. Since it is a copy, changes made in Lua will not be reflected in the calling program and vice-verse. To receive modifications to the changed message, you will need to pull the message out of Lua. How you do this is beyond this documentation.

::acme::example::Foo msg = ::acme::example::Foo();
msg->set_name("my name");

lua_State *L = luaL_newstate();
lua_protobuf_acme_example_open(L);
lua_protobuf_acme_example_Foo_pushcopy(L, msg);

What you do with the mesage once it is on the stack is up to you. You could assign it to a global variable:

// assign the pushed message to the "msg" global variable
lua_setglobal(L, "msg");

Or, you could have pushed a function object and made the protocol buffer message an argument to said function.

Do whatever you want.

pushreference()

The pushreference() function will push a reference of a message instance (i.e. a pointer). This allows changes in Lua to be reflected in the calling application and vice-versa. It is also faster, since we don't need to copy the message.

However, with power comes responsibility. When you push a reference, it is not clear whether the caller or Lua owns the backing memory. To alleviate matters, this function takes optional arguments which can be used to define a function to be called just before Lua garbage collects the object. The return value of this callback tells Lua whether to free the memory. If no function is passed, Lua assumes the caller will free the memory (since the caller has a longer lifetime than the individual Lua interpreter).

int msg_gc_notify(::google::protobuf::Message *msg, void *data)
{
    // do stuff with passed data and determine if you want the message deleted

    int *ref_count = (int *)data;

    if (ref_count > 0) {
        return 0;
    }
    else {
        return 1;
    }
}

// you almost always want to use _new_ otherwise you have greater risk of
// variable falling out of scope and being destroyed
// this would result in Lua reading freed memory, which will cause kittens
// to be killed. think of the kitteh!
::acme::example::Foo *msg = new ::acme::example::Foo();

int *ref_count = new ref_count;
*ref_count = 1;

lua_protobuf_acme_example_msgA_pushreference(L, msg_gc_notify, (void *)ref_count);

msg->set_name("some name"); // reflected in Lua immediately

The above example shows you a very primitive reference counting mechanism. What you do with the callback function is completely up to you.

One common use case is to want to use pushreference() for performance reasons, but to also have Lua always free the message at garbage collection time. The lua_protobuf_gc_always_free function, which is defined by lua-protobuf, always returns 1 and can be used for this purpose.

No locking on the object is performed in the Lua code, so it is the caller's responsibility to deal with things like thread safety.

Clone this wiki locally