- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
实现目标:能将Rust对象快速的映射到lua中使用,尽可能的简化使用.
以struct HcTestMacro为例:
local val = HcTestMacro.new()
可构建HcTestMacro.del(val)
可析建,仅限light use**rdata
hc
,我们需要能快速的进行字段的取值赋值val.hc
或者val:get_hc()
均可进行取值val.hc = "hclua"
或者val:set_hc("hclua")
均可进行取值call1
,那我们就可以通过注册到lua虚拟机,由于lua虚拟机可能不会是全局唯一的,所以不好通过宏直接注册// 直接注册函数注册
HcTestMacro::object_def(&mut lua, "ok", hclua::function1(HcTestMacro::ok));
// 闭包注册单参数
HcTestMacro::object_def(&mut lua, "call1", hclua::function1(|obj: &HcTestMacro| -> u32 {
obj.field
}));
// 闭包注册双参数
HcTestMacro::object_def(&mut lua, "call2", hclua::function2(|obj: &mut HcTestMacro, val: u32| -> u32 {
obj.field + val
}));
HcTestMacro::object_static_def(&mut lua, "sta_run", hclua::function0(|| -> String {
"test".to_string()
}));
use hclua_macro::ObjectMacro;
#[derive(ObjectMacro, Default)]
#[hclua_cfg(name = HcTest)]
#[hclua_cfg(light)]
struct HcTestMacro {
#[hclua_field]
field: u32,
#[hclua_field]
hc: String,
}
impl HcTestMacro {
fn ok(&self) {
println!("ok!!!!");
}
}
fn main() {
let mut lua = hclua::Lua::new();
let mut test = HcTestMacro::default();
HcTestMacro::register(&mut lua);
// 直接注册函数注册
HcTestMacro::object_def(&mut lua, "ok", hclua::function1(HcTestMacro::ok));
// 闭包注册单参数
HcTestMacro::object_def(&mut lua, "call1", hclua::function1(|obj: &HcTestMacro| -> u32 {
obj.field
}));
// 闭包注册双参数
HcTestMacro::object_def(&mut lua, "call2", hclua::function2(|obj: &mut HcTestMacro, val: u32| -> u32 {
obj.field + val
}));
HcTestMacro::object_static_def(&mut lua, "sta_run", hclua::function0(|| -> String {
"test".to_string()
}));
lua.openlibs();
let val = "
print(aaa);
print(\"cccxxxxxxxxxxxxxxx\");
print(type(HcTest));
local v = HcTest.new();
print(\"call ok\", v:ok())
print(\"call1\", v:call1())
print(\"call2\", v:call2(2))
print(\"kkkk\", v.hc)
v.hc = \"dddsss\";
print(\"kkkk ok get_hc\", v:get_hc())
v.hc = \"aa\";
print(\"new kkkkk\", v.hc)
v:set_hc(\"dddddd\");
print(\"new kkkkk1\", v.hc)
print(\"attemp\", v.hc1)
print(\"vvvvv\", v:call1())
print(\"static run\", HcTest.sta_run())
HcTest.del(v);
";
let _: Option<()> = lua.exec_string(val);
}
hclua Rust中的lua绑定.
通过derive宏进行函数注册:#[derive(ObjectMacro, Default)] 通过attrib声明命名:#[hclua_cfg(name = HcTest)],配置该类在lua 中的名字为HcTest,本质上在lua里注册全局的table,通过在该table下注册 HcTest { new = function(), del = function() } 通过attrib注册生命:#[hclua_cfg(light)],表示该类型是light userdata即生命周期由Rust控制,默认为userdata即生命周期由Lua控制,通过__gc进行回收。 通过attrib声明字段:#[hclua_field]放到字段前面,即可以注册字段使用,在derive生成的时候判断是否有该字段,进行字段的映射.
主要源码在 hclua-macro 实现, 完整代码可进行参考.
#[proc_macro_derive(ObjectMacro, attributes(hclua_field, hclua_cfg))]
pub fn object_macro_derive(input: TokenStream) -> TokenStream {
let ItemStruct {
ident,
fields,
attrs,
..
} = parse_macro_input!(input);
let config = config::Config::parse_from_attributes(ident.to_string(), &attrs[..]).unwrap();
let functions: Vec<_> = fields
.iter()
.map(|field| {
let field_ident = field.ident.clone().unwrap();
if field.attrs.iter().any(|attr| attr.path().is_ident("hclua_field")) {
let get_name = format_ident!("get_{}", field_ident);
let set_name = format_ident!("set_{}", field_ident);
let ty = field.ty.clone();
quote! {
fn #get_name(&mut self) -> &#ty {
&self.#field_ident
}
fn #set_name(&mut self, val: #ty) {
self.#field_ident = val;
}
}
} else {
quote! {}
}
})
.collect();
let registers: Vec<_> = fields.iter().map(|field| {
let field_ident = field.ident.clone().unwrap();
if field.attrs.iter().any(|attr| attr.path().is_ident("hclua_field")) {
let ty = field.ty.clone();
let get_name = format_ident!("get_{}", field_ident);
let set_name = format_ident!("set_{}", field_ident);
quote!{
hclua::LuaObject::add_object_method_get(lua, &stringify!(#field_ident), hclua::function1(|obj: &mut #ident| -> &#ty {
&obj.#field_ident
}));
// ...
}
} else {
quote!{}
}
}).collect();
通过生成TokenStream数组,在最终的时候进行源码展开#(#functions)*即可以得到我们的TokenStream拼接的效果.
let name = config.name;
let is_light = config.light;
let gen = quote! {
impl #ident {
fn register_field(lua: &mut hclua::Lua) {
#(#registers)*
}
fn register(lua: &mut hclua::Lua) {
let mut obj = if #is_light {
hclua::LuaObject::<#ident>::new_light(lua.state(), &#name)
} else {
hclua::LuaObject::<#ident>::new(lua.state(), &#name)
};
obj.create();
Self::register_field(lua);
}
fn object_def<P>(lua: &mut hclua::Lua, name: &str, param: P)
where
P: hclua::LuaPush,
{
hclua::LuaObject::<#ident>::object_def(lua, name, param);
}
#(#functions)*
}
// ...
};
gen.into()
这样子我们通过宏就实现了我们快速的实现方案.
Lua对象映射中,type(val)为一个object变量,在这基础上进行访问的都将会触发元表的操作metatable 。
我们访问任何对象如val.hc:
lua_getmetatable
若为meta__index
的key值,若不存在则返回空值__index
函数,此时调用该数第一个参数为val
,第二个参数为hc
val:hc()
即val.hc(val)
实现调用,结束流程lua_call(lua, 1, 1);
即可以实现字段的返回注:在变量中该值是否为字段处理过程会有相对的差别,又需要高效的进行验证,这里用的是全局的静态变量来存储是否为该类型的字段值.
lazy_static! {
static ref FIELD_CHECK: RwLock<HashSet<(TypeId, &'static str)>> = RwLock::new(HashSet::new());
}
完整源码:
extern "C" fn index_metatable(lua: *mut sys::lua_State) -> libc::c_int {
unsafe {
if lua_gettop(lua) < 2 {
let value = CString::new(format!("index field must use 2 top")).unwrap();
return luaL_error(lua, value.as_ptr());
}
}
if let Some(key) = String::lua_read_with_pop(lua, 2, 0) {
let typeid = Self::get_metatable_real_key();
unsafe {
sys::lua_getglobal(lua, typeid.as_ptr());
let is_field = LuaObject::is_field(&*key);
let key = CString::new(key).unwrap();
let t = lua_getfield(lua, -1, key.as_ptr());
if !is_field {
if t == sys::LUA_TFUNCTION {
return 1;
} else {
return 1;
}
}
lua_pushvalue(lua, 1);
lua_call(lua, 1, 1);
1
}
} else {
0
}
}
此时字段的获取已经完成了.
此时我们需要设置对象val.hc = "hclua":
lua_getmetatable
若为meta__newindex
的key值,若不存在则返回空值__newindex
函数,此时调用该数第一个参数为val
,第二个参数为hc
,第三个参数为字符串"hclua"
__set
即为hc__set
,我们查找meta["hc__set"] 若为空则返回失败,若为函数则转到7val
,第三个参数hclua
,并进行函数调用lua_pushvalue(lua, 1);
lua_pushvalue(lua, 3);
lua_call(lua, 2, 1);
此时字段的设置已经完成了.
Lua的处理速度较慢,为了高性能,通常有许多函数会放到Rust层或者底层进行处理,此时有一个快速的映射就可以方便代码的快速使用复用,而通过derive宏,我们可以快速的构建出想要的功能.
最后此篇关于在Lua中实现Rust对象的绑定的文章就讲到这里了,如果你想了解更多关于在Lua中实现Rust对象的绑定的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!