[-] suffering with closures, references, and async

so I have a personal problem. a problem that can only be solved by passing functions into functions.
here I am going to document the iterations through which this code (d)evolved as code requirements elsewhere changed.
So the original problem is thus: I had some code that needed to coordinate two clients interacting with eachother. the primary structure was a HashMap.
the way in which I wanted to interact with this was that I would give it the `ClientId` of one client and it would then fetch for me the coresponding `other_client` and give me mutable references to both. and given the aforementioned personal problem, I figured I would solve this through passing a function to this structure:
use std::collections::HashMap;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, ClientState>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, ClientState {
            other_client: client2,
            some_data: 0,
        });
        self.state.insert(client2, ClientState {
            other_client: client1,
            some_data: 0,
        });
    }

    pub fn with<T, F>(&mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&mut ClientState, &mut ClientState) -> T
    {
        let c1 = self.state.get_mut(&client).ok_or(StateError::Blah)?;
        let c2 = self.state.get_mut(&c1.other_client).ok_or(StateError::Blah)?;

        Ok(func(c1, c2))
    }
}

fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| {
        this.some_data = 23;
        other.some_data = 5;
    }).unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
cool great got the basic idea going lets see how it works
error[E0499]: cannot borrow `self.state` as mutable more than once at a time
  --> src/main.rs:37:18
   |
36 |         let c1 = self.state.get_mut(&client).ok_or(StateError::Blah)?;
   |                  --------------------------- first mutable borrow occurs here
37 |         let c2 = self.state.get_mut(&c1.other_client).ok_or(StateError::Blah)?;
   |                  ^^^^^^^^^^^^^^^^^^^----------------^
   |                  |                  |
   |                  |                  first borrow later used here
   |                  second mutable borrow occurs here
jokes on me of course it doesn't work those there consecutive `get_mut`s are just not gonna work luckily we have this rad `RefCell` thing to put in there to make this work:
use std::collections::HashMap;
use std::cell::RefCell;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub fn with<T, F>(&mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&mut ClientState, &mut ClientState) -> T
    {
        let mut c1 = self.state.get(&client).ok_or(StateError::Blah)?.borrow_mut();
        let mut c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?.borrow_mut();

        Ok(func(&mut *c1, &mut *c2))
    }
}

fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| {
        this.some_data = 23;
        other.some_data = 5;
    }).unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
$ cargo run
   Compiling sufferingwithwith v0.1.0 (/home/jake/projects/sharnoth.com/0005)
    Finished dev [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/sufferingwithwith`
c1 23
c2 5
look at it go.


and this was great, perfect, ideal. until suddenly `F` needed to be async.
use std::collections::HashMap;
use std::cell::RefCell;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub fn with<T, F>(&mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&mut ClientState, &mut ClientState) -> T
    {
        let mut c1 = self.state.get(&client).ok_or(StateError::Blah)?.borrow_mut();
        let mut c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?.borrow_mut();

        Ok(func(&mut *c1, &mut *c2))
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async {
        this.some_data = 23;
        other.some_data = 5;
    }).unwrap().await;

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
error: lifetime may not live long enough
  --> src/main.rs:50:43
   |
50 |       state.with(ClientId(1), |this, other| async {
   |  ______________________________----_______-_^
   | |                              |          |
   | |                              |          return type of closure `impl Future` contains a lifetime `'2`
   | |                              has type `&'1 mut ClientState`
51 | |         this.some_data = 23;
52 | |         other.some_data = 5;
53 | |     }).unwrap().await;
   | |_____^ returning this value requires that `'1` must outlive `'2`

error: lifetime may not live long enough
  --> src/main.rs:50:43
   |
50 |       state.with(ClientId(1), |this, other| async {
   |  ____________________________________------_^
   | |                                    |    |
   | |                                    |    return type of closure `impl Future` contains a lifetime `'4`
   | |                                    has type `&'3 mut ClientState`
51 | |         this.some_data = 23;
52 | |         other.some_data = 5;
53 | |     }).unwrap().await;
   | |_____^ returning this value requires that `'3` must outlive `'4`
   |
   = note: requirement occurs because of a mutable reference to `u32`
   = note: mutable references are invariant over their type parameter
   = help: see  for more information about variance

error: could not compile `sufferingwithwith` due to 2 previous errors
and now the suffering begins

now this error totally makes sense. `state` is lending out `this` and `other` which get captured by this async block which may not be `.await`ed until after `state` stops existing.
lets throw some lifetimes in here and see if it helps:
use std::collections::HashMap;
use std::cell::RefCell;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub fn with<'a, T, F>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&'a mut ClientState, &'a mut ClientState) -> T
    {
        let mut c1 = self.state.get(&client).ok_or(StateError::Blah)?.borrow_mut();
        let mut c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?.borrow_mut();

        Ok(func(&mut *c1, &mut *c2))
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async {
        this.some_data = 23;
        other.some_data = 5;
    }).unwrap().await;

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
error[E0597]: `c1` does not live long enough
  --> src/main.rs:41:23
   |
34 |     pub fn with<'a, T, F>(&'a mut self, client: ClientId, func: F) -> Result
   |                 -- lifetime `'a` defined here
...
41 |         Ok(func(&mut *c1, &mut *c2))
   |            -----------^^-----------
   |            |          |
   |            |          borrowed value does not live long enough
   |            argument requires that `c1` is borrowed for `'a`
42 |     }
   |     - `c1` dropped here while still borrowed

error[E0597]: `c2` does not live long enough
  --> src/main.rs:41:33
   |
34 |     pub fn with<'a, T, F>(&'a mut self, client: ClientId, func: F) -> Result
   |                 -- lifetime `'a` defined here
...
41 |         Ok(func(&mut *c1, &mut *c2))
   |            ---------------------^^-
   |            |                    |
   |            |                    borrowed value does not live long enough
   |            argument requires that `c2` is borrowed for `'a`
42 |     }
   |     - `c2` dropped here while still borrowed
literally useless

throwing shit at the wall, maybe a second lifetime 'b that is less than 'a:
use std::collections::HashMap;
use std::cell::RefCell;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub fn with<'a, 'b, T, F>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        'a: 'b,
        F: Fn(&'b mut ClientState, &'b mut ClientState) -> T
    {
        let mut c1 = self.state.get(&client).ok_or(StateError::Blah)?.borrow_mut();
        let mut c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?.borrow_mut();

        Ok(func(&mut *c1, &mut *c2))
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async {
        this.some_data = 23;
        other.some_data = 5;
    }).unwrap().await;

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
error[E0597]: `c1` does not live long enough
  --> src/main.rs:42:23
   |
34 |     pub fn with<'a, 'b, T, F>(&'a mut self, client: ClientId, func: F) -> Result
   |                     -- lifetime `'b` defined here
...
42 |         Ok(func(&mut *c1, &mut *c2))
   |            -----------^^-----------
   |            |          |
   |            |          borrowed value does not live long enough
   |            argument requires that `c1` is borrowed for `'b`
43 |     }
   |     - `c1` dropped here while still borrowed

error[E0597]: `c2` does not live long enough
  --> src/main.rs:42:33
   |
34 |     pub fn with<'a, 'b, T, F>(&'a mut self, client: ClientId, func: F) -> Result
   |                     -- lifetime `'b` defined here
...
42 |         Ok(func(&mut *c1, &mut *c2))
   |            ---------------------^^-
   |            |                    |
   |            |                    borrowed value does not live long enough
   |            argument requires that `c2` is borrowed for `'b`
43 |     }
   |     - `c2` dropped here while still borrowed

why did I think that would do anything.

its at this point that I notice all except one of my actual-code-that-caused-me-to-write-this `with` calls were using an async block internally. maybe I can just make `with` async and move on with my life
use std::collections::HashMap;
use std::cell::RefCell;
use std::future::Future;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&'a mut ClientState, &'a mut ClientState) -> Fut,
        Fut: Future<Output=T>,
    {
        let mut c1 = self.state.get(&client).ok_or(StateError::Blah)?.borrow_mut();
        let mut c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?.borrow_mut();

        Ok(func(&mut *c1, &mut *c2).await)
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async {
        this.some_data = 23;
        other.some_data = 5;
    }).await.unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
error[E0597]: `c1` does not live long enough
  --> src/main.rs:43:23
   |
35 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
43 |         Ok(func(&mut *c1, &mut *c2).await)
   |            -----------^^-----------
   |            |          |
   |            |          borrowed value does not live long enough
   |            argument requires that `c1` is borrowed for `'a`
44 |     }
   |     - `c1` dropped here while still borrowed

error[E0597]: `c2` does not live long enough
  --> src/main.rs:43:33
   |
35 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
43 |         Ok(func(&mut *c1, &mut *c2).await)
   |            ---------------------^^-
   |            |                    |
   |            |                    borrowed value does not live long enough
   |            argument requires that `c2` is borrowed for `'a`
44 |     }
   |     - `c2` dropped here while still borrowed
I suppose if I actually sat to think about this before just throwing code at my computer I would have realized this would never have solved anything. the result is still a future that needs to be `.await`ed outside of this function scope.

so how do I make my resulting borrowed clients live longer than this function? idk lets try Arc I'm getting desperate
use std::collections::HashMap;
use std::cell::RefCell;
use std::future::Future;

use async_std::sync::Arc;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, Arc<RefCell<ClientState>>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, Arc::new(RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        })));
        self.state.insert(client2, Arc::new(RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        })));
    }

    pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&'a mut ClientState, &'a mut ClientState) -> Fut,
        Fut: Future<Output=T>,
    {
        let c1 = self.state.get(&client).ok_or(StateError::Blah)?.clone();
        let c2 = self.state.get(&c1.borrow().other_client).ok_or(StateError::Blah)?.clone();

        let mut c1b = c1.borrow_mut();
        let mut c2b = c2.borrow_mut();

        Ok(func(&mut *c1b, &mut *c2b).await)
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async {
        this.some_data = 23;
        other.some_data = 5;
    }).await.unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
error[E0597]: `c1` does not live long enough
  --> src/main.rs:45:23
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
45 |         let mut c1b = c1.borrow_mut();
   |                       ^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
48 |         Ok(func(&mut *c1b, &mut *c2b).await)
   |            -------------------------- argument requires that `c1` is borrowed for `'a`
49 |     }
   |     - `c1` dropped here while still borrowed

error[E0597]: `c2` does not live long enough
  --> src/main.rs:46:23
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
46 |         let mut c2b = c2.borrow_mut();
   |                       ^^^^^^^^^^^^^^^ borrowed value does not live long enough
47 |
48 |         Ok(func(&mut *c1b, &mut *c2b).await)
   |            -------------------------- argument requires that `c2` is borrowed for `'a`
49 |     }
   |     - `c2` dropped here while still borrowed

error[E0597]: `c1b` does not live long enough
  --> src/main.rs:48:23
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
48 |         Ok(func(&mut *c1b, &mut *c2b).await)
   |            -----------^^^------------
   |            |          |
   |            |          borrowed value does not live long enough
   |            argument requires that `c1b` is borrowed for `'a`
49 |     }
   |     - `c1b` dropped here while still borrowed

error[E0597]: `c2b` does not live long enough
  --> src/main.rs:48:34
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
48 |         Ok(func(&mut *c1b, &mut *c2b).await)
   |            ----------------------^^^-
   |            |                     |
   |            |                     borrowed value does not live long enough
   |            argument requires that `c2b` is borrowed for `'a`
49 |     }
   |     - `c2b` dropped here while still borrowed
yeah the same problem the borrowing of the refcell does not last long enough for the actual running of the async function.

I'm starting to run out of ideas at this point.a Mutex would face similar problems.I suppose I could solve this problem by passing in the `RefCell` itself to the function but I would prefer to hide the details of the inner workings of with.
use std::collections::HashMap;
use std::cell::RefCell;
use std::future::Future;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&'a RefCell<ClientState>, &'a RefCell<ClientState>) -> Fut,
        Fut: Future<Output=T>,
    {
        let c1 = self.state.get(&client).ok_or(StateError::Blah)?;
        let c2 = self.state.get(&c1.borrow().other_client).ok_or(StateError::Blah)?;

        Ok(func(c1, c2).await)
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async {
        this.borrow_mut().some_data = 23;
        other.borrow_mut().some_data = 5;
    }).await.unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
$ cargo run
   Compiling sufferingwithwith v0.1.0 (/home/jake/projects/sharnoth.com/0005)
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/sufferingwithwith`
c1 23
c2 5
yeah I really do not like the `borrow_mut`s in the function itself BUT HEY IT WORKS.

in a questionable state of mind I figure "hey what happens if I send the `RefMut`s just directly by value?"
use std::collections::HashMap;
use std::cell::{RefCell, RefMut};
use std::future::Future;

use async_std::sync::{Arc, Mutex};

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(RefMut<ClientState>, RefMut<ClientState>) -> Fut,
        Fut: Future<Output=T>,
    {
        let c1 = self.state.get(&client).ok_or(StateError::Blah)?;
        let c2 = self.state.get(&c1.borrow().other_client).ok_or(StateError::Blah)?;

        let c1b = c1.borrow_mut();
        let c2b = c2.borrow_mut();

        Ok(func(c1b, c2b).await)
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |mut this, mut other| async move {
        this.some_data = 23;
        other.some_data = 5;
    }).await.unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
error: lifetime may not live long enough
  --> src/main.rs:57:51
   |
57 |       state.with(ClientId(1), |mut this, mut other| async move {
   |  ______________________________--------___________-_^
   | |                              |                  |
   | |                              |                  return type of closure `impl Future` contains a lifetime `'2`
   | |                              has type `RefMut<'1, ClientState>`
58 | |         this.some_data = 23;
59 | |         other.some_data = 5;
60 | |     }).await.unwrap();
   | |_____^ returning this value requires that `'1` must outlive `'2`

error: lifetime may not live long enough
  --> src/main.rs:57:51
   |
57 |       state.with(ClientId(1), |mut this, mut other| async move {
   |  ________________________________________----------_^
   | |                                        |        |
   | |                                        |        return type of closure `impl Future` contains a lifetime `'4`
   | |                                        has type `RefMut<'3, ClientState>`
58 | |         this.some_data = 23;
59 | |         other.some_data = 5;
60 | |     }).await.unwrap();
   | |_____^ returning this value requires that `'3` must outlive `'4`
oh nevermind me just being dumb over here ignoring that naturally those structures would have lifetimes built into them.

anyway, it seems the core problems I am having is that references to outside data inside async closures is just not gonna work.so lets try some stupid shit and see which I hate least.
removing from hashmap to run the function then re-add after:
use std::collections::HashMap;
use std::cell::{RefCell, RefMut};
use std::future::Future;

use async_std::sync::{Arc, Mutex};

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, ClientState>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, ClientState {
            other_client: client2,
            some_data: 0,
        });
        self.state.insert(client2, ClientState {
            other_client: client1,
            some_data: 0,
        });
    }

    pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(&'a mut ClientState, &'a mut ClientState) -> Fut,
        Fut: Future<Output=T>,
    {
        let mut c1 = self.state.remove(&client).ok_or(StateError::Blah)?;
        let mut c2 = self.state.remove(&c1.other_client).ok_or(StateError::Blah)?;

        let result = func(&mut c1, &mut c2).await;

        let c1_client_id = c2.other_client;
        let c2_client_id = c1.other_client;
        self.state.insert(c1_client_id, c1);
        self.state.insert(c2_client_id, c2);

        Ok(result)
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async move {
        this.some_data = 23;
        other.some_data = 5;
    }).await.unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().some_data);
}
error[E0597]: `c1` does not live long enough
  --> src/main.rs:45:27
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
45 |         let result = func(&mut c1, &mut c2).await;
   |                      -----^^^^^^^----------
   |                      |    |
   |                      |    borrowed value does not live long enough
   |                      argument requires that `c1` is borrowed for `'a`
...
53 |     }
   |     - `c1` dropped here while still borrowed

error[E0597]: `c2` does not live long enough
  --> src/main.rs:45:36
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
45 |         let result = func(&mut c1, &mut c2).await;
   |                      --------------^^^^^^^-
   |                      |             |
   |                      |             borrowed value does not live long enough
   |                      argument requires that `c2` is borrowed for `'a`
...
53 |     }
   |     - `c2` dropped here while still borrowed

error[E0503]: cannot use `c2.other_client` because it was mutably borrowed
  --> src/main.rs:47:28
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
45 |         let result = func(&mut c1, &mut c2).await;
   |                      ----------------------
   |                      |             |
   |                      |             borrow of `c2` occurs here
   |                      argument requires that `c2` is borrowed for `'a`
46 |
47 |         let c1_client_id = c2.other_client;
   |                            ^^^^^^^^^^^^^^^ use of borrowed `c2`

error[E0503]: cannot use `c1.other_client` because it was mutably borrowed
  --> src/main.rs:48:28
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
45 |         let result = func(&mut c1, &mut c2).await;
   |                      ----------------------
   |                      |    |
   |                      |    borrow of `c1` occurs here
   |                      argument requires that `c1` is borrowed for `'a`
...
48 |         let c2_client_id = c1.other_client;
   |                            ^^^^^^^^^^^^^^^ use of borrowed `c1`

error[E0505]: cannot move out of `c1` because it is borrowed
  --> src/main.rs:49:41
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
45 |         let result = func(&mut c1, &mut c2).await;
   |                      ----------------------
   |                      |    |
   |                      |    borrow of `c1` occurs here
   |                      argument requires that `c1` is borrowed for `'a`
...
49 |         self.state.insert(c1_client_id, c1);
   |                                         ^^ move out of `c1` occurs here

error[E0505]: cannot move out of `c2` because it is borrowed
  --> src/main.rs:50:41
   |
37 |     pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result
   |                       -- lifetime `'a` defined here
...
45 |         let result = func(&mut c1, &mut c2).await;
   |                      ----------------------
   |                      |             |
   |                      |             borrow of `c2` occurs here
   |                      argument requires that `c2` is borrowed for `'a`
...
50 |         self.state.insert(c2_client_id, c2);
   |                                         ^^ move out of `c2` occurs here

hahahah man jokes on me I have no idea what I am doing anymore.

ok so references here are infinite forever suffering how about I just pass the state by value and try and make that work in some capacity. so to pass by value then I need to like return the data back out:
use std::collections::HashMap;
use std::future::Future;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

#[derive(Clone)]
struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, ClientState>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, ClientState {
            other_client: client2,
            some_data: 0,
        });
        self.state.insert(client2, ClientState {
            other_client: client1,
            some_data: 0,
        });
    }

    pub async fn with<T, F, Fut>(&mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: Fn(ClientState, ClientState) -> Fut,
        Fut: Future<Output=(ClientState, ClientState, T)>,
    {
        let c1 = self.state.get(&client).ok_or(StateError::Blah)?;
        let c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?;

        let (c1, c2, result) = func(c1.clone(), c2.clone()).await;

        let c1_client_id = c2.other_client;
        let c2_client_id = c1.other_client;
        self.state.insert(c1_client_id, c1);
        self.state.insert(c2_client_id, c2);

        Ok(result)
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |mut this, mut other| async move {
        this.some_data = 23;
        other.some_data = 5;

        (this, other, ())
    }).await.unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().some_data);
}

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/sufferingwithwith`
c1 23
c2 5
I'm not sure if I dislike this more or less than the explicit borrow_mut()/lock() in the closure.I do think this version is susceptible to weird timing issues like the other one was.

so after some googling I find a possibly promising `FutureBoxLocal` future where I can specify a lifetime lets see how that goes
use std::collections::HashMap;
use std::cell::RefCell;

use futures::future::{Future, FutureExt, LocalBoxFuture};

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, RefCell<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, RefCell::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, RefCell::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub fn with<'a, 'b, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result<LocalBoxFuture<'a, T>, StateError>
    where
        'a: 'b,
        F: 'a + FnOnce(&'b mut ClientState, &'b mut ClientState) -> Fut,
        Fut: Future<Output=T> + 'b
    {
        let mut c1 = self.state.get(&client).ok_or(StateError::Blah)?.borrow_mut();
        let mut c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?.borrow_mut();

        Ok(async move {
            func(&mut *c1, &mut *c2).await
        }
        .boxed_local())
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |this, other| async {
        this.some_data = 23;
        other.some_data = 5;
    }).unwrap().await;

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().borrow().some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().borrow().some_data);
}
error[E0597]: `c1` does not live long enough
  --> src/main.rs:46:24
   |
36 |     pub fn with<'a, 'b, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result, StateError>
   |                     -- lifetime `'b` defined here
...
46 |             func(&mut *c1, &mut *c2).await
   |             -----------^^-----------
   |             |          |
   |             |          borrowed value does not live long enough
   |             argument requires that `c1` is borrowed for `'b`
47 |         }
   |         - `c1` dropped here while still borrowed

error[E0597]: `c2` does not live long enough
  --> src/main.rs:46:34
   |
36 |     pub fn with<'a, 'b, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result, StateError>
   |                     -- lifetime `'b` defined here
...
46 |             func(&mut *c1, &mut *c2).await
   |             ---------------------^^-
   |             |                    |
   |             |                    borrowed value does not live long enough
   |             argument requires that `c2` is borrowed for `'b`
47 |         }
   |         - `c2` dropped here while still borrowed
nope that sure didn't help!

you know just for completions sake lets just do the MutexGuard version of that RefCellimplementation above oh wait look at those docs theres a lifetime parameter for MutexGuard<'a, T> (and apparently for RefCell which I totally did not notice which may have made my life easier a while ago). maybe that will save the day
use std::collections::HashMap;
use async_std::sync::{Mutex, MutexGuard};
use futures::future::Future;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct ClientId(u32);

struct ClientState {
    other_client: ClientId,
    some_data: u32,
}

#[derive(Debug)]
enum StateError {
    Blah,
}

#[derive(Default)]
struct State {
    state: HashMap<ClientId, Mutex<ClientState>>,
}

impl State {
    pub fn new_client(&mut self, client1: ClientId, client2: ClientId) {
        self.state.insert(client1, Mutex::new(ClientState {
            other_client: client2,
            some_data: 0,
        }));
        self.state.insert(client2, Mutex::new(ClientState {
            other_client: client1,
            some_data: 0,
        }));
    }

    pub async fn with<'a, T, F, Fut>(&'a mut self, client: ClientId, func: F) -> Result<T, StateError>
    where
        F: FnOnce(MutexGuard<'a, ClientState>, MutexGuard<'a, ClientState>) -> Fut + 'a,
        Fut: Future<Output=T>,
    {
        let c1 = self.state.get(&client).ok_or(StateError::Blah)?.lock().await;
        let c2 = self.state.get(&c1.other_client).ok_or(StateError::Blah)?.lock().await;

        Ok(func(c1, c2).await)
    }
}

#[async_std::main]
async fn main() {
    let mut state = State::default();
    state.new_client(ClientId(1), ClientId(2));

    state.with(ClientId(1), |mut this, mut other| Box::pin(async move {
        this.some_data = 23;
        other.some_data = 5;
    })).await.unwrap();

    println!("c1 {}", state.state.get(&ClientId(1)).unwrap().lock().await.some_data);
    println!("c2 {}", state.state.get(&ClientId(2)).unwrap().lock().await.some_data);
}
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/sufferingwithwith`
c1 23
c2 5
oh. huh. cool.