lua调用C/C++函数发送数据
主要操作函数是lua_table_to_protobuf,
static google::protobuf::Message* lua_table_to_protobuf(lua_State* L, int stackIdx, const char* msg_name){
if (!lua_istable(L, stackIdx)){
return NULL;
}
Message* message = proto_man::create_message(msg_name);
if (!message) {
log_error("cant find message %s from compiled poll \n", msg_name);
return NULL;
}
const Reflection* reflection = message->GetReflection();
const Descriptor* descriptor = message->GetDescriptor();
// 遍历table的所有key, 并且与 protobuf结构相比较。如果require的字段没有赋值, 报错! 如果找不到字段,报错!
for (int32_t index = 0; index < descriptor->field_count(); ++index) {
const FieldDescriptor* fd = descriptor->field(index);
const string& name = fd->name();
bool isRequired = fd->is_required();
bool bReapeted = fd->is_repeated();
lua_pushstring(L, name.c_str());
lua_rawget(L, stackIdx);
bool isNil = lua_isnil(L, -1);
if (bReapeted) {
if (isNil) {
lua_pop(L, 1);
continue;
}
else {
bool isTable = lua_istable(L, -1);
if (!isTable) {
log_error("cant find required repeated field %s\n", name.c_str());
proto_man::release_message(message);
return NULL;
}
}
lua_pushnil(L);
for (; lua_next(L, -2) != 0;) {
switch (fd->cpp_type()) {
case FieldDescriptor::CPPTYPE_DOUBLE:
{
double value = luaL_checknumber(L, -1);
reflection->AddDouble(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_FLOAT:
{
float value = luaL_checknumber(L, -1);
reflection->AddFloat(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_INT64:
{
int64_t value = luaL_checknumber(L, -1);
reflection->AddInt64(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_UINT64:
{
uint64_t value = luaL_checknumber(L, -1);
reflection->AddUInt64(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
{
int32_t value = luaL_checknumber(L, -1);
const EnumDescriptor* enumDescriptor = fd->enum_type();
const EnumValueDescriptor* valueDescriptor = enumDescriptor->FindValueByNumber(value);
reflection->AddEnum(message, fd, valueDescriptor);
}
break;
case FieldDescriptor::CPPTYPE_INT32:
{
int32_t value = luaL_checknumber(L, -1);
reflection->AddInt32(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_UINT32:
{
uint32_t value = luaL_checknumber(L, -1);
reflection->AddUInt32(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_STRING:
{
size_t size = 0;
const char* value = luaL_checklstring(L, -1, &size);
reflection->AddString(message, fd, std::string(value, size));
}
break;
case FieldDescriptor::CPPTYPE_BOOL:
{
bool value = lua_toboolean(L, -1);
reflection->AddBool(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
{
Message* value = lua_table_to_protobuf(L, lua_gettop(L), fd->message_type()->name().c_str());
if (!value) {
log_error("convert to message %s failed whith value %s\n", fd->message_type()->name().c_str(), name.c_str());
proto_man::release_message(value);
return NULL;
}
Message* msg = reflection->AddMessage(message, fd);
msg->CopyFrom(*value);
proto_man::release_message(value);
}
break;
default:
break;
}
// remove value, keep the key
lua_pop(L, 1);
}
}
else {
if (isRequired) {
if (isNil) {
log_error("cant find required field %s\n", name.c_str());
proto_man::release_message(message);
return NULL;
}
}
else {
if (isNil) {
lua_pop(L, 1);
continue;
}
}
switch (fd->cpp_type()) {
case FieldDescriptor::CPPTYPE_DOUBLE:
{
double value = luaL_checknumber(L, -1);
reflection->SetDouble(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_FLOAT:
{
float value = luaL_checknumber(L, -1);
reflection->SetFloat(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_INT64:
{
int64_t value = luaL_checknumber(L, -1);
reflection->SetInt64(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_UINT64:
{
uint64_t value = luaL_checknumber(L, -1);
reflection->SetUInt64(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
{
int32_t value = luaL_checknumber(L, -1);
const EnumDescriptor* enumDescriptor = fd->enum_type();
const EnumValueDescriptor* valueDescriptor = enumDescriptor->FindValueByNumber(value);
reflection->SetEnum(message, fd, valueDescriptor);
}
break;
case FieldDescriptor::CPPTYPE_INT32:
{
int32_t value = luaL_checknumber(L, -1);
reflection->SetInt32(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_UINT32:
{
uint32_t value = luaL_checknumber(L, -1);
reflection->SetUInt32(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_STRING:
{
size_t size = 0;
const char* value = luaL_checklstring(L, -1, &size);
reflection->SetString(message, fd, std::string(value, size));
}
break;
case FieldDescriptor::CPPTYPE_BOOL:
{
bool value = lua_toboolean(L, -1);
reflection->SetBool(message, fd, value);
}
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
{
Message* value = lua_table_to_protobuf(L, lua_gettop(L), fd->message_type()->name().c_str());
if (!value) {
log_error("convert to message %s failed whith value %s \n", fd->message_type()->name().c_str(), name.c_str());
proto_man::release_message(message);
return NULL;
}
Message* msg = reflection->MutableMessage(message, fd);
msg->CopyFrom(*value);
proto_man::release_message(value);
}
break;
default:
break;
}
}
// pop value
lua_pop(L, 1);
}
return message;
return NULL;
}
syntax = "proto3";
enum Cmd {
eLoginReq = 0;
eLoginRes = 1;
}
message LoginReq {
string name = 1;
int32 age = 2;
string email = 3;
repeated int32 int_set = 4;
}
message LoginRes {
int32 status = 1;
}
lua_table_to_protobuf(toLua_S, 6, msg_name); //msg_name就是根据ctype返回的命令名称
假如发送数据是
Data = {
Stype = 0,
ctype = 0,
utag = 0,
body = {
Name:’hello’,
Age:20,
Email:’[email protected]’,
int_set:[a = 100, b = 200, c = 300]
}
}
const Reflection* reflection = message->GetReflection();
const Descriptor* descriptor = message->GetDescriptor();
获得Message对象的反射和描述
const FieldDescriptor* fd = descriptor->field(index);
const string& name = fd->name() //得到name = ‘Name’
获取索引6表中的key为Name的value压入栈中
lua_pushstring(L, name.c_str());
lua_rawget(L, stackIdx);
Stack: session,table,stype,ctype,tag, body, hello
fd->cpp_type = CPPTYPE_STRING;
把hello 通过反射reflection->AddString写入到Message中
size_t size = 0;
const char* value = luaL_checklstring(L, -1, &size);
reflection->AddString(message, fd, std::string(value, size));
循环到int_set是repeated的就执行if循环
先压入一个nil,lua_pushnil(L);作为key位 table在-2索引上
lua_next(L,-2); 可以遍历lua表中的数据,到尾部就返回0退出循环,
static void push_proto_message_to_lua(const Message* message){
lua_State* state = lua_wrapper::lua_state();
if (!message) {
// printf("PushProtobuf2LuaTable failed, message is NULL");
return;
}
const Reflection* reflection = message->GetReflection(); //操作字段
// 顶层table
lua_newtable(state);
const Descriptor* descriptor = message->GetDescriptor(); //descriptor获取字段
for (int32_t index = 0; index < descriptor->field_count(); ++index) {
const FieldDescriptor* fd = descriptor->field(index);
const std::string& name = fd->lowercase_name();
// key
lua_pushstring(state, name.c_str());
bool bReapeted = fd->is_repeated();
if (bReapeted) {
// repeated这层的table
lua_newtable(state);
int size = reflection->FieldSize(*message, fd);
for (int i = 0; i < size; ++i) {
char str[32] = { 0 };
switch (fd->cpp_type()) {
case FieldDescriptor::CPPTYPE_DOUBLE:
lua_pushnumber(state, reflection->GetRepeatedDouble(*message, fd, i));
break;
case FieldDescriptor::CPPTYPE_FLOAT:
lua_pushnumber(state, (double)reflection->GetRepeatedFloat(*message, fd, i));
break;
case FieldDescriptor::CPPTYPE_INT64:
sprintf(str, "%lld", (long long)reflection->GetRepeatedInt64(*message, fd, i));
lua_pushstring(state, str);
break;
case FieldDescriptor::CPPTYPE_UINT64:
sprintf(str, "%llu", (unsigned long long)reflection->GetRepeatedUInt64(*message, fd, i));
lua_pushstring(state, str);
break;
case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
lua_pushinteger(state, reflection->GetRepeatedEnum(*message, fd, i)->number());
break;
case FieldDescriptor::CPPTYPE_INT32:
lua_pushinteger(state, reflection->GetRepeatedInt32(*message, fd, i));
break;
case FieldDescriptor::CPPTYPE_UINT32:
lua_pushinteger(state, reflection->GetRepeatedUInt32(*message, fd, i));
break;
case FieldDescriptor::CPPTYPE_STRING:
{
std::string value = reflection->GetRepeatedString(*message, fd, i);
lua_pushlstring(state, value.c_str(), value.size());
}
break;
case FieldDescriptor::CPPTYPE_BOOL:
lua_pushboolean(state, reflection->GetRepeatedBool(*message, fd, i));
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
push_proto_message_to_lua(&(reflection->GetRepeatedMessage(*message, fd, i)));
break;
default:
break;
}
lua_rawseti(state, -2, i + 1); // lua's index start at 1
}
}
else {
char str[32] = { 0 };
switch (fd->cpp_type()) {
case FieldDescriptor::CPPTYPE_DOUBLE:
lua_pushnumber(state, reflection->GetDouble(*message, fd));
break;
case FieldDescriptor::CPPTYPE_FLOAT:
lua_pushnumber(state, (double)reflection->GetFloat(*message, fd));
break;
case FieldDescriptor::CPPTYPE_INT64:
sprintf(str, "%lld", (long long)reflection->GetInt64(*message, fd));
lua_pushstring(state, str);
break;
case FieldDescriptor::CPPTYPE_UINT64:
sprintf(str, "%llu", (unsigned long long)reflection->GetUInt64(*message, fd));
lua_pushstring(state, str);
break;
case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
lua_pushinteger(state, (int)reflection->GetEnum(*message, fd)->number());
break;
case FieldDescriptor::CPPTYPE_INT32:
lua_pushinteger(state, reflection->GetInt32(*message, fd));
break;
case FieldDescriptor::CPPTYPE_UINT32:
lua_pushinteger(state, reflection->GetUInt32(*message, fd));
break;
case FieldDescriptor::CPPTYPE_STRING:
{
std::string value = reflection->GetString(*message, fd);
lua_pushlstring(state, value.c_str(), value.size());
}
break;
case FieldDescriptor::CPPTYPE_BOOL:
lua_pushboolean(state, reflection->GetBool(*message, fd));
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
push_proto_message_to_lua(&(reflection->GetMessage(*message, fd)));
break;
default:
break;
}
}
lua_rawset(state, -3);
}
}