Clashing types, crossterm::Result and core::Result error[E0107]: - rust

I know the issue is that I have two Result types from different libraries but can't find how to fix it.
[dependencies]
crossterm = "0.23"
time = "0.3.9"
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.11", features = ["blocking", "json"] }
use time::Instant;
use std::collections::HashMap;
use crossterm::{
event::{self, Event, KeyCode, KeyEvent},
Result,
};
pub fn read_char() -> Result<char> {
loop {
if let Event::Key(KeyEvent {
code: KeyCode::Char(c),
..
}) = event::read()?
{
return Ok(c);
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let instant = Instant::now();
let response = reqwest::blocking::get("https://httpbin.org/ip")?
.json::<HashMap<String, String>>()?;
let duration = instant.elapsed();
println!("ns = {:?}, response: {:#?}, ", duration.whole_nanoseconds(), response);
// Any key to continue
println!("Press any key to continue:");
println!("{:?}", read_char());
Ok(())
}
Gives the error:
error[E0107]: this type alias takes 1 generic argument but 2 generic arguments were supplied
--> src\main.rs:20:14
|
20 | fn main() -> Result<(), Box<dyn std::error::Error>> {
| ^^^^^^ -------------------------- help: remove this generic argument
| |
| expected 1 generic argument
How do I fix this? I have searched but am likely looking for incorrect terms e.g. namespace alias and core::Result error[E0107] is not really helping.
I have tried this without success:
fn main() -> core::Result<(), Box<dyn std::error::Error>> {

You have crossterm ::Result in scope, so you would have to disambiguate the result you want to return, otherwise it just thinks you want to return the crossterm type:
fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
...
Ok(())
}

Related

how to return current working directory from function?

has experience with high level programming languages. I read the Rust book and now trying to survive and understand how the "things" in Rust works. I would love that someone explain what the heck is - Ok(()) and how to deal with it? My goal is to return result from function in to the variable where the output:
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/rcp ./file/ aba`
Ok(
"/home/tomand/rcp",
)
Here is the full code:
use std::fs;
use std::env;
use serde_json;
use regex::Regex;
use std::path::Path;
fn determinate_file_size(file: &str) -> u64 {
fs::metadata(file).unwrap().len()
}
fn determinate_is_it_file_or_dirctory(arg: &str) -> &str {
let file = "File";
let dir = "Directory";
let re = Regex::new(r"/").unwrap();
if re.is_match(arg) {
return dir;
}
return file;
}
fn collect_user_arguments() -> Vec<String> {
env::args().collect()
}
fn check_if_arguments_count_valid(args: &Vec<String>) -> bool {
if args.len() == 3 {
return true
}
help();
return false
}
fn get_current_working_dir() -> Result<T> {
env::current_dir()
}
fn help() {
println!("Examples:");
println!("rcp [srcfile] [destfile]");
println!("rcp [srcdir]/[srcfile] [destdir]/[destfile]");
}
fn main() {
let WORKING_DIR = get_current_working_dir();
let args: Vec<String> = collect_user_arguments();
if check_if_arguments_count_valid(&args) {
let arg1 = &args[1];
let arg2 = &args[2];
println!("{:#?}", determinate_is_it_file_or_dirctory(&arg1));
}
}
Seems the compiler tried to give me some inspiration but eventually we miscommunicate in the end:
error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
--> src/main.rs:42:33
|
42 | fn get_current_working_dir() -> Result<T> {
| ^^^^^^ - supplied 1 generic argument
| |
| expected 2 generic arguments
EDIT:
I went with this approach:
fn get_current_working_dir() -> String {
let res = env::current_dir();
match res {
Ok(path) => path.into_os_string().into_string().unwrap(),
Err(_) => "FAILED".to_string()
}
}
It seems more practice is required to understand the Result type and how to manage it.
std::env::current_dir returns a std::io::Result<Pathbuf>, so you need to use that type in your wrapper method:
fn get_current_working_dir() -> std::io::Result<PathBuf> {
env::current_dir()
}
Playground
Other nitpick:
const is not a type so let WORKING_DIR: const = get_current_working_dir(); is wrong, just let WORKING_DIR = get_current_working_dir(); is enough.

how to generalize from `File` to `Read`?

I have some working code that reads a file, but I need to generalize it to pull data from additional sources other than simple disk files.
Is Read the correct generalization I should work with in order to replace File?
If so, how can I fix example2 in the following sample code? As is, it fails with the compile error dyn async_std::io::Read cannot be unpinned at the commented line. If not, what type should I return instead from get_read and are there any corresponding changes required in example2?
//! [dependencies]
//! tokio = { version = "1.0.1", features = ["full"] }
//! async-std = "1.8.0"
//! anyhow = "1.0.32"
use async_std::io::prelude::*;
use async_std::fs::File;
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
example1().await?;
example2().await?;
Ok(())
}
// Example of consuming `File` ... works great!
async fn example1() -> Result<()> {
let mut file = get_file().await?;
let mut contents = String::new();
let _ = file.read_to_string(&mut contents).await?;
println!("read {} characters", contents.len());
Ok(())
}
// Example of consuming `Read` ... does not compile?
async fn example2() -> Result<()> {
let mut read = get_read().await?;
let mut contents = String::new();
// ERROR: `dyn async_std::io::Read` cannot be unpinned
let _ = read.read_to_string(&mut contents).await?;
println!("read {} characters", contents.len());
Ok(())
}
async fn get_read() -> Result<Box<dyn Read>> {
let file = get_file().await?;
Ok(Box::new(file))
}
async fn get_file() -> Result<File> {
let file = File::open("/etc/hosts").await?;
Ok(file)
}
You need to pin:
async fn get_read() -> Result<Pin<Box<dyn Read>>> {
let file = get_file().await?;
Ok(Box::pin(file))
}
Box<File> (without Pin) works because File implements Unpin. Box<dyn Read + Unpin> would work too.

How do I use PickleDB with Rocket/Juniper Context?

I'm trying to write a Rocket / Juniper / Rust based GraphQL Server using PickleDB - an in-memory key/value store.
The pickle db is created / loaded at the start and given to rocket to manage:
fn rocket() -> Rocket {
let pickle_path = var_os(String::from("PICKLE_PATH")).unwrap_or(OsString::from("pickle.db"));
let pickle_db_dump_policy = PickleDbDumpPolicy::PeriodicDump(Duration::from_secs(120));
let pickle_serialization_method = SerializationMethod::Bin;
let pickle_db: PickleDb = match Path::new(&pickle_path).exists() {
false => PickleDb::new(pickle_path, pickle_db_dump_policy, pickle_serialization_method),
true => PickleDb::load(pickle_path, pickle_db_dump_policy, pickle_serialization_method).unwrap(),
};
rocket::ignite()
.manage(Schema::new(Query, Mutation))
.manage(pickle_db)
.mount(
"/",
routes![graphiql, get_graphql_handler, post_graphql_handler],
)
}
And I want to retrieve the PickleDb instance from the Rocket State in my Guard:
pub struct Context {
pickle_db: PickleDb,
}
impl juniper::Context for Context {}
impl<'a, 'r> FromRequest<'a, 'r> for Context {
type Error = ();
fn from_request(_request: &'a Request<'r>) -> request::Outcome<Context, ()> {
let pickle_db = _request.guard::<State<PickleDb>>()?.inner();
Outcome::Success(Context { pickle_db })
}
}
This does not work because the State only gives me a reference:
26 | Outcome::Success(Context { pickle_db })
| ^^^^^^^^^ expected struct `pickledb::pickledb::PickleDb`, found `&pickledb::pickledb::PickleDb`
When I change my Context struct to contain a reference I get lifetime issues which I'm not yet familiar with:
15 | pickle_db: &PickleDb,
| ^ expected named lifetime parameter
I tried using 'static which does make rust quite unhappy and I tried to use the request lifetime (?) 'r of the FromRequest, but that does not really work either...
How do I get this to work? As I'm quite new in rust, is this the right way to do things?
I finally have a solution, although the need for unsafe indicates it is sub-optimal :)
#![allow(unsafe_code)]
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::env;
use std::path::Path;
use std::time::Duration;
pub static mut PICKLE_DB: Option<PickleDb> = None;
pub fn cache_init() {
let pickle_path = env::var(String::from("PICKLE_PATH")).unwrap_or(String::from("pickle.db"));
let pickle_db_dump_policy = PickleDbDumpPolicy::PeriodicDump(Duration::from_secs(120));
let pickle_serialization_method = SerializationMethod::Json;
let pickle_db = match Path::new(&pickle_path).exists() {
false => PickleDb::new(
pickle_path,
pickle_db_dump_policy,
pickle_serialization_method,
),
true => PickleDb::load(
pickle_path,
pickle_db_dump_policy,
pickle_serialization_method,
)
.unwrap(),
};
unsafe {
PICKLE_DB = Some(pickle_db);
}
}
pub fn cache_get<V>(key: &str) -> Option<V>
where
V: DeserializeOwned + std::fmt::Debug,
{
unsafe {
let pickle_db = PICKLE_DB
.as_ref()
.expect("cache uninitialized - call cache_init()");
pickle_db.get::<V>(key)
}
}
pub fn cache_set<V>(key: &str, value: &V) -> Result<(), pickledb::error::Error>
where
V: Serialize,
{
unsafe {
let pickle_db = PICKLE_DB
.as_mut()
.expect("cache uninitialized - call cache_init()");
pickle_db.set::<V>(key, value)?;
Ok(())
}
}
This can be simply imported and used as expected, but I think I'll run into issues when the load gets to high...

How to write an asynchronous recursive walkdir function with an asynchronous callback

I'm trying to write an async function that will traverse the filesystem tree, recursively, and calls an asynchronous callback for each file found.
This is for a learning effort, I have no real use case.
Here is what I have so far:
use async_std::{
fs::{self, *},
path::*,
prelude::*,
}; // 1.5.0, features = ["unstable"]
use futures::{
executor::block_on,
future::{BoxFuture, FutureExt},
}; // 0.3.4
use std::{marker::Sync, pin::Pin};
fn main() {
fn walkdir<F>(path: String, cb: &'static F) -> BoxFuture<'static, ()>
where
F: Fn(&DirEntry) -> BoxFuture<()> + Sync + Send,
{
async move {
let mut entries = fs::read_dir(&path).await.unwrap();
while let Some(path) = entries.next().await {
let entry = path.unwrap();
let path = entry.path().to_str().unwrap().to_string();
if entry.path().is_file().await {
cb(&entry).await
} else {
walkdir(path, cb).await
}
}
}
.boxed()
}
let foo = async {
walkdir(".".to_string(), &|entry: &DirEntry| async {
async_std::println!(">> {}\n", &entry.path().to_str().unwrap()).await
})
.await
};
block_on(foo);
}
I get this far by some sort of trial and error, but now I'm stuck on async closure callback with this error
warning: unused import: `path::*`
--> src/main.rs:3:5
|
3 | path::*,
| ^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: unused import: `pin::Pin`
--> src/main.rs:10:25
|
10 | use std::{marker::Sync, pin::Pin};
| ^^^^^^^^
error[E0308]: mismatched types
--> src/main.rs:33:54
|
33 | walkdir(".".to_string(), &|entry: &DirEntry| async {
| ______________________________________________________^
34 | | async_std::println!(">> {}\n", &entry.path().to_str().unwrap()).await
35 | | })
| |_________^ expected struct `std::pin::Pin`, found opaque type
|
= note: expected struct `std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = ()> + std::marker::Send>>`
found opaque type `impl core::future::future::Future`
use async_std::{
fs::{self, *},
path::*,
prelude::*,
}; // 1.5.0
use futures::{future::{Future, FutureExt, LocalBoxFuture}, executor}; // 0.3.4
fn main() {
async fn walkdir<R>(path: impl AsRef<Path>, mut cb: impl FnMut(DirEntry) -> R)
where
R: Future<Output = ()>,
{
fn walkdir_inner<'a, R>(path: &'a Path, cb: &'a mut dyn FnMut(DirEntry) -> R) -> LocalBoxFuture<'a, ()>
where
R: Future<Output = ()>,
{
async move {
let mut entries = fs::read_dir(path).await.unwrap();
while let Some(path) = entries.next().await {
let entry = path.unwrap();
let path = entry.path();
if path.is_file().await {
cb(entry).await
} else {
walkdir_inner(&path, cb).await
}
}
}.boxed_local()
}
walkdir_inner(path.as_ref(), &mut cb).await
}
executor::block_on({
walkdir(".", |entry| async move {
async_std::println!(">> {}", entry.path().display()).await
})
});
}
Notable changes:
Take in AsRef<Path> instead of a String and a generic closure instead of a trait object reference
Change the closure type to be FnMut as it's more permissive
The closure returns any type that is a future.
There's an inner implementation function that hides the ugly API required for recursive async functions.
The callback takes the DirEntry by value instead of by reference.
See also:
How to asynchronously explore a directory and its sub-directories?
How to using async fn callback in rust

How do I convert an async / standard library future to futures 0.1?

I want to use the async function to parse the inbound stream progressively, but actix-web requires impl Future<Item = HttpResponse, Error = Error> as the return value.
How can I convert the future returned by async function to what actix-web requires?
I'm using Rust 1.39 nightly and actix-web 1.0.7.
http_srv.rs :
use futures::compat::Stream01CompatExt;
use futures::future::{FutureExt, TryFutureExt};
use futures::stream::TryStreamExt;
use futures01::future::Future;
use futures01::stream::Stream;
use futures01::sync::mpsc; // for `try_next`
use actix_web::*;
use bytes::Bytes;
use futures_timer::Delay;
use std::time::Duration;
fn inbound(
req: HttpRequest,
stream: web::Payload,
) -> impl Future<Item = HttpResponse, Error = Error> {
let fut = async_inbound(&req, &stream);
fut.unit_error().boxed_local().compat() // <--- compliation error here.
}
async fn async_inbound(req: &HttpRequest, stream: &web::Payload) -> HttpResponse {
let mut compat_stream = stream.compat();
loop {
let result = compat_stream.try_next().await;
if let Err(e) = result {
warn!("Failed to read stream from {} : {}", req.path(), e);
break;
}
if let Ok(option) = result {
match option {
None => {
info!("Request ends");
break;
}
Some(data) => {
println!("{:?}", data);
}
}
}
}
HttpResponse::Ok().content_type("text/html").body("RESP")
}
pub fn start(port: u16) {
info!("Starting HTTP server listening at port {} ...", port);
let _ = HttpServer::new(|| {
App::new()
.wrap(middleware::DefaultHeaders::new().header(http::header::CACHE_CONTROL, "no-cache"))
.wrap(middleware::Logger::default())
.service(web::resource("/").route(web::put().to_async(inbound)))
})
.bind(format!("0.0.0.0:{}", port))
.expect(&format!("Unable to bind on port {}", port))
.run()
.expect("Failed to start HTTP server");
}
Cargo.toml:
dependencies]
log = "0.4.8"
env_logger = "0.6.2"
chrono = "0.4.8"
actix = "0.8.3"
bytes = "0.4.12"
actix-utils = "0.4.5"
futures-timer = "0.3"
futures01 = { package = "futures", version = "0.1", optional = false }
[dependencies.actix-web]
version = "1.0.7"
features = ["ssl"]
# https://rust-lang-nursery.github.io/futures-rs/blog/2019/04/18/compatibility-layer.html
# Rust’s futures ecosystem is currently split in two:
# On the one hand we have the vibrant ecosystem built around futures#0.1 with its many libraries working on stable Rust
# and on the other hand there’s std::future ecosystem with support for the ergonomic and powerful async/await language feature.
# To bridge the gap between these two worlds we have introduced a compatibility layer as part of the futures#0.3 extension to std::future.
[dependencies.futures-preview]
version = "0.3.0-alpha.18"
default-features = false
features = ["compat", "async-await", "nightly"]
Compilation Error:
error[E0271]: type mismatch resolving `<std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<actix_http::response::Response, ()>>>> as core::future::future::Future>::Output == std::result::Result<_, actix_http::error::Error>`
--> src/http_server.rs:39:55
|
39 | fn inbound(req: HttpRequest, stream: web::Payload) -> impl Future<Item=HttpResponse, Error=Error> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `actix_http::error::Error`
|
= note: expected type `std::result::Result<actix_http::response::Response, ()>`
found type `std::result::Result<_, actix_http::error::Error>`
= note: required because of the requirements on the impl of `futures_core::future::TryFuture` for `std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<actix_http::response::Response, ()>>>>`
= note: the return type of a function must have a statically known size
std::future -> future#0.1 conversion steps:
The future needs to be TryFuture (Output = Result<T, E>)
The future needs to be Unpin (you can use boxed combinator)
Finally, you can call the compat combinator
Your inbound function:
fn inbound(
req: HttpRequest,
stream: web::Payload,
) -> impl Future<Item = HttpResponse, Error = Error> {
let fut = async_inbound(&req, &stream);
fut.unit_error().boxed_local().compat()
}
The inbound function signature is fine, but the conversion isn't.
The async_inbound function isn't TryFuture (because of -> HttpResponse). You're trying to convert it with the unit_error combinator, but the result is Result<HttpResponse, ()> and you want Result<HttpResponse, Error>. Fixed inbound function:
fn inbound(
req: HttpRequest,
stream: web::Payload,
) -> impl Future<Item = HttpResponse, Error = Error> {
let fut = async_inbound(req, stream);
fut.boxed_local().compat()
}
Your async_inbound function:
async fn async_inbound(req: &HttpRequest, stream: &web::Payload) -> HttpResponse {
// ...
}
The first issue here is to replace -> HttpResponse with -> Result<HttpResponse>. Another problem is that you're passing reg and stream by reference. Move them as there's no need to take a reference and you'll need 'static. Fixed async_inbound function:
async fn async_inbound(req: HttpRequest, stream: web::Payload) -> Result<HttpResponse> {
let mut compat_stream = stream.compat();
while let Some(data) = compat_stream.try_next().await? {
println!("{:?}", data);
}
Ok(HttpResponse::Ok().content_type("text/html").body("RESP"))
}

Resources