From 879710c91ceb2befd8de85cafe8ee0b00caa3a85 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Wed, 18 Oct 2023 18:43:06 -0700 Subject: [PATCH] JNA client - connect and get. Signed-off-by: Yury-Fridlyand --- java/.cargo/config.toml | 2 +- java/Cargo.toml | 10 +- java/benchmarks/build.gradle | 2 + .../benchmarks/BenchmarkingApp.java | 9 +- .../javababushka/benchmarks/jna/Babushka.java | 133 ++++++++ java/javababushka.hpp | 29 +- java/jna-stuff/build.gradle | 2 +- java/jna-stuff/src/main/java/Loader.java | 141 ++++++-- java/src/lib.rs | 316 ++++++++++++------ 9 files changed, 486 insertions(+), 158 deletions(-) create mode 100644 java/benchmarks/src/main/java/javababushka/benchmarks/jna/Babushka.java mode change 100755 => 100644 java/javababushka.hpp mode change 100755 => 100644 java/jna-stuff/build.gradle mode change 100755 => 100644 java/jna-stuff/src/main/java/Loader.java diff --git a/java/.cargo/config.toml b/java/.cargo/config.toml index 24a6f21533..07cff72751 100644 --- a/java/.cargo/config.toml +++ b/java/.cargo/config.toml @@ -1,3 +1,3 @@ [env] -BABUSHKA_NAME = { value = "BabushkaPy", force = true } +BABUSHKA_NAME = { value = "BabushkaJava", force = true } BABUSHKA_VERSION = "0.1.0" diff --git a/java/Cargo.toml b/java/Cargo.toml index a2b9d7b0bc..2cb1a29cb9 100644 --- a/java/Cargo.toml +++ b/java/Cargo.toml @@ -10,12 +10,14 @@ name = "javababushka" crate-type = ["cdylib"] [dependencies] -# redis = { path = "../submodules/redis-rs/redis", features = ["aio", "tokio-comp", "connection-manager", "tls", "tokio-rustls-comp"] } -# babushka = { path = "../babushka-core" } -# tokio = { version = "^1", features = ["rt", "macros", "rt-multi-thread", "time"] } -logger_core = {path = "../logger_core"} +redis = { path = "../submodules/redis-rs/redis", features = ["aio", "tokio-comp", "connection-manager", "tls", "tokio-rustls-comp"] } +babushka = { path = "../babushka-core" } +tokio = { version = "^1", features = ["rt", "macros", "rt-multi-thread", "time"] } +logger_core = { path = "../logger_core" } tracing-subscriber = "0.3.16" thiserror = "1.0.49" +num-derive = "0.4.1" +num-traits = "0.2.17" [profile.release] lto = true diff --git a/java/benchmarks/build.gradle b/java/benchmarks/build.gradle index 8d9e500284..8c0aaec33a 100644 --- a/java/benchmarks/build.gradle +++ b/java/benchmarks/build.gradle @@ -18,6 +18,8 @@ dependencies { implementation 'io.lettuce:lettuce-core:6.2.6.RELEASE' implementation 'commons-cli:commons-cli:1.5.0' implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0' + + implementation "net.java.dev.jna:jna:5.8.0" } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java/benchmarks/src/main/java/javababushka/benchmarks/BenchmarkingApp.java b/java/benchmarks/src/main/java/javababushka/benchmarks/BenchmarkingApp.java index 66ea1f5029..e3316a1b71 100644 --- a/java/benchmarks/src/main/java/javababushka/benchmarks/BenchmarkingApp.java +++ b/java/benchmarks/src/main/java/javababushka/benchmarks/BenchmarkingApp.java @@ -11,6 +11,7 @@ import java.util.stream.Stream; import javababushka.benchmarks.jedis.JedisClient; import javababushka.benchmarks.jedis.JedisPseudoAsyncClient; +import javababushka.benchmarks.jna.Babushka; import javababushka.benchmarks.lettuce.LettuceAsyncClient; import javababushka.benchmarks.lettuce.LettuceClient; import org.apache.commons.cli.CommandLine; @@ -53,7 +54,7 @@ public static void main(String[] args) { testClientSetGet(LettuceAsyncClient::new, runConfiguration, true); break; case BABUSHKA: - System.out.println("Babushka not yet configured"); + testClientSetGet(Babushka::new, runConfiguration, false); break; } } @@ -150,7 +151,7 @@ private static RunConfiguration verifyOptions(CommandLine line) throws ParseExce case ALL_SYNC: return Stream.of( ClientName.JEDIS, - // ClientName.BABUSHKA, + ClientName.BABUSHKA, ClientName.LETTUCE); default: return Stream.of(e); @@ -227,8 +228,8 @@ public RunConfiguration() { concurrentTasks = List.of(10, 100); clients = new ClientName[] { - // ClientName.BABUSHKA, - ClientName.JEDIS, ClientName.JEDIS_ASYNC, ClientName.LETTUCE, ClientName.LETTUCE_ASYNC + ClientName.BABUSHKA, + ClientName.JEDIS, ClientName.LETTUCE, }; host = "localhost"; port = 6379; diff --git a/java/benchmarks/src/main/java/javababushka/benchmarks/jna/Babushka.java b/java/benchmarks/src/main/java/javababushka/benchmarks/jna/Babushka.java new file mode 100644 index 0000000000..9934a7ea8c --- /dev/null +++ b/java/benchmarks/src/main/java/javababushka/benchmarks/jna/Babushka.java @@ -0,0 +1,133 @@ +package javababushka.benchmarks.jna; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Structure; +import javababushka.benchmarks.SyncClient; +import javababushka.benchmarks.utils.ConnectionSettings; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +public class Babushka implements SyncClient { + + private final long ptr = lib.init_client0(42); + + // = enum + public static enum ResultType { + Str(0), + Int(1), + Nil(2), + Data(3), + Bulk(4), + Ok(5), + Err(6), + Undef(-1); + + private int id; + ResultType(int id) { + this.id = id; + } + + public static ResultType of(int val) { + switch (val) { + case 0: return ResultType.Str; + case 1: return ResultType.Int; + case 2: return ResultType.Nil; + case 3: return ResultType.Data; + case 4: return ResultType.Bulk; + case 5: return ResultType.Ok; + case 6: return ResultType.Err; + default: return ResultType.Undef; + } + } + } + + public interface RustLib extends Library { + + @Structure.FieldOrder({"error", "value_type", "string", "num"}) + public static class BabushkaResult extends Structure { + public BabushkaResult() { + error = null; + value_type = 0; + string = null; + num = 0; + } + public static class ByValue extends BabushkaResult implements Structure.ByValue { } + public String error = null; + public int value_type = 0; + public String string = null; + public long num = 0; + }; + + public long init_client0(int data); + public BabushkaResult.ByValue connect0(long client, String address); + public BabushkaResult.ByValue set0(long client, String key, String value); + public BabushkaResult.ByValue get0(long client, String key); + } + + private static final RustLib lib; + static { + var is_win = System.getProperty("os.name").contains("Windows"); + var targetDir = Paths.get("jna-stuff", "build", "resources", "main", is_win ? "win32-x86-64" : "linux-x86-64").toAbsolutePath(); + + //System.setProperty("jna.debug_load", "true"); + System.setProperty("jna.library.path", targetDir.toString()); + + var created = targetDir.toFile().mkdirs(); + try { + if (is_win) { + Files.copy( + Paths.get(System.getProperty("user.dir"), "target", "debug", "javababushka.dll"), + Paths.get(targetDir.toString(), "javababushka.dll"), + StandardCopyOption.REPLACE_EXISTING); + } else { + Files.copy( + Paths.get(System.getProperty("user.dir"), "..", "target", "debug", "libjavababushka.so"), + Paths.get(targetDir.toString(), "libjavababushka.so"), + StandardCopyOption.REPLACE_EXISTING); + } + } catch (IOException e) { + System.out.printf("Failed to copy lib: %s%n", e.getMessage()); + e.printStackTrace(); + } + + lib = Native.load("javababushka", RustLib.class); + } + + @Override + public void connectToRedis() { + connectToRedis(new ConnectionSettings("localhost", 6379, false)); + } + + @Override + public void connectToRedis(ConnectionSettings connectionSettings) { + var connStr = String.format( + "%s://%s:%d", + connectionSettings.useSsl ? "rediss" : "redis", + connectionSettings.host, + connectionSettings.port); + lib.connect0(ptr, connStr); + } + + @Override + public String getName() { + return "JNA babushka"; + } + + @Override + public void set(String key, String value) { + + } + + @Override + public String get(String key) { + var res = lib.get0(ptr, key); + if (res.value_type == ResultType.Str.id) { + return res.string; + } + return res.error; + } +} diff --git a/java/javababushka.hpp b/java/javababushka.hpp old mode 100755 new mode 100644 index 1331438fef..37a90b06a2 --- a/java/javababushka.hpp +++ b/java/javababushka.hpp @@ -4,20 +4,25 @@ #include #include +template +struct Option; + struct BabushkaResultStr { const char *error; const char *result; }; -struct BabushkaValue { +struct BabushkaResult { + const char *error; + uint32_t value_type; const char *str; int64_t num; }; -struct BabushkaResult { - const char *error; - uint8_t value_type; - BabushkaValue value; +struct BabushkaClient { + Option> runtime; + Option> connection; + int32_t data; }; extern "C" { @@ -36,4 +41,18 @@ BabushkaResult static_function2_3(); BabushkaResult static_function2_4(); +uint64_t init_client0(int32_t data); + +BabushkaResult test0(uint64_t ptr, const char *address); + +BabushkaResult connect0(uint64_t ptr, const char *address); + +BabushkaResult set0(uint64_t ptr, const char *key, const char *value); + +BabushkaResult get0(uint64_t ptr, const char *key); + +BabushkaResult set(BabushkaClient *self, const char *key, const char *value); + +BabushkaResult get(BabushkaClient *self, const char *key); + } // extern "C" diff --git a/java/jna-stuff/build.gradle b/java/jna-stuff/build.gradle old mode 100755 new mode 100644 index eddb64fa79..941771480f --- a/java/jna-stuff/build.gradle +++ b/java/jna-stuff/build.gradle @@ -21,4 +21,4 @@ test { application { mainClass = 'Loader' -} \ No newline at end of file +} diff --git a/java/jna-stuff/src/main/java/Loader.java b/java/jna-stuff/src/main/java/Loader.java old mode 100755 new mode 100644 index 1c7665c761..07a8bf8965 --- a/java/jna-stuff/src/main/java/Loader.java +++ b/java/jna-stuff/src/main/java/Loader.java @@ -10,15 +10,33 @@ public class Loader { // = enum - public static class ResultType { - public static final int Str = 0; - public static final int Int = 1; - public static final int Nil = 2; - public static final int Data = 3; - public static final int Bulk = 4; - public static final int Ok = 5; - public static final int Err = 6; - public static final int Undef = -1; + public static enum ResultType { + Str(0), + Int(1), + Nil(2), + Data(3), + Bulk(4), + Ok(5), + Err(6), + Undef(-1); + + private int id; + ResultType(int id) { + this.id = id; + } + + public static ResultType of(int val) { + switch (val) { + case 0: return ResultType.Str; + case 1: return ResultType.Int; + case 2: return ResultType.Nil; + case 3: return ResultType.Data; + case 4: return ResultType.Bulk; + case 5: return ResultType.Ok; + case 6: return ResultType.Err; + default: return ResultType.Undef; + } + } }; public interface RustLib extends Library { @@ -41,51 +59,59 @@ public static class ByValue extends BabushkaResultStr implements Structure.ByVal public String result; } - @Structure.FieldOrder({"str", "num"/*, "data", "bulk"*/}) - public static class BabushkaValue extends Structure { - public BabushkaValue() { - str = null; - num = 0; - } - //public static class ByReference extends BabushkaValue implements Structure.ByReference { - //public ByReference() { } - //} - public static class ByValue extends BabushkaValue implements Structure.ByValue { - //public ByValue() { } - } - public String str; - public long num; -// List data; -// List bulk; - }; - - @Structure.FieldOrder({"error", "value_type", "value"}) + @Structure.FieldOrder({"error", "value_type", "string", "num"}) public static class BabushkaResult extends Structure { public BabushkaResult() { error = null; value_type = 0; - value = null; + string = null; + num = 0; } public static class ByValue extends BabushkaResult implements Structure.ByValue { } public String error = null; - public byte value_type = 0; + public int value_type = 0; //public BabushkaValue.ByReference value; - public BabushkaValue.ByValue value = null; + public String string = null; + public long num = 0; }; + + public static class BabushkaClient extends Structure { + public static class ByValue extends BabushkaClient implements Structure.ByValue { } + public static class ByReference extends BabushkaClient implements Structure.ByReference { } + } + + public long init_client0(int data); + public BabushkaResult.ByValue connect0(long client, String address); + public BabushkaResult.ByValue test0(long client, String address); + + + public BabushkaResult.ByValue set0(long client, String key, String value); + + public BabushkaResult.ByValue get0(long client, String key); + + } public static void main(String [] args) { - var targetDir = Paths.get("jna-stuff", "build", "resources", "main", "win32-x86-64").toAbsolutePath(); + var is_win = System.getProperty("os.name").contains("Windows"); + var targetDir = Paths.get("jna-stuff", "build", "resources", "main", is_win ? "win32-x86-64" : "linux-x86-64").toAbsolutePath(); //System.setProperty("jna.debug_load", "true"); System.setProperty("jna.library.path", targetDir.toString()); var created = targetDir.toFile().mkdirs(); try { - Files.copy( - Paths.get(System.getProperty("user.dir"), "target", "debug", "javababushka.dll"), - Paths.get(targetDir.toString(), "javababushka.dll"), - StandardCopyOption.REPLACE_EXISTING); + if (is_win) { + Files.copy( + Paths.get(System.getProperty("user.dir"), "target", "debug", "javababushka.dll"), + Paths.get(targetDir.toString(), "javababushka.dll"), + StandardCopyOption.REPLACE_EXISTING); + } else { + Files.copy( + Paths.get(System.getProperty("user.dir"), "..", "target", "debug", "libjavababushka.so"), + Paths.get(targetDir.toString(), "libjavababushka.so"), + StandardCopyOption.REPLACE_EXISTING); + } } catch (IOException e) { System.out.printf("Failed to copy lib: %s%n", e.getMessage()); e.printStackTrace(); @@ -107,5 +133,48 @@ public static void main(String [] args) { var res2_3 = lib.static_function2_3(); var res2_4 = lib.static_function2_4(); int a = 5; + + var bab = lib.init_client0(42); + var t1 = lib.test0(bab, "pewpew"); + var t2 = lib.test0(bab, "ololo"); + var t3 = lib.test0(bab, "ikiki"); + + + + + + + + + + + System.out.println("Before connect"); + var con = lib.connect0(bab, "redis://127.0.0.1:6379"); + System.out.println("After connect"); + if (con.value_type == ResultType.Ok.id) { + System.out.println("Connected"); + } else { + System.out.printf("Conn failed: Res = %s, str = %s, err = %s%n", ResultType.of(con.value_type), con.string, con.error); + } + + System.out.println("=======\nBefore set"); + var set = lib.set0(bab, "kkkey", "ololo"); + System.out.println("After set"); + if (set.value_type == ResultType.Ok.id) { + System.out.println("Set ok"); + } else { + System.out.printf("Set failed: Res = %s, str = %s, err = %s%n", ResultType.of(set.value_type), set.string, set.error); + } + + System.out.println("=======\nBefore get"); + var get = lib.get0(bab, "key"); + System.out.println("After get"); + if (get.value_type == ResultType.Str.id) { + System.out.printf("Get ok: %s%n", get.string); + } else { + System.out.printf("Set failed: Res = %s, str = %s, err = %s%n", ResultType.of(get.value_type), get.string, get.error); + } + + int b = 5; } } diff --git a/java/src/lib.rs b/java/src/lib.rs index 1de033a257..7b5f5249c0 100644 --- a/java/src/lib.rs +++ b/java/src/lib.rs @@ -3,15 +3,16 @@ use std::ffi::{CStr,CString}; use std::str; use std::mem; use std::ptr::null; - -/* use std::sync::{Mutex}; +//* use redis::aio::MultiplexedConnection; use redis::{Client, ErrorKind, FromRedisValue, RedisResult, Value}; use redis::{AsyncCommands, RedisError}; use tokio::runtime::Builder; use tokio::runtime::Runtime; -*/ +// */ + + #[no_mangle] pub extern fn static_function_which_throws() -> BabushkaResultStr { BabushkaResultStr { error: str_to_ptr(""), result: str_to_ptr("hello from rust -> static function which throws") } @@ -27,13 +28,9 @@ pub extern fn static_function2_0() -> BabushkaResult { //BabushkaResult::from_str(str_to_ptr("ololo")) BabushkaResult { error: null(), - value_type: ResultType::Str as u8, - //* - value: BabushkaValue { - str: str_to_ptr("ololo"), - num: 0 - } - // */ + value_type: ResultType::Str as u32, + str: str_to_ptr("ololo"), + num: 0 } } @@ -42,8 +39,9 @@ pub extern fn static_function2_1() -> BabushkaResult { //BabushkaResult::from_err(str_to_ptr("oh no")) BabushkaResult { error: str_to_ptr("oh no"), - value_type: ResultType::Err as u8, - value: Default::default() + value_type: ResultType::Err as u32, + str: null(), + num: 0 } } @@ -52,13 +50,9 @@ pub extern fn static_function2_2() -> BabushkaResult { //BabushkaResult::from_int(100500) BabushkaResult { error: null(), - value_type: ResultType::Int as u8, - //* - value: BabushkaValue { - str: null(), - num: 100500 - } - // */ + value_type: ResultType::Int as u32, + str: null(), + num: 100500 } } @@ -67,8 +61,9 @@ pub extern fn static_function2_3() -> BabushkaResult { //BabushkaResult::from_ok() BabushkaResult { error: null(), - value_type: ResultType::Ok as u8, - value: Default::default() + value_type: ResultType::Ok as u32, + str: null(), + num: 0 } } @@ -76,17 +71,24 @@ pub extern fn static_function2_3() -> BabushkaResult { pub extern fn static_function2_4() -> BabushkaResult { BabushkaResult { error: null(), - value_type: ResultType::Nil as u8, - value: Default::default() + value_type: ResultType::Nil as u32, + str: null(), + num: 0 } } /// Convert a native string to a Rust string -fn to_string(pointer: * const c_char) -> String { +fn ptr_to_string(pointer: * const c_char) -> String { let slice = unsafe { CStr::from_ptr(pointer).to_bytes() }; str::from_utf8(slice).unwrap().to_string() } +/// Convert a native string to a Rust string +fn ptr_to_str(pointer: * const c_char) -> &'static str { + let slice = unsafe { CStr::from_ptr(pointer).to_bytes() }; + str::from_utf8(slice).unwrap() +} + /// Convert a Rust string to a native string fn string_to_ptr(string: String) -> * const c_char { let cs = CString::new(string.as_bytes()).unwrap(); @@ -113,8 +115,11 @@ pub struct BabushkaResultStr { pub result: * const c_char } +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; + // redis::Value -#[repr(C)] +#[derive(FromPrimitive)] pub enum ResultType { Str = 0, // * const c_char Int = 1, // i64 @@ -128,102 +133,84 @@ pub enum ResultType { #[repr(C)] pub struct BabushkaResult { pub error: * const c_char, - pub value_type: u8, //ResultType, - value: BabushkaValue, + pub value_type: u32, //ResultType, + pub str: * const c_char, + pub num: i64, } -//impl BabushkaResult { -/* - pub fn from_str(str: * const c_char) -> Self { +impl BabushkaResult { + pub fn from_str(str: String) -> Self { Self { error: null(), - value_type: ResultType::Str, - value: BabushkaValue { - str: str, - num: 0, -// data: Vec::new(), -// bulk: Vec::new(), - } - } - } - - pub fn from_int(int: i64) -> Self { - Self { - error: null(), - value_type: ResultType::Int, - value: BabushkaValue { - str: null(), - num: int, -// data: Vec::new(), -// bulk: Vec::new(), - } + value_type: ResultType::Str as u32, + str: string_to_ptr(str), + num: 0, } } - pub fn from_data(data: Vec) -> Self { + pub fn from_empty_str() -> Self { Self { error: null(), - value_type: ResultType::Data, - value: BabushkaValue { - str: null(), - num: 0, -// data: data, -// bulk: Vec::new(), - } + value_type: ResultType::Str as u32, + str: null(), + num: 0, } } - pub fn from_bulk(bulk: Vec) -> Self { + pub fn from_int(int: i64) -> Self { Self { error: null(), - value_type: ResultType::Bulk, - value: BabushkaValue { - str: null(), - num: 0, -// data: Vec::new(), -// bulk: bulk, - } + value_type: ResultType::Int as u32, + str: null(), + num: int, } } - pub fn from_err(err: * const c_char) -> Self { + pub fn from_err(err: String) -> Self { Self { - error: err, - value_type: ResultType::Err, - value: BabushkaValue::default() + error: string_to_ptr(err), + value_type: ResultType::Err as u32, + str: null(), + num: 0, } } pub fn from_nil() -> Self { Self { error: null(), - value_type: ResultType::Nil, - value: BabushkaValue::default() + value_type: ResultType::Nil as u32, + str: null(), + num: 0, } } pub fn from_ok() -> Self { Self { error: null(), - value_type: ResultType::Ok, - value: BabushkaValue::default() + value_type: ResultType::Ok as u32, + str: null(), + num: 0, } } -*/ -/* - #[no_mangle] - pub extern fn get_str(&self) -> * const c_char { - self.value.str + pub fn get_type(&self) -> ResultType { + // unsafe { std::mem::transmute(self.value_type as u32) }; + ResultType::from_u32(self.value_type).unwrap() } - #[no_mangle] - pub extern fn get_int(&self) -> i64 { - self.value.num + pub fn get_err(&self) -> String { + ptr_to_string(self.error) + } + + pub fn get_str(&self) -> String { + ptr_to_string(self.str) + } + + pub fn get_int(&self) -> i64 { + self.num } -*/ // TODO other types -//} +} #[repr(C)] pub struct BabushkaValue { @@ -245,13 +232,111 @@ impl Default for BabushkaValue { } -/* + #[repr(C)] pub struct BabushkaClient { runtime: Option>, connection: Option>, + //runtime: Option>, + //connection: Option>, + data: i32 +} + + +#[no_mangle] +pub extern fn init_client0(data: i32) -> u64 { + let p = Box::::into_raw(Box::new( + BabushkaClient { + runtime: None, + connection: None, + data + })); + p as u64 + //p.into(); +} + +#[no_mangle] +pub extern fn test0(ptr: u64, address: * const c_char) -> BabushkaResult { + let mut babushka = unsafe { Box::from_raw(ptr as *mut BabushkaClient) }; + babushka.data += 15; + BabushkaResult { + error: null(), + value_type: ResultType::Ok as u32, + str: string_to_ptr(format!("{} {}", babushka.data, ptr_to_string(address))), + num: Box::::into_raw(babushka) as i64, + } +} + +//* +#[no_mangle] +pub extern fn connect0(ptr: u64, address: * const c_char) -> BabushkaResult { + let mut babushka = unsafe { Box::from_raw(ptr as *mut BabushkaClient) }; + let client_res = redis::Client::open(ptr_to_string(address)); + let client : Client; + + match client_res { + Ok(c) => client = c, + Err(err) => return BabushkaResult::from_err(err.to_string()) + } + + let runtime_res = + Builder::new_multi_thread() + .enable_all() + .thread_name("Babushka java thread") + .build(); + + let runtime : Runtime; + + match runtime_res { + Ok(rt) => runtime = rt, + Err(err) => return BabushkaResult::from_err(err.to_string()) + } + + let _runtime_handle = runtime.enter(); + + let connection_res = runtime + .block_on(client.get_multiplexed_async_connection()); + + let connection : MultiplexedConnection; + + match connection_res { + Ok(c) => connection = c, + Err(err) => return BabushkaResult::from_err(err.to_string()) + } + + babushka.runtime = Some(Mutex::new(runtime)); + babushka.connection = Some(Mutex::new(connection)); + + Box::::into_raw(babushka); + BabushkaResult::from_ok() } +#[no_mangle] +pub extern fn set0(ptr: u64, key: * const c_char, value: * const c_char) -> BabushkaResult { + let mut babushka = unsafe { Box::from_raw(ptr as *mut BabushkaClient) }; + //self.runtime.spawn(async move { + babushka.connection.as_mut().unwrap().lock().unwrap() + .set::(ptr_to_string(key), ptr_to_string(value)); // TODO try RedisValue + //}); + Box::::into_raw(babushka); + BabushkaResult::from_ok() +} + +#[no_mangle] +pub extern fn get0(ptr: u64, key: * const c_char) -> BabushkaResult { + let mut babushka = unsafe { Box::from_raw(ptr as *mut BabushkaClient) }; + let res = babushka.runtime.as_mut().unwrap().lock().unwrap().block_on(async { + babushka.connection.as_mut().unwrap().lock().unwrap().get::>(ptr_to_string(key)).await + }); + Box::::into_raw(babushka); + match res { + Ok(Some(val)) => BabushkaResult::from_str(val), + Ok(None) => BabushkaResult::from_empty_str(), + Err(err) => BabushkaResult::from_err(err.to_string()) + } +} +// */ + impl BabushkaClient { /* fn new() -> Self { @@ -261,20 +346,35 @@ impl BabushkaClient { } }*/ +/* + #[no_mangle] + pub extern fn connect(&mut self, address: * const c_char) -> BabushkaResult { + self.runtime = Some(Mutex::new(BabushkaValue::default())); + self.connection = Some(Mutex::new(BabushkaValue::default())); + + BabushkaResult::from_str(ptr_to_string(address).to_lowercase()) + } +*/ #[no_mangle] - pub extern fn class_function(&self) -> String { - "hello from rust -> class function".into() + pub extern fn set(&mut self, key: * const c_char, value: * const c_char) -> BabushkaResult { + BabushkaResult::from_str(ptr_to_string(key) + ptr_to_str(value)) } #[no_mangle] - pub extern fn connect(&mut self, address: String) -> Result<(), String> { + pub extern fn get(&mut self, key: * const c_char) -> BabushkaResult { + BabushkaResult::from_str(ptr_to_string(key).repeat(3)) + } + +/* + #[no_mangle] + pub extern fn connect(&mut self, address: String) -> BabushkaResult { //self.client = Some(redis::Client::open(address)?); let client_res = redis::Client::open(address); let client : Client; match client_res { Ok(c) => client = c, - Err(err) => return Err(err.to_string()) + Err(err) => return BabushkaResult::from_err(err.to_string()) } let runtime_res = @@ -287,7 +387,7 @@ impl BabushkaClient { match runtime_res { Ok(rt) => runtime = rt, - Err(err) => return Err(err.to_string()) + Err(err) => return BabushkaResult::from_err(err.to_string()) } let _runtime_handle = runtime.enter(); @@ -299,13 +399,13 @@ impl BabushkaClient { match connection_res { Ok(c) => connection = c, - Err(err) => return Err(err.to_string()) + Err(err) => return BabushkaResult::from_err(err.to_string()) } self.runtime = Some(Mutex::new(runtime)); self.connection = Some(Mutex::new(connection)); - Ok(()) + BabushkaResult::from_ok() } /* @@ -315,63 +415,65 @@ impl BabushkaClient { */ // TODO support any type for value #[no_mangle] - pub extern fn set(&mut self, key: String, value: String) -> Result<(), String> { + pub extern fn set(&mut self, key: String, value: String) -> BabushkaResult { //self.runtime.spawn(async move { self.connection.as_mut().unwrap().lock().unwrap() //.set/*::*/(key, value); .set::(key, value); // TODO try RedisValue //}); - Ok(()) + BabushkaResult::from_ok() } #[no_mangle] - pub extern fn set2(&mut self, key: String, value: Option) -> Result<(), String> { + pub extern fn set2(&mut self, key: String, value: Option) -> BabushkaResult { //self.runtime.spawn(async move { //let val: Value = value.map_or_else(|| { Value::Nil }, |s| { Value::Status(s) }); self.connection.as_mut().unwrap().lock().unwrap() //.set/*::*/(key, value); .set::, Option, ()>(Some(key), value); // TODO try RedisValue //}); - Ok(()) + BabushkaResult::from_ok() } // TODO support any type for value // TODO support null value (Option<...>) - // TODO handle (nil) // TODO handle other types #[no_mangle] - pub extern fn get(&mut self, key: String) -> Result { + pub extern fn get(&mut self, key: String) -> BabushkaResult { let res = self.runtime.as_mut().unwrap().lock().unwrap().block_on(async { self.connection.as_mut().unwrap().lock().unwrap().get::(key).await }); match res { - Ok(val) => Ok(val), - Err(err) => Err(err.to_string()) + Ok(val) => BabushkaResult::from_str(val), + Err(err) => BabushkaResult::from_err(err.to_string()) } } #[no_mangle] - pub extern fn get2(&mut self, key: String) -> Result { + pub extern fn get2(&mut self, key: String) -> BabushkaResult { let res = self.runtime.as_mut().unwrap().lock().unwrap().block_on(async { self.connection.as_mut().unwrap().lock().unwrap().get::(key).await }); match res { - Ok(val) => Ok(String::from_redis_value(&val).unwrap()), - Err(err) => Err(err.to_string()) + Ok(val) => BabushkaResult::from_str(String::from_redis_value(&val).unwrap()), + Err(err) => BabushkaResult::from_err(err.to_string()) } } #[no_mangle] - pub extern fn get3(&mut self, key: String) -> Result, String> { + pub extern fn get3(&mut self, key: String) -> BabushkaResult { let res = self.runtime.as_mut().unwrap().lock().unwrap().block_on(async { self.connection.as_mut().unwrap().lock().unwrap().get::>(key).await }); match res { - Ok(val) => Ok(val), - Err(err) => Err(err.to_string()) + Ok(Some(val)) => BabushkaResult::from_str(val), + Ok(None) => BabushkaResult::from_empty_str(), + Err(err) => BabushkaResult::from_err(err.to_string()) } } + */ + /* #[no_mangle] pub extern fn get4(&mut self, key: String) -> Result<* const String, String> { let res = self.runtime.as_mut().unwrap().lock().unwrap().block_on(async { @@ -387,5 +489,5 @@ impl BabushkaClient { Err(err) => Err(err.to_string()) } } + */ } -*/