I've got the following code:
use actix_service::Service;
use actix_web::{web, App, HttpServer, Responder};
use actix_router::{Path, Url};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::error::ResponseError;
use actix_web::{http, http::StatusCode, Error, HttpRequest, HttpResponse};
async fn greet(req: HttpRequest) -> impl Responder {
let name = req.match_info().get("name").unwrap_or("World");
format!("Hello {}!", &name)
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let app = App::new()
.wrap_fn(|req, srv| {
let passed: bool;
// change to false to simulate a failed check
let check = true;
if *&req.path().contains("/item/") {
passed = check;
} else {
passed = true;
}
let fresh_result = match passed {
true => {
let fut = srv.call(req);
Box::pin(async {
let result = fut.await?;
Ok(result)
})
}
false => Box::pin(async {
let result = req.into_response(
HttpResponse::Found()
.header(http::header::LOCATION, "/login")
.finish()
.into_body(),
);
Ok(result)
}),
};
async {
let last_outcome = fresh_result.await?;
Ok(last_outcome)
}
})
.route("/", web::get().to(greet));
return app;
})
.bind("127.0.0.1:8000")?
.run()
.await
}
However, I get the following error:
110 | let fresh_result = match passed {
| ________________________________________-
111 | | true => {
112 | | let fut = srv.call(req);
113 | | Box::pin(
| _|_____________________________-
114 | | | async {
115 | | | let result = fut.await?;
116 | | | Ok(result)
117 | | | }
118 | | | )
| |_|_____________________________- this is found to be of type `std::pin::Pin<std::boxed::Box<impl core::future::future::Future>>`
... |
121 | / | Box::pin(
122 | | | async {
123 | | | let result = req.into_response(
124 | | | HttpResponse::Found()
... | |
129 | | | }
130 | | | )
| |_|_____________________________^ expected generator, found a different generator
131 | | }
132 | | };
| |_____________________- `match` arms have incompatible types
|
::: /Users/maxwellflitton/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/future/mod.rs:55:43
|
55 | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| ------------------------------- the found opaque type
|
= note: expected type `std::pin::Pin<std::boxed::Box<impl core::future::future::Future>>` (generator)
found struct `std::pin::Pin<std::boxed::Box<impl core::future::future::Future>>` (generator)
I am completely stuck on this. I don't know how to ensure it's a type. If there is no match statement and there is just one async block then it all runs fine. This is for middleware in an Actix-web server. I am trying to redirect the viewer if credentials are not working.
You use Box::pin to create the boxed futures,
but Rust still thinks you want the impl Future<...> version (meaning the future is boxed to the heap, but doesn't use dynamic dispatch).
This is why the type in the error is Pin<Box<impl Future<...>>>, and because any two impl Future<...>s are of different types, you get the expected/found error.
You need to tell Rust you are interested in dynamic dispatch (because you have two different futures that can be stored in the Box, and which one really is stored there can only be known at runtime), for example by explicitly specifying the return type like this:
use std::pin::Pin;
use std::future::Future;
let fresh_result: Pin<Box<dyn Future<Output=_>>> = match passed {
// ...
}
Now you will get a new error about cannot infer type for type parameter E which can be resolved by specifying the Output of the future as well,
so the new line should be:
let fresh_result: Pin<Box<dyn Future<Output=Result<ServiceResponse, Error>>>> = match passed {
// ...
}
which will compile successfully!
Related
I already have GSI set to author as partition key and status as a sort key and use them to query the data I need. However, I can't figure out to sort my return data by chronological order.
DynamoDb table
-----------------------------------------------
| id | post | author | status | createdAt |
-----------------------------------------------
| 1 | post1 | author1 | publish | 2019-12-10 |
-----------------------------------------------
| 2 | post2 | author2 | draft | 2019-12-11 |
-----------------------------------------------
| 3 | post3 | author1 | publish | 2019-12-12 |
-----------------------------------------------
and the query
var params = {
TableName : "TABLENAME",
IndexName: "gsi-authorStatus",
KeyConditionExpression: "author = :author AND status = :status",
ExpressionAttributeValues: {
":author": JSON.stringify(event.bodyJSON.author),
":status": JSON.stringify(event.bodyJSON.status)
}
};
dynamo.query(params, function (err, data) {
if (err) {
console.error('Error with ', err);
context.fail(err);
} else {
context.succeed(data);
}
});
My query give me the data where author and status are matching but it give me a data in a random order. It is possible to use createdAt to make the return data order by latest?
I'm writing an application that has a function for tipping points. I want to make a conditional update which is only executed if the resulting value of a user's wallet would be 0 or higher. If the value is negative the update should not happen.
The function works without the conditional expression but when I add it, it breaks.
ConditionExpression: 'teleUser.wallet.points -:a > -1',
In the above line :a is a passed in integer. I'll post the context below, but the above line is where my problem occurs.
The error returned is ValidationException: Invalid ConditionExpression: Syntax error; token: "-", near: "points -:a".
Full function for context:
function removeFromWallet(msg, amount) {
console.log("remove");
let params = {
TableName: tableName,
Key: {"id": msg.from.id},
UpdateExpression: 'set teleUser.wallet.points = teleUser.wallet.points -:a',
ExpressionAttributeValues:{
":a": parseInt(amount)
},
ConditionExpression: 'teleUser.wallet.points -:a > -1',
ReturnValues:"UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) {
console.log(err);
} else {
const { Items } = data;
console.log(data.Attributes.teleUser.wallet.points);
addToWallet(msg, amount);
}
});
}
You can't perform calculations in ConditionExpression (see grammar for ConditionExpression)
condition-expression ::=
operand comparator operand
| operand BETWEEN operand AND operand
| operand IN ( operand (',' operand (, ...) ))
| function
| condition AND condition
| condition OR condition
| NOT condition
| ( condition )
comparator ::=
=
| <>
| <
| <=
| >
| >=
function ::=
attribute_exists (path)
| attribute_not_exists (path)
| attribute_type (path, type)
| begins_with (path, substr)
| contains (path, operand)
| size (path)
You can perform calculations in ExpressionAttributeValues, but in this particular case you'll probably have to use teleUser.wallet.points >= :a since column values aren't available in ExpressionAttributeValues
I made a simple macro that returns the taken parameter.
macro_rules! n {
($n:expr) => {{
let val: usize = $n;
match val {
0 => 0,
_ => n!(val - 1),
}
}};
}
When I compile this code with the option external-macro-backtrace, it raises an error:
error: recursion limit reached while expanding the macro `n`
--> src/main.rs:15:18
|
10 | macro_rules! n {
| _-
| |_|
| |
11 | | ($n:expr) => {{
12 | | let val: usize = $n;
13 | | match val {
14 | | 0 => 0,
15 | | _ => n!(val - 1),
| | ^^^^^^^^^^^
| | |
| | in this macro invocation
16 | | }
17 | | }};
18 | | }
| | -
| |_|
| |_in this expansion of `n!`
| in this expansion of `n!`
...
31 | | n!(1);
| | ------ in this macro invocation
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
I changed the recursion_limit to 128 and higher, but the compiler error message just increase as well. Even when I call n!(0) it makes the same error. I think it is infinite recursion, but I can't find the reason.
Well, it really is an infinite recursion. Check what your macro invocation n!(0) will be expanded into:
{
let val: usize = 0;
match val {
0 => 0,
_ => n!(0 - 1),
}
}
...and since there's no way for argument of n! to stop growing negative, it'll repeat (with n!(0 - 1 - 1) in the second match arm, then n!(0 - 1 - 1 - 1) etc.) infinitely.
The key point here is that the macro expansion happens in compile-time, while the match statement you're trying to use to limit the recursion is invoked only at run-time and can't stop anything from appear before that. Unhappily, there's no easy way to do this, since Rust won't evaluate macro arguments (even if it's a constant expression), and so just adding the (0) => {0} branch to the macro won't work, since the macro will be invoked as (for example) n!(1 - 1).
I have QList<m_User> with
m_User {
QString status;
QString firstName;
QString lastName;
QDate joinDate;
QDate leaveDate;
}
status here can be: terminated, in test, requested, activated.
The order of sorting for status should be: activated -> terminated -> requested -> in test
This QList should be sorted according to this order:
status (with order like above)
if status is same, we sort firstName, this time alphabetically
if firstName is same, we sort lastName, also alphabetically
So the result should look like
----------------------------------------------------------
| firstName | lastName | status | joinDate | leaveDate |
----------------------------------------------------------
| A | C |activated | bla | bla |
| A | D |activated | bla | bla |
| B | E |activated | bla | bla |
| A | F |terminated| bla | bla |
| A | G |terminated| bla | bla |
| B | H |terminated| bla | bla |
| A | I |requested | bla | bla |
| B | I |requested | bla | bla |
| B | K |requested | bla | bla |
| A | L | in test | bla | bla |
| B | L | in test | bla | bla |
| B | M | in test | bla | bla |
You can add lessThen function to your class/struct and then if needed create forwarder for qSort.
Example:
class m_User {
public:
bool operator<(const m_User other) const {
return a<other.a;
}
};
template <typename T>
struct ForwardLessThen
{
bool operator()(const T* a, const T* b) const
{
return *a < *b;
}
};
qSort(list.begin(), list.end(), ForwardLessThen<m_User>());
if you use C++11/14 you can use lambdas
QList<const m_User*> l;
qSort(l.begin(), l.end(),
[](const m_User* a, const m_User* b) -> bool { return a->firstName() < b->firstName(); //implement your logic here
});
With Qt5 qSort is actually deprecated and you should use std::sort function.
std::sort(container.begin(), container.end(), qLess<T>());
Take a look at template-based algorithms in QtAlgorithms
EDIT: Or if you plan using some kind of View Models(like ListView) you can even implement own QSortFilterProxyModel
bool compareUsers(const m_User &u1, const m_User &u2)
{
if(u1.status != u2.status)
{
//compare all possible combination if statuses of the
//u1 user and u2 user and return which has priority
//example activated has priorty over terminated
if(u1.status == "activated" && u2.status =="terminated")
{
return true;
}
else if(u1.status == "terminated" && u2.status =="activated")
{
return false;
}
...
..
.
}
else if(u1.firstName != u2.firstName)
{
return u1.firstName > u2.firstName;
}
else
{
return u1.lastName > u2.lastName;
}
}
and then just call the predicate in sort function
QList<m_User> list;
qSort(list.begin(), list.end(), compareUsers);
Currently a student in college, decided to jump ahead of my programming class and have a little fun with pointers. This is supposed to take a specific serial input and change the state of three LED's I have attached to the Teensy++2.0. However it seems to be just giving me back the first input.
http://arduino.cc/en/Serial/ReadBytesUntil
This is my reference for the ReadBytesUntil() The input goes #,#,### (1,1,255 being an example)
I guess basically my question is, does ReadBytesUntil() deal with commas? And if so, whats going on here?
EDIT -- I asked my teacher and even he has no clue why it doesn't work.
char *dataFinder(char *str){
while (*str != ','){
str++;
}
str++;
return str;
}
void inputDecoder(){
str = incomingText;
whichLED = *str;
dataFinder(str);
onoff = *str;
dataFinder(str);
powerLevel = *str;
}
void loop(){
int length;
if (Serial.available() > 0 ){ //this is basically: if something is typed in, do something.
length = Serial.readBytesUntil(13,incomingText, 10); //reads what is typed in, and stores it in incomingVar
incomingText[length]=0; ///swapping out cr with null
inputDecoder();
//ledControl();
Serial.print("Entered:");
//incomingText[9]=0;
Serial.println(incomingText); //Here for testing, to show what values I'm getting back.
Serial.println(whichLED);
Serial.println(onoff);
Serial.println(powerLevel);
}
delay(1000);
}
The str in inputDecoder() is from the global scope and is not the same str in dataFinder(), which has local scope.
Imagine this ASCII picture is the layout of memory:
str
+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+
| * | | | | ... | 1 | , | 1 | , | 2 | 5 | 5 | \n |
+--|--+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+
|
|
\-----------------------------^
When you pass str to dataFinder() it creates a copy of the pointer, which I'll call str'
str str'
+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+
| * | | * | | ... | 1 | , | 1 | , | 2 | 5 | 5 | \n |
+--|--+-----+--|--+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+
| \-----------------^
|
\-----------------------------^
When dataFinder() increments str it is really altering str'
str str'
+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+
| * | | * | | ... | 1 | , | 1 | , | 2 | 5 | 5 | \n |
+--|--+-----+--|--+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+
| \-----------------------------^
|
\-----------------------------^
Then, when you return to inputDecoder() you dereference str which is still pointing at the start of the string.
You can either assign the value of str' back to the global str using:
str = dataFinder(str);
or change dataFinder() so it does not take an argument, therefore not copying the variable.