lua-protobuf-rs 0.3.0

lua protobuf
Documentation
use anyhow::anyhow;
use derive_more::{Deref, From, Into};
use mlua::prelude::LuaUserData;
use mlua::{AnyUserData, ErrorContext, MetaMethod, Table, UserDataMethods};
use protobuf::reflect::MessageDescriptor;

use crate::codec::LuaProtoCodec;
use crate::descriptor::enum_descriptor::LuaEnumDescriptor;
use crate::descriptor::field_descriptor::LuaFieldDescriptor;
use crate::descriptor::file_descriptor::LuaFileDescriptor;
use crate::descriptor::oneof_descriptor::LuaOneofDescriptor;
use crate::descriptor_proto::LuaDescriptorProto;
use crate::descriptor_proto::file_descriptor_proto::LuaFileDescriptorProto;
use crate::message_dyn::LuaMessageDyn;

#[derive(Clone, Eq, PartialEq, Hash, Deref, From, Into)]
pub struct LuaMessageDescriptor(pub MessageDescriptor);

impl LuaUserData for LuaMessageDescriptor {
    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
        methods.add_method(MetaMethod::ToString, |_, this, ()| Ok(this.to_string()));

        methods.add_meta_method(MetaMethod::Eq, |_, this, other: AnyUserData| {
            let other = other.borrow::<LuaMessageDescriptor>()?;
            Ok(*this == *other)
        });

        methods.add_method("proto", |_, this, ()| {
            let proto: LuaDescriptorProto = this.proto().clone().into();
            Ok(proto)
        });

        methods.add_method("name", |_, this, ()| Ok(this.name().to_string()));

        methods.add_method("nested_messages", |_, this, ()| {
            let nested_messages: Vec<LuaMessageDescriptor> =
                this.nested_messages().map(From::from).collect();
            Ok(nested_messages)
        });

        methods.add_method("nested_enums", |_, this, ()| {
            let nested_enums: Vec<LuaEnumDescriptor> =
                this.nested_enums().map(From::from).collect();
            Ok(nested_enums)
        });

        methods.add_method("enclosing_message", |_, this, ()| {
            let enclosing_message: Option<LuaMessageDescriptor> =
                this.enclosing_message().map(From::from);
            Ok(enclosing_message)
        });

        methods.add_method("file_descriptor", |_, this, ()| {
            let file_descriptor: LuaFileDescriptor = From::from(this.file_descriptor().clone());
            Ok(file_descriptor)
        });

        methods.add_method("file_descriptor_proto", |_, this, ()| {
            let proto: LuaFileDescriptorProto = this.file_descriptor_proto().clone().into();
            Ok(proto)
        });

        methods.add_method("is_map_entry", |_, this, ()| Ok(this.is_map_entry()));

        methods.add_method("new_instance", |_, this, ()| {
            Ok::<LuaMessageDyn, _>(this.new_instance().into())
        });

        methods.add_method("default_instance", |_, this, ()| {
            match this.default_instance() {
                None => Ok(None),
                Some(instance) => Ok::<Option<LuaMessageDyn>, _>(Some(instance.clone_box().into())),
            }
        });

        methods.add_method("clone_message", |_, this, ()| {
            match this.enclosing_message() {
                None => Ok(None),
                Some(message) => {
                    Ok::<Option<LuaMessageDescriptor>, _>(Some(message.clone().into()))
                }
            }
        });

        methods.add_method("eq", |_, this, (a, b): (AnyUserData, AnyUserData)| {
            let a = a.borrow::<LuaMessageDyn>()?;
            let b = b.borrow::<LuaMessageDyn>()?;
            Ok(MessageDescriptor::eq(this, &***a, &***b))
        });

        methods.add_method("full_name", |_, this, ()| Ok(this.full_name().to_string()));

        methods.add_method("name_to_package", |_, this, ()| {
            Ok(this.name_to_package().to_string())
        });

        methods.add_method("all_oneofs", |_, this, ()| {
            let all_oneofs: Vec<LuaOneofDescriptor> = this.all_oneofs().map(From::from).collect();
            Ok(all_oneofs)
        });

        methods.add_method("oneofs", |_, this, ()| {
            let oneofs: Vec<LuaOneofDescriptor> = this.oneofs().map(From::from).collect();
            Ok(oneofs)
        });

        methods.add_method("oneof_by_name", |_, this, name: String| {
            let descriptor: Option<LuaOneofDescriptor> =
                this.oneof_by_name(name.as_str()).map(From::from);
            Ok(descriptor)
        });

        methods.add_method("fields", |_, this, ()| {
            let fields: Vec<LuaFieldDescriptor> = this.fields().map(From::from).collect();
            Ok(fields)
        });

        methods.add_method("extensions", |_, this, ()| {
            let extensions: Vec<LuaFieldDescriptor> = this.extensions().map(From::from).collect();
            Ok(extensions)
        });

        methods.add_method("field_by_name", |_, this, name: String| {
            let field_descriptor: Option<LuaFieldDescriptor> =
                this.field_by_name(name.as_str()).map(From::from);
            Ok(field_descriptor)
        });

        methods.add_method("field_by_name_or_json_name", |_, this, name: String| {
            let field_descriptor: Option<LuaFieldDescriptor> = this
                .field_by_name_or_json_name(name.as_str())
                .map(From::from);
            Ok(field_descriptor)
        });

        methods.add_method("field_by_number", |_, this, number: u32| {
            let field_descriptor: Option<LuaFieldDescriptor> =
                this.field_by_number(number).map(From::from);
            Ok(field_descriptor)
        });

        methods.add_method("parse_from_bytes", |lua, this, bytes_table: Table| {
            let len = bytes_table.len()? as usize;
            let mut bytes = Vec::with_capacity(len);
            for byte in bytes_table.sequence_values::<u8>() {
                bytes.push(byte.context("expect u8 in table, found other type")?);
            }
            let message = this
                .parse_from_bytes(bytes.as_slice())
                .map_err(|e| anyhow!(e))?;
            let codec = LuaProtoCodec;
            let message = codec.decode_message(lua, message.as_ref())?;
            Ok(message)
        });
    }
}