I have two closures that capture the same Vec and I don't know how to write this in idiomatic Rust:
use std::error;
fn get_token -> Box<Vec<u8>>() {...}
fn do_stuff(file: &str) -> std::io::Result<i32> {...}
fn do_other_stuff(a: &str, a: &str) -> std::io::Result<i32> {...}
enum MyError {
IoError { token: Vec<u8>, reason: String ),
}
fn consumer() -> Result<MyError, ()> {
let token = get_token();
try!(do_stuff("a")
.map_err(|e| MyError::IoError { token: token, reason: "foo".to_str() }));
try!(do_other_stuff("b", "c")
.map_err(|e| MyError::IoError { token: token, reason: "bar".to_str() }));
}
I could replace the map_err calls with match expressions but I really am stumped by this: how do I pass a Vec to multiple closures?
First of all: Please make sure to provide an MCVE in the future, it's not fun to have to fix syntax errors before being able to reproduce your problem: http://is.gd/tXr7WK
Rust does not know that the only way the second closure can run, is if the first closure did not run and will never run. You can either wait for the let/else RFC to be accepted, implemented and stabilized, or you can create your error in steps, first create an inner closure that does all the operations for that one error kind without using up the token, then run the closure, then map the error to your custom error type.
|| -> _ {
try!(do_stuff("a").map_err(|e| ("foo".to_owned(), e)));
try!(do_other_stuff("b","c").map_err(|e| ("bar".to_owned(), e)));
Ok(())
} ().map_err(|(reason, e)| MyError::IoError{ token: token, reason: reason })
There's something weird going on where the closure requires us to specify that it returns something with -> _, but I'm not sure what it is.
Much more straightforward is to just not use try! or closures:
if let Err(e) = do_stuff("a") {
return Err(MyError::IoError{token: token, reason: "foo".to_owned()});
}
if let Err(e) = do_other_stuff("b", "c") {
return Err(MyError::IoError{token: token, reason: "bar".to_owned()});
}
This lets Rust perform straightforward analysis like you want it to, and is much more readable than dancing through hoops.
You can use and_then() combinator to avoid additional closure:
try!(do_stuff("a").map_err(|_| "foo" )
.and_then(|_|
do_other_stuff("b","c").map_err(|_| "bar")
)
.map_err(|e| MyError::IoError{token:token,reason:e.into()})
);
Related
What I want to do is really what the title says. I would like to know how I can receive data per post in hyper, for example, suppose I execute the following command (with a server in hyper running on port :8000):
curl -X POST -F "field=#/path/to/file.txt" -F "tool=curl" -F "other-file=#/path/to/other.jpg" http://localhost:8000
Now, I'm going to take parf of the code on the main page of hyper as an example:
use std::{convert::Infallible, net::SocketAddr};
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};
async fn handle(_: Request<Body>) -> Result<Response<Body>, Infallible> {
Ok(Response::new("Hello, World!".into()))
}
#[tokio::main]
async fn main() {
let addr = SocketAddr::from(([127, 0, 0, 1], 8000));
let make_svc = make_service_fn(|_conn| async {
Ok::<_, Infallible>(service_fn(handle))
});
let server = Server::bind(&addr).serve(make_svc);
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}
So, now, with this basic code, how can I receive the data per post that my curl command above would send? How do I adapt my code to read the data? I've tried to search the internet, but what I found was that hyper doesn't actually split the request body depending on the HTTP method, it's all part of the same body. But I haven't been able to find a way to process data like the above with code like mine. Thanks in advance.
Edit
I tried the exact code that they left me in the answer. That is, this code:
async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
let mut files = multipart::server::Multipart::from(req);
.....
}
But I get this error:
expected struct multipart::server::Multipart, found struct
hyper::Request
How can I solve that?
It is a single body, but the data is encoded in a way that contains the multiple files.
This is called multipart, and in order to parse the body correctly you need a multipart library such as https://crates.io/crates/multipart
To hyper integration you need to add the feature flag hyper in Cargo.toml
multipart = { version = "*", features = ["hyper"] }
Then
async fn handle(mut files: multipart::server::Multipart) -> Result<Response<Body>, Infallible> {
files.foreach_entry(|field| {
// contains name, filename, type ..
println!("Info: {:?}",field.headers);
// contains data
let mut bytes:Vec<u8> = Vec::new();
field.data.read_to_end(&mut bytes);
});
Ok(Response::new("Received the files!".into()))
}
You can also use it like this
async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
let mut files = multipart::server::Multipart::from(req);
.....
}
I am using FSharp.Data.GraphQL for implementing GraphQL server. The documentation is not very clear about error handling. In the following mutation resolver, I wish to return errors if user provides invalid values for email and password:
let login =
Define.AsyncField(
name = "login",
typedef = Nullable Output.Token,
description = "Login using email and password",
args = [
Define.Input("email", String)
Define.Input("password", String)
],
resolve =
fun ctx _ ->
// ... some more code related to db and validation
let customErr: exn = Error.InvalidUserPassword
// This statement has not effect
ctx.AddError customErr
// Should I use raise to explicitly throw exception
// raise customErr
Async.result None
)
Looking into the source code, I found out AddError method on ResolveFieldContext. But it seems to produce no effect on the final result of the mutation. The output is always without any error:
{
"documentId": 1234,
"data": {
"login": null
},
// The errors array is not available
"errors": []
}
Should I raise the exception to add the error handling? And, if that is the case, how can I go about adding multiple error codes as part of single query or mutation since I can raise only one exception?
I'm trying to import a node module in my fable code. Being new to fable I did expect so problems and understanding the import flow seems to be one of those. I have the below code which compiles fine but fails run time with Cannot read property 'request' of undefined on the line of the printfn statement
module Session =
let inline f (f: 'a->'b->'c->'d) = Func<_,_,_,_> f
[<Import("default","request")>]
type Http =
abstract request : string -> System.Func<obj,obj,obj,unit> -> unit
let http : Http = failwith "js only"
let start () =
http.request "http://dr.dk" (ff (fun error response body ->
printfn "%A" body
))
do
start()
I was able to get your example working in the Fable REPL:
open System
open Fable
open Fable.Core
open Fable.Core.JS
open Fable.Core.JsInterop
type RequestCallback = Func<obj, obj, obj, unit>
type Request = Func<string, RequestCallback, unit>
[<ImportDefault("request")>]
let request : Request = jsNative
let start () =
request.Invoke("http://dr.dk", (fun error response body ->
console.log("error", error)
console.log("response", response)
console.log("body", body)
))
start ()
And here is the JavaScript that it generated:
import request from "request";
import { some } from "fable-library/Option.js";
export function start() {
request("http://dr.dk", (error, response, body) => {
console.log(some("error"), error);
console.log(some("response"), response);
console.log(some("body"), body);
});
}
start();
Note that there are bindings for many modules already. For this particular task, I would suggest using Fable.Fetch. If you want a library that works in the browser and .NET, try Fable.SimpleHttp.
I'm using Play Framework 2.2 and ReactiveMongo. I'm iterating trough all received entries from ReactiveMongo, and getting some property from single entry. Sometimes it throws Exception of inexistent property, how should I catch it, for now using simple "recover" doesn't work.
val cursor:Cursor[JsObject] = // QUERY FOR DATA
val processingData = cursor.enumerate().apply(Iteratee.foreach { doc =>
(doc \ "property")
}
processingData.map { data =>
Logger.info(s"$data")
None
}.recover {
case e =>
Logger.error(s"Error during parsing $e")
None
}
Iteratee.foreach always return Unit type, so value processingData will not contain data and enumerator apply some Iteratee only attach iteratee to emumerator, but don't run it. I think, this must solve your problem:
val cursor:Cursor[JsObject] = // QUERY FOR DATA
val getData = Enumeratee.mapM[JsObject]{doc =>
Future(doc \ "property") //use future to catch exception here
}
val processingData: Future[scala.List[JsObject]] = cursor.enumerate() &> getData .run Iteratee.getChunks
I am trying to print an enum (or structure) using fmt::Display. Though the code compiles and gets to the display method, it doesn't print the value.
pub enum TestEnum<'a> {
Foo(&'a str),
Bar(f32)
}
impl<'b> fmt::Display for TestEnum <'b> {
fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
println!("Got this far");
match self{
&TestEnum::Foo(x) => write!(f,"{}",x),
&TestEnum::Bar(x) => write!(f,"{}",x),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_print() {
let cell = TestEnum::Str("foo");
println!("Printing");
println!("{}",cell); // No output here
}
}
I tried using {:?} and {} but to no avail.
This happens because Rust test program hides stdout of successful tests. You can disable this behavior passing --nocapture option to test binary or to cargo test command this way:
cargo test -- --nocapture
PS: your code is broken/incomplete
The test runner seems to divert the standard output; you should consider using assert!, assert_eq! or other panicky ways to test your assertions rather than printing in tests.
Besides, your code fails to compile due to mismatching names. I got it working as expected from main:
use std::fmt;
pub enum TestEnum<'a> {
Foo(&'a str),
Bar(f32)
}
impl<'b> fmt::Display for TestEnum <'b> {
fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
match self {
&TestEnum::Foo(x) => write!(f, "{}", x),
&TestEnum::Bar(x) => write!(f, "{}", x),
}
}
}
fn main() {
let cell = TestEnum::Foo("foo");
println!("Printing");
println!("{}", cell);
}
Test output is redirected to a buffer when the test succeeds as to not mangle up with the test "FAILED" or "ok" messages.
If you just want to test something while developing your test, you can always add a panic!() at the end of your test to make sure it keeps failing and outputting all logging. Or as #AndreaP notes in his answer, you can use cargo test -- --nocapture to display the standard output of all tests.
Usually a test should not write to stdout, but instead write to a buffer and check whether that buffer contains what it should:
let cell = TestEnum::Foo("foo");
let mut buf = Vec::new();
let _ = write!(buf, "{}\n", cell);
assert_eq!(&buf, b"foo\n");
If you truly want to output something, you need to write directly to stdout.
let _ = write!(io::stdout(), "{}\n", cell);
but this will mix with the test's output:
test tests::blub ... foo
ok
PlayPen