I have a loop in which a program receives a message via a web socket and writes information about the user (from the message) to the 'database?'.
#[derive(Debug)]
struct ChatUser{
name: String,
password: String,
}
static NEW_USER_ID: AtomicUsize = AtomicUsize::new(1);
type UserDB = Arc<RwLock<HashMap<usize, ChatUser>>>;
async fn web_socket(mut ws: WebSocket, State(state): State<UserDB>) {
let new_id = NEW_USER_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
while let Ok(Message::Text(message)) = ws.next().await.unwrap(){
let user_info: Value = serde_json::from_str(&message.trim()).unwrap();
let (name, password) = (user_info["name"].to_string(), user_info["password"].to_string());
state.write().await.insert(new_id, ChatUser { name: name, password: password }).expect("cant write");
println!("{:?}",state);
}
}
state.write does not work correctly when run in a loop... outside the loop everything works correctly
Is it possible to take values out of the loop? or write them down in the state in some other way?
if I run the code and send message to socket
thread 'tokio-runtime-worker' panicked at src/main.rs:41:93:
cant write
stack backtrace:
0: rust_begin_unwind
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:652:5
1: core::panicking::panic_fmt
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panicking.rs:72:14
2: core::panicking::panic_display
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panicking.rs:262:5
3: core::option::expect_failed
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/option.rs:1995:5
4: core::option::Option<T>::expect [............]
how can I fix it?
"can't write" <--- is the message form state.write.await.insert.expect("can't write")
There are 2 problem
The returned value of HashMap::insert()
is Option<V>
, which does not represent if the insertion is successful, it is always successful, however,
Some(V)
of the old value when the key already in the HashMap, andNone
when it is a entirely new key. I.e. when first insert a key, it will return None, you should just let _ =
it .use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
// the first time inserting a key return `None`
assert_eq!(None, map.insert("My Key", 69));
// subsequent insertion return the already inserted value
assert_eq!(Some(69), map.insert("My Key", 420));
}
It's the wrong question but here is an answer anyway,
You can change the while
loop to a loop
loop, and break
a loop with a value.
let error: std::io::Error = loop {
// do whatever task
// blah blah blah
//...
// some how encounter a Result type
let result: Result<i32, std::io::Error> = /* some error-able things */;
let ok_i32 = match result {
// safely unwrap the result into Ok(_)
Ok(i) => i,
// return the error
Err(e) => break e,
};
// Keep doing whatever task
drop(ok_i32);
};