elegant way of capturing a reference to an integer variable? - input

I have this snippet:
let mut animation_index = 0 as usize;
let mut ptr : *mut usize = &mut animation_index as _;
{
io_context.window().add_key_callback(
Box::new(move |key_states| {
if key_states[KbKey::Space.to_index()] == KeyActionState::Press
{
unsafe {
*ptr += 1;
println!("{}", animation_index);
}
}
})
);
}
Basically it adds a callback such that if and when I press space, the integer variable animation_index goes up by 1. This works, but requires the use of mutable pointers and unsafe, which is very ugly.
I'd like to have the same logic but ideally do it with pure safe rust isntead.

It looks like you are trying to share a mutable value across threads.
Typically, this is done with atomics, Arc<Mutex<T>> or Arc<RwLock<T>>.
use std::synce::{Arc, RwLock};
let mut animation_index = Arc::new(RwLock::new(0usize));
{
// a clone of the counter that can be moved into the callback
let animation_index = animation_index.clone();
io_context.window().add_key_callback(
Box::new(move |key_states| {
if key_states[KbKey::Space.to_index()] == KeyActionState::Press
{
let index = animation_index.write().unwrap();
*index += 1;
println!("{}", index);
}
})
);
}
With atomics it would look something like this:
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
let mut animation_index = Arc::new(AtomicUsize::new(0));
{
// a clone of the counter that can be moved into the callback
let animation_index = animation_index.clone();
io_context.window().add_key_callback(
Box::new(move |key_states| {
if key_states[KbKey::Space.to_index()] == KeyActionState::Press
{
let index = animation_index.fetch_add(1, Ordering::SeqCst);
println!("{}", index);
}
})
);
}

Related

How can I print data in a way that consumes local variables when an assert fails in Rust?

I have some tests which have some variables that hold some important data and I'd like to print their data when an assertion fails. Getting the data I need consumes the variables, so the printing code must own the variables. In this example, I'd want to call dump_foo_data once an assertion fails:
struct Foo();
fn dump_foo_data(f: Foo) {
eprintln!("Behold, Foo data: ");
}
#[test]
fn my_test() {
let f = Foo();
eprintln!("begin");
// do a test
&f;
let success = true;
assert!(success);
// do another test
&f;
let success = false;
assert!(success);
}
I can make a very bad solution by making dump_foo_data non-returning and panic:
fn dump_foo_data(f: Foo) -> ! {
eprintln!("Behold, Foo data: ");
panic!();
}
Then instead of using assert!, I check the failure with an if and maybe call dump_foo_data:
let success = true;
if !success {
dump_foo_data(f);
}
This is too many lines of code, and I need to specify f. In reality, I have more than one variable like f that I need to dump data from, so it's not very nice to list out single relevant local variable in every check.
I couldn't figure out how to write a macro to make this better because I'd still need to pass every relevant local variable to the macro.
I couldn't think of a way to use std::panic either. update_hook would need to take ownership of f, then I couldn't use it in tests.
Is there any good way to do this in Rust?
Edit: I've thought of another approach: put each relevant local in an Rc then pass each of those to std::panic::update_hook. I've not confirmed whether this'll work yet.
Edit 2: Maybe I could abuse break to do what I explained with goto in a comment.
One way that doesn't use any macro or shared-interior-mutability-reference magic might be to repossess f:
fn check_or_dump(success: bool, f: Foo) -> Foo {
match success {
true => f,
false => panic!("Behold foo data: {:?}", dump_foo_data(f)),
}
}
You use it like this:
let f = Foo();
let success = true;
let f = check_or_dump(success, f);
let success = false;
let f = check_or_dump(success, f);
// and so on.
Here's a solution without macro or interior mutability and that doesn't require you to list all the variables on each check. It is inspired by this answer:
struct Foo();
fn dump_foo_data(_f: Foo) {
eprintln!("Behold, Foo data: ");
}
#[test]
fn my_test() {
let f = Foo();
let doit = || -> Option<()> {
eprintln!("begin");
// do a test
&f;
let success = true;
success.then_some(())?;
// do another test
&f;
let success = false;
success.then_some(())?;
Some(())
};
if let None = doit() {
dump_foo_data (f);
panic!("Test failure");
}
}
Playground
I've worked out a solution using the panic handler:
use std::rc::Rc;
use std::cell::{Cell, RefCell};
use std::panic::PanicInfo;
thread_local! {
static TL_PANIC_TARGETS: RefCell<Vec<Rc<dyn PanicTrigger>>> = RefCell::new(vec![]);
}
pub trait PanicTrigger {
fn panic_trigger(self: Rc<Self>);
}
pub fn register_panic_trigger<P: PanicTrigger + 'static>(p: Rc<P>) {
TL_PANIC_TARGETS.with(|v: _| {
v.borrow_mut().push(p.clone());
});
}
#[ctor::ctor]
fn set_panic_hook() {
let old_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |pi: &PanicInfo| {
run_panic_triggers(pi);
old_hook(pi);
}));
}
fn run_panic_triggers(_: &PanicInfo) {
TL_PANIC_TARGETS.with(|v: _| {
for pt in v.take() {
pt.panic_trigger();
}
});
}
struct Foo();
fn dump_foo_data(_f: Foo) {
eprintln!("Behold, Foo data: ");
}
impl PanicTrigger for Cell<Option<Foo>> {
fn panic_trigger(self: Rc<Self>) {
if let Some(f) = self.take() {
dump_foo_data(f);
}
}
}
#[test]
fn my_test() {
let f = Rc::new(Cell::new(Some(Foo())));
register_panic_trigger(f.clone());
let success = true;
assert!(success);
let success = false;
assert!(success);
}
fn main() { }
Basically, you put the relevant data in an Rc and keep a local reference and put one in TLS for the panic handler. You need to put it in an Option in a Cell so that you can move out of it.
Types that don't need to be owned to print relevant data can be registered too, and you don't need to implement PanicTrigger on a Cell<Option<T>>, just T.
This is thread-safe.
Because the data is so wrapped up, it's harder to manipulate in the test body. But now you can use normal assert!. It's a trade-off.

Is there an alternative to this unsafe code for mutable index rust

I am making a chess game and I'm looking to return a mutable null character from an array of pieces when the index of the array (a Vec2 is out of bounds), the reason I need to do this is that my function for moving the piece needs a mutable reference to the Indexed piece, long story short I ended up needing to create a static NULL_PIECE that I could reference within the function but this is potentially quite dangerous as you'll see from my code
impl Index<IVec2> for Board {
type Output = Piece;
fn index(&self, index : IVec2) -> &Self::Output{
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
&Piece('\0') // this works
} else {
let i : usize = (index.x + WIDTH* index.y).try_into().unwrap();
&self.pieces[i]
}
}
}
impl IndexMut<IVec2> for Board {
fn index_mut(&mut self, index: IVec2) -> &mut Self::Output{
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
// &mut Piece('\0') // this does not work
unsafe {&mut NULL_PIECE} // this works but I don't like it
} else {
let i : usize = (index.x + WIDTH * index.y).try_into().unwrap();
&mut self.pieces[i]
}
}
}
There is a lot of potential for this to cause an error in the event that this mutates to be a piece because of the recursion I've implemented on the piece movement.
You can find the GitHub link here:
https://github.com/LyndonAlcock/chess_test/tree/main/src
Instead of implementing Index you could write it as:
impl Board {
fn get(&self, index: IVec2) -> Option<&Piece> {
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
None
} else {
let i = (index.x + WIDTH* index.y).try_into().ok()?;
Some(&self.pieces[i])
}
}
fn get_mut(&mut self, index: IVec2) -> Option<&mut Piece> {
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
None
} else {
let i = (index.x + WIDTH * index.y).try_into().ok()?;
Some(&mut self.pieces[i])
}
}
}
Index implementations should panic when the index is out of bounds.

Rust server must save the updated value of variable

I need to realize TCP server, that stores a variable M. At the beginning, M = 1.
But, when the conntection set between server and client, and client sends another value of variable N, server must do next: M = M * N. And return that value to client.
And server must save that new value of variable M!
And, when next new client set connection, it will work with new value of variable.
Example:
Server: M = 1; Client: N = 5; Server: M = 5;
Server: A = 5; Client: N = 8; Server: M = 40;
This is my code of my server. And it works in that way:(not saving new value)
Example:
Server: M = 1; Client: N = 5; Server: M = 5;
Server: A = 1; Client: N = 8; Server: M = 8;
Maybe should I do a global variable? Or something about it... Give me some advice. Thank you.
fn handle_client(mut stream: TcpStream, a:&mut i32) {
let mut data = [0 as u8; 30]; // using 30 byte buffer
while match stream.read(&mut data) {
Ok(size) => {
if size>0{
let temp = str::from_utf8(&data[0..size]).unwrap().to_string();
let temp: i32 = temp.trim().parse().unwrap();
*a = *a * temp;
let st = a.to_string();
// String в u8
let data = st.as_bytes();
stream.write(&data).unwrap();
}
true
},
Err(_) => {
println!("An error occurred, terminating connection with {}", stream.peer_addr().unwrap());
stream.shutdown(Shutdown::Both).unwrap();
false
}
} {}
}
fn main() {
let listener = TcpListener::bind("0.0.0.0:7956").unwrap();
let mut a: i32 = 1;
// accept connections and process them, spawning a new thread for each one
println!("Server listening on port 7956");
println!("A = 1");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
println!("New connection: {}", stream.peer_addr().unwrap());
thread::spawn(move|| {
// connection succeeded
handle_client(stream, &mut a)
});
}
Err(e) => {
println!("Error: {}", e);
/* connection failed */
}
}
}
// close the socket server
drop(listener);
}
Why doesn't your code work?
Because you move a into the closure, thus copying it. In order to se that, you just have to ask: What do you need to move into the closure, such that &mut a is of type &mut i32?
Exactly, a "raw" i32. How does the compiler do that? By copying it. That means changes to the variable "inside" the closure will not be reflected "outside".
Well, then how to fix it?
Let's start from the beginning: If you simply don't borrow in the call, you will move a mutable reference into the closure - that doesn't work though, due to two reasons: Firstly, it is obviously not thread safe, and secondly, the lifetime of the borrow cant even be guaranteed to be long enough ('static).
How do we work around that: For the first part, the thread-safety, we could use a Mutex. That's overkill for a simple integer though. We use an atomic. For the second part, we could use an Arc - I again went with the simpler option, make it a static ("global") variable.
Edit: In the comments it was raised to my attention, that maybe my views of a "simple" solution to this problem are a little skewed, this is a link to the chapter on thread-safety in the book, which uses an Arc<Mutex<_>> to count to ten in parallel. Every Rust programmer should have read that section (and the entire book!).
So here is your code, with only the relevant parts rewritten:
use std::sync::atomic;
fn handle_client(mut stream: TcpStream) {
let mut data = [0 as u8; 30]; // using 30 byte buffer
while match stream.read(&mut data) {
Ok(size) => {
if size > 0 {
let temp = std::str::from_utf8(&data[0..size]).unwrap().to_string();
let temp: i32 = temp.trim().parse().unwrap();
let prev_a_val = loop {
let a_acquired = a.load(atomic::Ordering::Acquire);
match a.compare_exchange_weak(
a_acquired,
a_acquired * temp,
atomic::Ordering::AcqRel,
atomic::Ordering::Acquire,
) {
Ok(value) => break value,
Err(_) => {}
}
};
let st = (prev_a_val * temp).to_string();
// String в u8
let data = st.as_bytes();
stream.write(&data).unwrap();
}
true
}
Err(_) => {
println!(
"An error occurred, terminating connection with {}",
stream.peer_addr().unwrap()
);
stream.shutdown(Shutdown::Both).unwrap();
false
}
} {}
}
static a: atomic::AtomicI32 = atomic::AtomicI32::new(1);
fn main() {
let listener = TcpListener::bind("0.0.0.0:7956").unwrap();
// accept connections and process them, spawning a new thread for each one
println!("Server listening on port 7956");
println!("A = 1");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
println!("New connection: {}", stream.peer_addr().unwrap());
thread::spawn(|| {
// connection succeeded
handle_client(stream)
});
}
Err(e) => {
println!("Error: {}", e);
/* connection failed */
}
}
}
}

Return Option inside Loop

The program aims to use a loop to check if the index of a iterator variable meets certain criteria (i.g., index == 3). If find the desired index, return Some(123), else return None.
fn main() {
fn foo() -> Option<i32> {
let mut x = 5;
let mut done = false;
while !done {
x += x - 3;
if x % 5 == 0 {
done = true;
}
for (index, value) in (5..10).enumerate() {
println!("index = {} and value = {}", index, value);
if index == 3 {
return Some(123);
}
}
return None; //capture all other other possibility. So the while loop would surely return either a Some or a None
}
}
}
The compiler gives this error:
error[E0308]: mismatched types
--> <anon>:7:9
|
7 | while !done {
| ^ expected enum `std::option::Option`, found ()
|
= note: expected type `std::option::Option<i32>`
= note: found type `()`
I think the error source might be that a while loop evaluates to a (), thus it would return a () instead of Some(123). I don't know how to return a valid Some type inside a loop.
The value of any while true { ... } expression is always (). So the compiler expects your foo to return an Option<i32> but finds the last value in your foo body is ().
To fix this, you can add a return None outside the original while loop. You can also use the loop construct like this:
fn main() {
// run the code
foo();
fn foo() -> Option<i32> {
let mut x = 5;
loop {
x += x - 3;
for (index, value) in (5..10).enumerate() {
println!("index = {} and value = {}", index, value);
if index == 3 {
return Some(123);
}
}
if x % 5 == 0 {
return None;
}
}
}
}
The behaviour of while true { ... } statements is maybe a bit quirky and there have been a few requests to change it.

is it possible to filter on a vector in-place?

I'd like to remove some elements from a Vec, but vec.iter().filter().collect() creates a new vector with borrowed items.
I'd like to mutate the original Vec without extra memory allocation (and keep memory of removed elements as an extra capacity of the vector).
If you want to remove elements, you can use retain(), which removes elements from the vector if the closure returns false:
let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);
If you want to modify the elements in place, you have to do that in a for x in vec.iter_mut().
If you truly want to mutate the vector's elements while filtering it, you can use the nightly-only method Vec::drain_filter, an extremely flexible tool:
#![feature(drain_filter)]
fn main() {
let mut vec = vec![1, 2, 3, 4];
vec.drain_filter(|x| {
if *x % 2 == 0 {
true
} else {
*x += 100;
false
}
});
assert_eq!(vec, [101, 103]);
}
It also allows you to get the removed elements as the return value of the entire method is an iterator!
Till Vec::drain_filter gets stable, we can solve the problem with homebrewed rust:
fn main() {
let mut v = vec![1, 2, 3, 4];
let mut i = 0;
while i < v.len() {
if v[i] % 2 == 0 {
v.remove(i);
} else {
v[i] += 100;
i += 1;
}
}
println!("{:?}", v); // [101, 103]
}
BTW remove() is an O(n) operation but doesn't allocate memory.
Playground
I am providing my take for this problem as I was unaware of the retain method:
impl<T> RemoveFilter<T> for Vec<T> {}
pub trait RemoveFilter<T>: BorrowMut<Vec<T>> {
fn remove_filter<F: for<'b> FnMut(&'b T) -> bool>(&mut self, mut cb: F) {
let vec: &mut Vec<T> = self.borrow_mut();
let mut write_to = 0;
let mut read_from = 0;
while read_from < vec.len() {
let maintain = cb(&mut vec[read_from]);
if maintain {
vec.as_mut_slice().swap(read_from, write_to);
write_to += 1;
}
read_from += 1;
}
vec.resize_with(write_to, || panic!("We are shrinking the vector"));
}
}
It will shift the elements as it iterates and then remove anything that is left behind. I think this is code may easily modified to solve other problems.