How do a pass a database variable to a function in Rust? - rust

I'm just starting to look at Rust. I wanted to experiment with a database, and found the sqlite repo which is good to have to experiment with.
I would like to know the "correct" way to pass the sqlite database variable to a function. The error messages that I was initially getting from the compiler appeared to indicate that when I passed the Db variable from main() to the function, it was gone, so I returned it. Although this appears to work, it doesn't seem to me that it would be the normal way. While I'm not a believer in a large number of Global variables, I attempted to create a Global variables, but I couldn't discover how to do that.
Below is the test program. Please note that I am not yet using the Rust naming conventions, but it is very-early days
The main lines in question are :
oDb1 = fCreateTable(oDb1);
fn fCreateTable(oDb1:sqlite::database::Database) -> sqlite::database::Database {
and what is the alternative and why is it necessary (in this instance) to return it?
Example program:
extern mod sqlite;
fn main() {
let mut oDb1:sqlite::database::Database;
oDb1 = fOpenDb();
oDb1 = fCreateTable(oDb1) ;
let mut iInsertTot: int = 0;
while iInsertTot < 25 {
let oDbExec = oDb1.exec("INSERT INTO test (sname, iborn) VALUES ('xxxxx', 1973)");
if (! oDbExec.is_ok()) {
fail!(fmt!("Insert Nr. %d Failed!", iInsertTot+1));
}
iInsertTot += 1;
}
println (fmt!("Inserts completed = %d", iInsertTot));
}
fn fOpenDb() -> sqlite::database::Database {
let oDbOpen = sqlite::open("test.db");
if oDbOpen.is_err() {
fail!(fmt!("Error opening test.db: %?", oDbOpen));
}
println(fmt!("Database Open OK? %?", oDbOpen.is_ok()));
oDbOpen.unwrap()
}
fn fCreateTable(oDb1:sqlite::database::Database) -> sqlite::database::Database {
let mut oDbExec = oDb1.exec("drop table if exists test");
println(fmt!("Drop Table OK? %?", oDbExec.is_ok()));
if (!oDbExec.is_ok()) {
fail!("Drop-table failed");
}
oDbExec = oDb1.exec("CREATE TABLE test (ikey INTEGER PRIMARY KEY not null,
sname text, iborn int)");
println(fmt!("Create OK? %?", oDbExec.is_ok()));
if !oDbExec.is_ok() {
fail!("Create Table failed");
}
oDb1
}

sqlite::database::Database implements Drop, meaning it has a destructor, meaning it is never copied and always moved: fCreateTable(oDb1) moves the database object out of oDb1: Now there's nothing left in oDb1! Of course, you can put back something. For example, when you return the database from fCreateTable, you again move - back into fCreateTable.
But this is a silly dance. Just don't move the database in the first place, borrowed a pointer to it:
fn main() {
let oDb1 = fOpenDb();
fCreateTable(&oDb1);
...
}
fn fCreateTable(oDb1: &sqlite::database::Database) {
...
}

Related

How do I get a JavaVM or JNIEnv from an already-running JVM using JNI?

I am working on a project which involves Rust and Java. I need to be able to use the JNI from the Rust side, without the Java side calling invoking it (because it is not my code). So far, I have been able to ensure my DLL is injected (open a small window on keypress, I have been using this for debugging).
A shortened example of the relevant code is the following:
use jni::sys::{JNI_GetCreatedJavaVMs, JNIInvokeInterface_};
let jvm_ptr = null_mut() as *mut *mut *const JNIInvokeInterface_;
let count = null_mut();
// hasn't crashed
JNI_GetCreatedJavaVMs(jvm_ptr, 1, count); // https://docs.rs/jni/latest/jni/sys/fn.JNI_GetCreatedJavaVMs.html
// crashes
My question is this: is it possible to/how do I get a JNI environment in this situation?
With the help of the comments, I got that crash to stop happening. The trick was to pre-allocate an array.
let jvm_ptr = Vec::with_capacity(1).as_mut_ptr();
let count = null_mut();
JNI_GetCreatedJavaVMs(jvm_ptr, 1, count);
You can't chunk a null pointer into the vmBuf parameter and then tell it that vmBuf points to an array of length 1 via bufLen. Translating the C++ code linked above, I would do something like
let mut count: jint = 0;
let check = JNI_GetCreatedJavaVMs(null_mut(), 0, &mut count);
assert!(check == JNI_OK);
let mut vms = vec![null_mut(); count as usize];
let check = JNI_GetCreatedJavaVMs(vms.as_mut_ptr(), vms.len() as i32, &mut count);
assert!(check == JNI_OK);
assert!(vms.len() == count as usize);
though that's probably a bit overkill since there can only be one VM. Still, checking the count is probably a good idea.
I have been using this many years. It can be polished....
try {
// how many JVMs is there?
JNI_GetCreatedJavaVMs(NULL, 0, &number_of_JVMs);
}
catch (exception e)
{
int x = 0;
}
if (number_of_JVMs > 0)
{
JavaVM** buffer = new JavaVM * [number_of_JVMs];
JNI_GetCreatedJavaVMs(buffer, number_of_JVMs, &number_of_JVMs);
// 2. get the data
jvm_handle = buffer[0];
if (!jvm_handle == 0)
return true;
else return false;
}

Gtk-rs: Set label within glib::timeout_add

I'm new to rust and having trouble with the scope of objects/variables in GTK. I have the following code, which works, but I need to set a label in the GTK Window to the text of the variable watch_text. Here is the code:
use adw::subclass::prelude::AdwApplicationWindowImpl;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{gio, glib, CompositeTemplate};
use glib::{clone, DateTime, timeout_add};
use std::time::Duration;
use std::sync::{Arc, Mutex};
fn setup_signals(&self) {
let imp = imp::FurWindow::from_instance(self);
let running = Arc::new(Mutex::new(false));
imp.start_button.connect_clicked(clone!(#weak self as this, #strong running => move |_| {
if !*running.lock().unwrap() {
let mut secs: u32 = 0;
let mut mins: u32 = 0;
let mut hrs: u32 = 0;
this.inapp_notification("Starting Timer!");
*running.lock().unwrap() = true;
let stopwatch = DateTime::now_local();
let duration = Duration::new(1,0);
let timer_repeat = timeout_add(duration, clone!(#strong running as running_clone => move || {
if *running_clone.lock().unwrap() {
secs += 1;
if secs > 59 {
secs = 0;
mins += 1;
if mins > 59 {
mins = 0;
hrs += 1;
}
}
let watch_text: &str = &format!("{:02}:{:02}:{:02}", hrs, mins, secs).to_string();
println!("{}",watch_text);
// **Here the println works, everything prints correctly,
// but I need to add watch_text to the label "watch"
// this.set_watch_time(watch_text);
}
Continue(*running_clone.lock().unwrap())
}));
} else {
this.inapp_notification("Stopping Timer!");
*running.lock().unwrap() = false;
}
}));
}
The issue is that in the commented section, no matter how I try to access or clone imp.watch, I get an error NonNull<GObject> cannot be sent between threads safely. How can I set the label text to watch_text?
The issue is that timeout_add() requires the passed callback to be Send, which is nice, because with this function you can pass values from one working thread to the GUI thread, to be processed and update the interface accordingly.
But GUI objects are not Send, because they live in the GUI thread and must be used only from the GUI thread, so they cannot be used for timeout_add().
But that is precisely why there is this other timeout_add_local(), that works just like the other one, except that it does not require Send, and that it must be called from the GUI thread, or else it will panic.

read in chunks with async-std

I'm trying to implement something similar to reading a file in Java with AsynchronousByteChannel like
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path...
channel.read(buffer,... new CompletionHandler<Integer, ByteBuffer>() {
#Override
public void completed(Integer result) {
...use buffer
}
i.e. read as much as OS gives, process, ask for more and so on.
What would be the most straightforward way to achieve this with async_std?
You can use the read method of the async_std::io::Read trait:
use async_std::prelude::*;
let mut reader = obtain_read_somehow();
let mut buf = [0; 4096]; // or however large you want it
// read returns a Poll<Result> so you have to handle the result
loop {
let byte_count = reader.read(&mut buf).await?;
if byte_count == 0 {
// 0 bytes read means we're done
break;
}
// call whatever handler function on the bytes read
handle(&buf[..byte_count]);
}

How to access rust variables outside the scope?

My code look like this
fn main() {
// some other codes goes here
let int = 1;
if int == 1 {
let x = "yes";
} else {
let x = "no";
}
if x == "yes" {
// some other codes goes here
println!("yes");
} else if x == "no" {
// some other codes goes here
println!("no")
}
}
When I run this I get this
error[E0425]: cannot find value `x` in this scope
--> src/main.rs:9:8
|
9 | if x == "yes" {
| ^ not found in this scope
error[E0425]: cannot find value `x` in this scope
--> src/main.rs:12:15
|
12 | } else if x == "no" {
| ^ not found in this scope
While searching for a solution I came across this post How do I access a variable outside of an `if let` expression? but could not able to understand the reason or its solution?
Easiest is by far to code it such that it is in scope in the first place.
You can assign variable with the result of a statement in a single assignment.
If you can make it as a one-liner, it also makes it arguably more readable.
If the actual processing is too long, nothing prevents you from just... making it a proper function.
let x = if int == 1 { "yes" } else { "no" };
// rest of the code accessing x.
Alternatively, the compiler will let you declare unassigned variables if you properly assign them later, with all the compile-time safety checks in place. Read the docs on RAII (Resource Acquisition Is Initialization) RAII Docs to see more how it works. In practice, it's just as simple as this:
let x;
if i == 1 {
x = "yes";
}
else {
x = "no";
}
// keep doing what you love
The compiler will error if there's a logic path where x doesn't get initialized, or if it gets initialized as a different type.
Notice you also do not need to declare it as mut, as the first value it gets will stay immutable. Unless you do want to change it afterwards, obviously.
You can't access a variable which is out of scope. But you use a workaround and set the variable in the same scope.
fn main(){
let int = 1;
let x = if int == 1 {
"yes"
} else {
"no"
};
if x == "yes" {
println!("yes");
} else if x == "no" {
println!("no");
}
}
In Rust each variable has a scope that starts where the variable in initialized. In you problem you try to use the variable x which is created inside of the if int == 1 and the if x == "yes", since if statements have a separate scope from the function main you cannot create a variable inside of your if statement and expect it not to be cleared when you leave scope. The simplest solution is to initialize the variable x where you want to have it used in if x == "yes", so let's say that we want the scope of x to start in main by putting let x; in main. In Rust you may have variable from the larger scope be visible to the scopes that are within that larger scope where the variable in initialized, so assigning the variable from the scope of an if statement is perfectly valid.
Please take a look at https://doc.rust-lang.org/rust-by-example/variable_bindings/scope.html for more information.
fn main() {
let x;
// some other codes goes here
let int = 1;
if int == 1 {
x = "yes";
} else {
x = "no";
}
if x == "yes" {
// some other codes goes here
println!("yes");
} else if x == "no" {
// some other codes goes here
println!("no")
}
}
But you could get rid of the two if statements and just use match:
fn main() {
let myint = 1;
match myint {
1 => {println!("yes")}
_ => {println!("no")}
}
}
The question
I believe you are asking what does this error mean?
To answer that, one must first answer, what is scope?
The answer
Scope, in lay terms, is the section of code where a variable exists.
So when the error says not found in this scope, it means the variable does not exist here.
An example
fn main() {
let a_bool = true;
let main_scope_x = 0;
if a_bool == true {
let if_scope_x = 1;
} // if_scope_x stops existing here!
println!("main x has the value {}", main_scope_x);
println!("if x has the value {}", if_scope_x); // this will cause an error, if_scope_x does not exist outside the if expression.
}
Further info
https://doc.rust-lang.org/stable/book/ch04-01-what-is-ownership.html
(Read the book! It's very good!)

Where is the Rust intrinsic called "transmute" actually implemented?

I'm trying to find the implementation for the Rust intrinsics, particularly the "transumte" intrinsic that takes one argument.
I've seen the following code in cast.rs, but as you can see, it merely delegates to some other implementation of transmute.
#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
intrinsics::transmute(thing)
}
Where is the actual implementation for intrinsics, especially the transmute intrinsic?
cast::transmute delegates to intrinsics::transmute. There is a module called intrinsics (now in libcore), it contains extern bindings to several functions, including transmute. As you can see from the module documentation, implementation of intrinsics is said to be located in librustc/middle/trans/foreign.rs.
However, as far as I can see, actual implementation of intrinsics is present in librustc/middle/trans/intrinsic.rs. You can search for transmute, and you will find an arm in a really big match statement which looks like this:
"transmute" => {
let (in_type, out_type) = (*substs.substs.tps.get(0),
*substs.substs.tps.get(1));
let llintype = type_of::type_of(ccx, in_type);
let llouttype = type_of::type_of(ccx, out_type);
let in_type_size = machine::llbitsize_of_real(ccx, llintype);
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
if in_type_size != out_type_size {
let sp = match ccx.tcx.map.get(ref_id.unwrap()) {
ast_map::NodeExpr(e) => e.span,
_ => fail!("transmute has non-expr arg"),
};
ccx.sess().span_fatal(sp,
format!("transmute called on types with different sizes: \
{intype} ({insize, plural, =1{# bit} other{# bits}}) to \
{outtype} ({outsize, plural, =1{# bit} other{# bits}})",
intype = ty_to_str(ccx.tcx(), in_type),
insize = in_type_size as uint,
outtype = ty_to_str(ccx.tcx(), out_type),
outsize = out_type_size as uint));
}
if !return_type_is_void(ccx, out_type) {
let llsrcval = get_param(decl, first_real_arg);
if type_is_immediate(ccx, in_type) {
match fcx.llretptr.get() {
Some(llretptr) => {
Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
RetVoid(bcx);
}
None => match (llintype.kind(), llouttype.kind()) {
(Pointer, other) | (other, Pointer) if other != Pointer => {
let tmp = Alloca(bcx, llouttype, "");
Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
Ret(bcx, Load(bcx, tmp));
}
(Array, _) | (_, Array) | (Struct, _) | (_, Struct) => {
let tmp = Alloca(bcx, llouttype, "");
Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
Ret(bcx, Load(bcx, tmp));
}
_ => {
let llbitcast = BitCast(bcx, llsrcval, llouttype);
Ret(bcx, llbitcast)
}
}
}
} else if type_is_immediate(ccx, out_type) {
let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
let ll_load = Load(bcx, llsrcptr);
Ret(bcx, ll_load);
} else {
// NB: Do not use a Load and Store here. This causes massive
// code bloat when `transmute` is used on large structural
// types.
let lldestptr = fcx.llretptr.get().unwrap();
let lldestptr = PointerCast(bcx, lldestptr, Type::i8p(ccx));
let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p(ccx));
let llsize = llsize_of(ccx, llintype);
call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
RetVoid(bcx);
};
} else {
RetVoid(bcx);
}
}
This seems to be code which generates code which will be inserted instead of a call to transmute. I'm no compiler expert, so please someone correct me if I'm wrong.

Resources