IVogel 2 роки тому
коміт
7a811cc309
6 змінених файлів з 402 додано та 0 видалено
  1. 2 0
      .gitignore
  2. 11 0
      Cargo.toml
  3. 18 0
      build.rs
  4. 197 0
      src/ldb.rs
  5. 31 0
      src/lib.rs
  6. 143 0
      src/ltree.rs

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/target
+/Cargo.lock

+ 11 - 0
Cargo.toml

@@ -0,0 +1,11 @@
+[package]
+name = "lsled"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+lua-shared = {git = "http://git.thetha.wtf/ivogel/lua-shared.git"}
+sled = "0.34.7"

+ 18 - 0
build.rs

@@ -0,0 +1,18 @@
+use std::env;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    println!("cargo:rerun-if-changed=build.rs");
+    let triple = &env::var("TARGET")?;
+    let mut target = triple.split("-");
+    let arch = target.next().unwrap_or("x86_64");
+    let search_paths = match arch {
+        "i686" => &[".", "bin/", "bin/linux32/", "garrysmod/bin/"][..],
+        "x86_64" => &[".", "bin/linux64/", "linux64"][..],
+        _ => &[][..],
+    };
+    for search_path in search_paths {
+        println!("cargo:rustc-link-arg=-Wl,-rpath,{}", search_path);
+        println!("cargo:warning={:?}", search_path);
+    }
+    Ok(())
+}

+ 197 - 0
src/ldb.rs

@@ -0,0 +1,197 @@
+use std::ops::{Deref, DerefMut};
+use std::ptr::null;
+
+use lua_shared as lua;
+use lua_shared::lua_State;
+
+use crate::check_slice;
+use crate::ltree::LTree;
+
+#[derive(Debug, Clone)]
+pub struct LDb(pub sled::Db);
+impl Deref for LDb {
+    type Target = sled::Db;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl DerefMut for LDb {
+    fn deref_mut(&mut self) -> &mut sled::Db {
+        &mut self.0
+    }
+}
+
+impl LDb {
+    pub fn l_open(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let db = sled::open(std::str::from_utf8_unchecked(check_slice!(state, 1)))?;
+            let ldb = lua::newuserdata(state, std::mem::size_of::<Self>()).cast::<Self>();
+            ldb.write(Self(db));
+            Self::metatble(state);
+            lua::setmetatable(state, -2);
+        }
+        Ok(1)
+    }
+
+    fn lm_name(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            let name = this.name();
+            lua::pushlstring(state, name.as_ptr(), name.len());
+            Ok(1)
+        }
+    }
+
+    fn lm_clear(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            this.clear()?;
+            Ok(0)
+        }
+    }
+
+    fn lm_get(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            if let Some(ivec) = this.0.get(check_slice!(state, 2))? {
+                lua::pushlstring(state, ivec.as_ptr(), ivec.len());
+            } else {
+                lua::pushnil(state)
+            }
+            Ok(1)
+        }
+    }
+
+    fn lm_insert(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            this.insert(check_slice!(state, 2), check_slice!(state, 3))?;
+            Ok(0)
+        }
+    }
+
+    fn lm_remove(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            this.remove(check_slice!(state, 2))?;
+            Ok(0)
+        }
+    }
+
+    fn lm_range(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            let mut range = this.range(check_slice!(state, 2)..=check_slice!(state, 3));
+            lua::pushfunction(state, move |state| {
+                if let Some(tree_name) = range.next() {
+                    let (key, value) = tree_name?;
+                    lua::pushlstring(state, key.as_ptr(), key.len());
+                    lua::pushlstring(state, value.as_ptr(), value.len());
+                    Ok(2)
+                } else {
+                    Ok(0)
+                }
+            });
+            Ok(1)
+        }
+    }
+
+    fn lm_scan_prefix(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            let prefix = {
+                let mut len = 0;
+                std::slice::from_raw_parts(lua::Loptlstring(state, 2, null(), &mut len), len)
+            };
+            let mut prefix = this.scan_prefix(prefix);
+            lua::pushfunction(state, move |state| {
+                if let Some(tree_name) = prefix.next() {
+                    let (key, value) = tree_name?;
+                    lua::pushlstring(state, key.as_ptr(), key.len());
+                    lua::pushlstring(state, value.as_ptr(), value.len());
+                    Ok(2)
+                } else {
+                    Ok(0)
+                }
+            });
+            Ok(1)
+        }
+    }
+
+    fn lm_tree_names(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            let mut iter = this.0.tree_names().into_iter();
+            lua::pushfunction(state, move |state| {
+                if let Some(tree_name) = iter.next() {
+                    lua::pushlstring(state, tree_name.as_ptr(), tree_name.len());
+                    Ok(1)
+                } else {
+                    Ok(0)
+                }
+            });
+            Ok(1)
+        }
+    }
+
+    fn lm_open_tree(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            let tree = this.open_tree(std::str::from_utf8_unchecked(check_slice!(state, 2)))?;
+            let ltree = lua::newuserdata(state, std::mem::size_of::<LTree>()).cast::<LTree>();
+            ltree.write(LTree(tree));
+            LTree::metatble(state);
+            lua::setmetatable(state, -2);
+            Ok(1)
+        }
+    }
+
+    fn lm_generate_id(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("csldb")).cast::<Self>();
+            lua::pushnumber(state, this.generate_id()? as _);
+            Ok(1)
+        }
+    }
+
+    fn __gc(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let _ = lua::Lcheckudata(state, 1, lua::cstr!("csldb"))
+                .cast::<Self>()
+                .read();
+            Ok(0)
+        }
+    }
+
+    fn metatble(state: lua_State) {
+        unsafe {
+            if lua::Lnewmetatable(state, lua::cstr!("csldb")) {
+                lua::pushvalue(state, -1);
+                lua::setfield(state, -2, lua::cstr!("__index"));
+                lua::pushfunction(state, Self::__gc);
+                lua::setfield(state, -2, lua::cstr!("__gc"));
+                lua::pushfunction(state, Self::lm_name);
+                lua::setfield(state, -2, lua::cstr!("name"));
+                lua::pushfunction(state, Self::lm_clear);
+                lua::setfield(state, -2, lua::cstr!("clear"));
+                lua::pushfunction(state, Self::lm_get);
+                lua::setfield(state, -2, lua::cstr!("get"));
+                lua::pushfunction(state, Self::lm_insert);
+                lua::setfield(state, -2, lua::cstr!("insert"));
+                lua::pushfunction(state, Self::lm_remove);
+                lua::setfield(state, -2, lua::cstr!("remove"));
+                lua::pushfunction(state, Self::lm_range);
+                lua::setfield(state, -2, lua::cstr!("range"));
+                lua::pushfunction(state, Self::lm_scan_prefix);
+                lua::setfield(state, -2, lua::cstr!("scan_prefix"));
+                lua::pushfunction(state, Self::lm_tree_names);
+                lua::setfield(state, -2, lua::cstr!("tree_names"));
+                lua::pushfunction(state, Self::lm_open_tree);
+                lua::setfield(state, -2, lua::cstr!("open_tree"));
+                lua::pushfunction(state, Self::lm_generate_id);
+                lua::setfield(state, -2, lua::cstr!("generate_id"));
+            }
+        }
+    }
+}

+ 31 - 0
src/lib.rs

@@ -0,0 +1,31 @@
+// use std::{collections::HashMap, hash::Hash};
+
+use ldb::LDb;
+use lua_shared as lua;
+use lua_shared::lua_State;
+
+mod ldb;
+mod ltree;
+
+#[macro_export]
+macro_rules! check_slice {
+    ($state:ident, $index:tt) => {{
+        let mut len = 0;
+        let str_ptr = lua_shared::Lchecklstring($state, $index, &mut len);
+        std::slice::from_raw_parts(str_ptr, len)
+    }};
+}
+
+#[no_mangle]
+unsafe extern "C" fn gmod13_open(state: lua_State) -> i32 {
+    lua::createtable(state, 0, 1);
+    lua::pushfunction(state, LDb::l_open);
+    lua::setfield(state, -2, lua::cstr!("open"));
+    lua::setfield(state, lua::GLOBALSINDEX, lua::cstr!("sled"));
+    0
+}
+
+#[no_mangle]
+unsafe extern "C" fn gmod13_close(_state: lua_State) -> i32 {
+    0
+}

+ 143 - 0
src/ltree.rs

@@ -0,0 +1,143 @@
+use std::ops::{Deref, DerefMut};
+use std::ptr::null;
+
+use lua_shared as lua;
+use lua_shared::lua_State;
+
+use crate::check_slice;
+
+#[derive(Debug, Clone)]
+pub struct LTree(pub sled::Tree);
+impl Deref for LTree {
+    type Target = sled::Tree;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl DerefMut for LTree {
+    fn deref_mut(&mut self) -> &mut sled::Tree {
+        &mut self.0
+    }
+}
+
+impl LTree {
+    fn lm_name(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("cslt")).cast::<Self>();
+            let name = this.name();
+            lua::pushlstring(state, name.as_ptr(), name.len());
+            Ok(1)
+        }
+    }
+
+    fn lm_clear(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("cslt")).cast::<Self>();
+            this.clear()?;
+            Ok(0)
+        }
+    }
+
+    fn lm_get(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("cslt")).cast::<Self>();
+            if let Some(ivec) = this.0.get(check_slice!(state, 2))? {
+                lua::pushlstring(state, ivec.as_ptr(), ivec.len());
+            } else {
+                lua::pushnil(state)
+            }
+            Ok(1)
+        }
+    }
+
+    fn lm_insert(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("cslt")).cast::<Self>();
+            this.insert(check_slice!(state, 2), check_slice!(state, 3))?;
+            Ok(0)
+        }
+    }
+
+    fn lm_remove(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("cslt")).cast::<Self>();
+            this.remove(check_slice!(state, 2))?;
+            Ok(0)
+        }
+    }
+
+    fn lm_range(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("cslt")).cast::<Self>();
+            let mut range = this.range(check_slice!(state, 2)..=check_slice!(state, 3));
+            lua::pushfunction(state, move |state| {
+                if let Some(tree_name) = range.next() {
+                    let (key, value) = tree_name?;
+                    lua::pushlstring(state, key.as_ptr(), key.len());
+                    lua::pushlstring(state, value.as_ptr(), value.len());
+                    Ok(2)
+                } else {
+                    Ok(0)
+                }
+            });
+            Ok(1)
+        }
+    }
+
+    fn lm_scan_prefix(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let this = &mut *lua::Lcheckudata(state, 1, lua::cstr!("cslt")).cast::<Self>();
+            let prefix = {
+                let mut len = 0;
+                std::slice::from_raw_parts(lua::Loptlstring(state, 2, null(), &mut len), len)
+            };
+            let mut prefix = this.scan_prefix(prefix);
+            lua::pushfunction(state, move |state| {
+                if let Some(tree_name) = prefix.next() {
+                    let (key, value) = tree_name?;
+                    lua::pushlstring(state, key.as_ptr(), key.len());
+                    lua::pushlstring(state, value.as_ptr(), value.len());
+                    Ok(2)
+                } else {
+                    Ok(0)
+                }
+            });
+            Ok(1)
+        }
+    }
+
+    fn __gc(state: lua_State) -> Result<i32, Box<dyn std::error::Error>> {
+        unsafe {
+            let _ = lua::Lcheckudata(state, 1, lua::cstr!("cslt"))
+                .cast::<Self>()
+                .read();
+            Ok(0)
+        }
+    }
+
+    pub fn metatble(state: lua_State) {
+        unsafe {
+            if lua::Lnewmetatable(state, lua::cstr!("cslt")) {
+                lua::pushvalue(state, -1);
+                lua::setfield(state, -2, lua::cstr!("__index"));
+                lua::pushfunction(state, Self::__gc);
+                lua::setfield(state, -2, lua::cstr!("__gc"));
+                lua::pushfunction(state, Self::lm_name);
+                lua::setfield(state, -2, lua::cstr!("name"));
+                lua::pushfunction(state, Self::lm_clear);
+                lua::setfield(state, -2, lua::cstr!("clear"));
+                lua::pushfunction(state, Self::lm_get);
+                lua::setfield(state, -2, lua::cstr!("get"));
+                lua::pushfunction(state, Self::lm_insert);
+                lua::setfield(state, -2, lua::cstr!("insert"));
+                lua::pushfunction(state, Self::lm_remove);
+                lua::setfield(state, -2, lua::cstr!("remove"));
+                lua::pushfunction(state, Self::lm_range);
+                lua::setfield(state, -2, lua::cstr!("range"));
+                lua::pushfunction(state, Self::lm_scan_prefix);
+                lua::setfield(state, -2, lua::cstr!("scan_prefix"));
+            }
+        }
+    }
+}