read in chunks with async-std - rust

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]);
}

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;
}

Trying to output sound with rust

I'm trying to output a simple sound (a square waveform). All seems to work except no sound is going to my speakers. I found cpal as a lib to manage sound, but maybe there is a better way to handle streams. Here is my code
use cpal::{Sample};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
fn main() {
let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err);
let host = cpal::default_host();
let device = host.default_output_device().expect("no output device available");
let supported_config = device.default_output_config().unwrap();
println!("Device: {}, Using config: {:?}", device.name().expect("flute"), supported_config);
let config = supported_config.into();
let stream = device.build_output_stream(&config, write_silence, err_fn).unwrap();
stream.play().unwrap();
std::thread::sleep(std::time::Duration::from_millis(3000));
}
fn write_silence(data: &mut [f32], _: &cpal::OutputCallbackInfo) {
let mut counter = 0;
for sample in data.iter_mut() {
let s = if (counter / 20) % 2 == 0 { &1.0 } else { &0.0 };
counter = counter + 1;
*sample = Sample::from(s);
}
println!("{:?}", data);
}
line 27 (println!("{:?}", data)) does output the samples of a square waveform.
I'm running this in the linux/crostini thing of chromebooks. It can be the problem.
Does anyone knows why it's not working ? And is cpal a good start for audio processing ?

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.

Can't convert NSData read from a local file and output as string in Swift

Well I am trying to creating a simple tool to read an specific offset address from a file that's within the project.
I can read it fine and get the bytes, the problem is that I want to convert the result into a string, but I just can't.
My output is this: <00000100 88000d00 02140dbb 05c3a282> but I want into String.
Found some examples of doing it using an extension for NSData, but still didn't work.
So anyone could help??
Here's my code:
class ViewController: UIViewController {
let filemgr = NSFileManager.defaultManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let pathToFile = NSBundle.mainBundle() .pathForResource("control", ofType: "bin")
let databuffer = filemgr.contentsAtPath(pathToFile!)
let file: NSFileHandle? = NSFileHandle(forReadingAtPath: pathToFile!)
if file == nil {
println("File open failed")
} else {
file?.seekToFileOffset(197584)
let byte = file?.readDataOfLength(16)
println(byte!)
file?.closeFile()
}
}
}
So long as you know the encoding, you can create a string from an NSData object like this
let str = NSString(data: data, encoding: NSUTF8StringEncoding)
By the way, you might want to try using if let to unwrap your optionals rather than force-unwrapping, to account for failure possibilities:
let filemgr = NSFileManager.defaultManager()
if let pathToFile = NSBundle.mainBundle() .pathForResource("control", ofType: "bin"),
databuffer = filemgr.contentsAtPath(pathToFile),
file = NSFileHandle(forReadingAtPath: pathToFile)
{
file.seekToFileOffset(197584)
let bytes = file.readDataOfLength(16)
let str = NSString(data: bytes, encoding: NSUTF8StringEncoding)
println(str)
file.closeFile()
}
else {
println("File open failed")
}
The correct answer following #Martin R suggestion to this link: https://codereview.stackexchange.com/a/86613/35991
Here's the code:
extension NSData {
func hexString() -> String {
// "Array" of all bytes:
let bytes = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes), count:self.length)
// Array of hex strings, one for each byte:
let hexBytes = map(bytes) { String(format: "%02hhx", $0) }
// Concatenate all hex strings:
return "".join(hexBytes)
}
}
And I used like this:
let token = byte.hexString()

How do a pass a database variable to a function in 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) {
...
}

Resources