How would I save this to a file instead of stdout? - rust

I'm probably just missing something simple
and I have used std::fs::File
use std::io::{stdout, Write};
use curl::easy::Easy;
fn main() {
let mut easy = Easy::new();
easy.url("checkip.amazonaws.com").unwrap();
easy.write_function(|data| {
Ok(stdout().write(data).unwrap())
}).unwrap();
easy.perform().unwrap();
}

Move a file into the closure and write all the content:
use std::fs::File;
use std::io::{Write};
use curl::easy::Easy;
fn main() {
let mut file = File::create("foo.txt").expect("open file");
let mut easy = Easy::new();
easy.url("checkip.amazonaws.com").unwrap();
easy.write_function(move |data| {
file.write_all(data).expect("write data");
Ok(data.len())
}).unwrap();
easy.perform().unwrap();
}

Related

type `std::result::Result<u8, std::io::Error>` cannot be dereferenced

use std::env;
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
fn main() {
let args = env::args().collect::<Vec<String>>();
let file = File::open(&args[1]).expect("file not found");
let reader = BufReader::new(file);
let mut writer = BufWriter::new(std::io::stdout());
for it in reader.bytes() {
writer.write(&[*it]);
}
}
Why does this give an error?
type `std::result::Result<u8, std::io::Error>` cannot be dereferenced
From the documentation,
fn bytes(self) -> Bytes<Self> where
Self: Sized,
Transforms this Read instance to an Iterator over its bytes.
The returned type implements Iterator where the Item is Result<u8,
io::Error>. The yielded item is Ok if a byte was successfully read and
Err otherwise. EOF is mapped to returning None from this iterator.
Only types implementing std::ops::Deref can be dereferenced.
use std::env;
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
fn main() {
let args = env::args().collect::<Vec<String>>();
let file = File::open(&args[1]).expect("file not found");
let reader = BufReader::new(file);
let mut writer = BufWriter::new(std::io::stdout());
for it in reader.bytes() {
writer.write(&[it.unwrap()]);
}
}

How do I use TcpStream split across 2 threads with async?

I am trying to use the read and write of a tcp stream in different threads. This is what I currently have:
use tokio::prelude::*;
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("localhost:8080").await?;
let (mut read, mut write) = stream.split();
tokio::spawn(async move {
loop {
let mut buf = [0u8; 32];
read.read(&mut buf).await.unwrap();
println!("{}", std::str::from_utf8(&buf));
}
});
Ok(())
}
Im going to use another thread for the write. My problem is that I get the error that 'stream' is dropped while still borrowed.
That happens due to the method signature of Tokio::split, as you can see it takes &mut self, so its part cannot be used in a tokio::spawn future argument due to the 'static bound. So, this is exactly what the error says.
What you are searching is tokio::io::split. Playground
use tokio::prelude::*;
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("localhost:8080").await?;
let (mut read, mut write) = tokio::io::split(stream);
tokio::spawn(async move {
loop {
let mut buf = [0u8; 32];
read.read(&mut buf).await.unwrap();
println!("{:?}", std::str::from_utf8(&buf));
}
});
Ok(())
}
Reading https://users.rust-lang.org/t/why-i-have-to-use-tokio-tcpstream-split-for-concurrent-read-writes/47755/3
And it suggests to use into_split it is more efficient.
tokio::io::split uses a Mutex which into_split apparently does not have (specific to TcpStream)

Take ownership of closure argument for rust future in and_then

I am trying to read all content from a file into a vector using the async rust api:
let mut content : Vec<u8> = vec![];
let f = tokio::fs::File::open("myfilecontent")
.and_then(|mut myfile| {
myfile.read_buf(&mut content)
});
f.await;
But I keep getting this error:
error[E0515]: cannot return value referencing function parameter `myfile`
Which sounds reasonable, because the future returned by the closure must keep a reference to the file, but as this closure is the only user of the file it could take ownership. How can I convince rust to do the right thing?
You can use an async move block like so:
use futures::TryFutureExt;
use tokio::io::AsyncReadExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut content: Vec<u8> = vec![];
let f = tokio::fs::File::open("myfilecontent").and_then(
|mut myfile| async move { myfile.read_buf(&mut content).await },
);
f.await?;
Ok(())
}
or skip and_then and go straight for .await:
use tokio::io::AsyncReadExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut content: Vec<u8> = vec![];
let mut myfile = tokio::fs::File::open("myfilecontent").await?;
myfile.read_buf(&mut content).await?;
Ok(())
}

Is there some way that rust-cargo put DLL file into exe program?

I write a tool, It can get device id through the dll, and copy the id to clipboard.
extern crate clipboard;
use clipboard::ClipboardProvider;
use clipboard::ClipboardContext;
extern crate libloading;
use libloading::{Library, Symbol};
use std::ffi::CStr;
use std::str;
type GetHylinkDeviceId = unsafe fn() -> *const i8;
fn copy_to_clipboard(x3id: String) {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
println!("{:?}", ctx.get_contents());
ctx.set_contents(x3id);
}
fn get_x3id() -> String {
let library_path = "PcInfo.dll";
println!("Loading add() from {:?}", library_path);
let lib = Library::new(library_path).unwrap();
let x3id = unsafe {
let func: Symbol<GetHylinkDeviceId> = lib.get(b"GetHylinkDeviceId").unwrap();
let c_buf: *const i8 = func();
let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
let str_slice: &str = c_str.to_str().unwrap();
let str_buf: String = str_slice.to_owned();
str_buf
};
x3id
}
fn main() {
let x3id: String = get_x3id();
println!("{:?}", x3id);
copy_to_clipboard(x3id)
}
It works well, I use cargo build it, auto generate an executable. I need to put dll file and exe in the same dir when run it.
I want to know if there is anyway to pack dll file into the exe by cargo?
I known how to do, code example:
extern crate clipboard;
use clipboard::ClipboardProvider;
use clipboard::ClipboardContext;
extern crate libloading;
use libloading::{Library, Symbol};
use std::io::prelude::*;
use std::path::Path;
use std::ffi::CStr;
use std::fs::File;
use std::str;
use std::io;
type GetHylinkDeviceId = unsafe fn() -> *const i8;
const LIBRARY_PATH: &'static str = "PcInfo.dll";
const HYLINK_DLL: &'static [u8] = include_bytes!("PcInfo.dll");
fn generate_hylink_dll(filename: &str, buf: &[u8]) -> io::Result<()> {
let mut f = try!(File::create(filename));
try!(f.write(&buf));
Ok(())
}
fn copy_to_clipboard(x3id: String) {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
println!("{:?}", ctx.get_contents());
ctx.set_contents(x3id).unwrap();
}
fn get_x3id() -> String {
if !Path::new(LIBRARY_PATH).exists() {
match generate_hylink_dll(LIBRARY_PATH, HYLINK_DLL) {
Ok(s) => println!("Generate hylink dll file success {:?}", s),
Err(r) => println!("Generate hylink dll file failed {:?}", r),
}
}
// load lib
let lib = Library::new(LIBRARY_PATH).unwrap();
println!("{:?}", lib);
// call
let x3id = unsafe {
let func: Symbol<GetHylinkDeviceId> = lib.get(b"GetHylinkDeviceId").unwrap();
let c_buf: *const i8 = func();
let c_str: &CStr = CStr::from_ptr(c_buf);
let str_slice: &str = c_str.to_str().unwrap();
let str_buf: String = str_slice.to_owned();
str_buf
};
x3id
}
fn main() {
let x3id: String = get_x3id();
println!("{:?}", x3id);
copy_to_clipboard(x3id)
}

Cannot use moved BufReader after for loop with bufreader.lines()

I'm trying to read some lines from a file, skipping the first few and printing the rest, but I keep getting errors about used value after move:
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read};
use std::path::Path;
fn skip_and_print_file(skip: &usize, path: &Path) {
let mut skip: usize = *skip;
if let Ok(file) = File::open(path) {
let mut buffer = BufReader::new(file);
for (index, line) in buffer.lines().enumerate() {
if index >= skip {
break;
}
}
print_to_stdout(&mut buffer);
}
}
fn print_to_stdout(mut input: &mut Read) {
let mut stdout = io::stdout();
io::copy(&mut input, &mut stdout);
}
fn main() {}
This is the error I'm getting:
error[E0382]: use of moved value: `buffer`
--> src/main.rs:15:30
|
10 | for (index, line) in buffer.lines().enumerate() {
| ------ value moved here
...
15 | print_to_stdout(&mut buffer);
| ^^^^^^ value used here after move
|
= note: move occurs because `buffer` has type `std::io::BufReader<std::fs::File>`, which does not implement the `Copy` trait
In order to avoid the move, use the Read::by_ref() method. That way, you only borrow the BufReader:
for (index, line) in buffer.by_ref().lines().enumerate() { ... }
// ^^^^^^^^^
// you can still use `buffer` here
As Lukas Kalbertodt says, use Read::by_ref.
This prevents lines from consuming the BufReader and instead it consumes a &mut BufReader. The same logic applies to iterators.
Instead of implementing skip yourself, you can use Iterator::take. This has to be driven to completion with a for loop though:
use std::{
fs::File,
io::{self, BufRead, BufReader, Read},
path::Path,
};
fn skip_and_print_file(skip: usize, path: impl AsRef<Path>) {
if let Ok(file) = File::open(path) {
let mut buffer = BufReader::new(file);
for _ in buffer.by_ref().lines().take(skip) {}
// Or: buffer.by_ref().lines().take(skip).for_each(drop);
print_to_stdout(buffer);
}
}
fn print_to_stdout(mut input: impl Read) {
let mut stdout = io::stdout();
io::copy(&mut input, &mut stdout).expect("Unable to copy");
}
fn main() {
skip_and_print_file(2, "/etc/hosts");
}
Note that there's no reason to make the skip variable mutable or even to pass in a reference. You can also take in AsRef<Path> and then callers of skip_and_print_file can just pass in a string literal.

Resources