From c6ff11dd3edc0ae7b555b42c7ad0a652c2959d7e Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 13 Jan 2025 23:11:43 -0800 Subject: [PATCH] use replace_with to replace the enum variant in-place without cloning --- strafe-client/src/mouse_interpolator.rs | 75 +++++++++++++------------ 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/strafe-client/src/mouse_interpolator.rs b/strafe-client/src/mouse_interpolator.rs index ee55452..6998b10 100644 --- a/strafe-client/src/mouse_interpolator.rs +++ b/strafe-client/src/mouse_interpolator.rs @@ -28,15 +28,16 @@ enum BufferState{ Buffered(SessionTime,MouseState), } impl BufferState{ - fn next_state(&self,ins:DoubleTimedUnbufferedInstruction,physics_timeline:&mut std::collections::VecDeque)->(Self,Option>){ - match self{ + fn next_state(self,ins:DoubleTimedUnbufferedInstruction,physics_timeline:&mut std::collections::VecDeque)->(Option>,Self){ + let next_state=match self{ BufferState::Unbuffered=>{ if let PhysicsUnbufferedInstruction::MoveMouse(pos)=ins.instruction.instruction{ - return (BufferState::Initializing(ins.time,MouseState{pos,time:ins.instruction.time}),None); + return (None,BufferState::Initializing(ins.time,MouseState{pos,time:ins.instruction.time})); } + BufferState::Unbuffered }, BufferState::Initializing(time,mouse_state)=>{ - let timeout=*time+MOUSE_TIMEOUT; + let timeout=time+MOUSE_TIMEOUT; if timeout{ // TODO: deduplicate code with above case - let timeout=*time+MOUSE_TIMEOUT; + let timeout=time+MOUSE_TIMEOUT; if timeoutNone, PhysicsUnbufferedInstruction::Other(other_instruction)=>Some(TimedInstruction{ @@ -99,7 +102,7 @@ impl BufferState{ instruction:other_instruction, }), }; - (self.clone(),instruction_out) + (instruction_out,next_state) } } pub struct MouseInterpolator{ @@ -139,9 +142,10 @@ impl MouseInterpolator{ // a mouse event is buffered, and exists within the last 10ms // case 3: stop // a mouse event is buffered, but no mouse events have transpired within 10ms - // TODO: remove clone - let ins_inner; - (self.buffer_state,ins_inner)=self.buffer_state.next_state(ins,&mut self.physics_timeline); + // replace_with allows the enum variant to safely be replaced from behind a mutable reference + let ins_inner=replace_with::replace_with_or_abort_and_return(&mut self.buffer_state,|buffer_state|{ + buffer_state.next_state(ins,&mut self.physics_timeline) + }); if let Some(ins)=ins_inner{ self.physics_timeline.push_back(TimedInstruction{ time:ins.time, @@ -196,26 +200,27 @@ impl MouseInterpolator{ match ins{ // could check if self.is_first_ready() StepInstruction::Pop=>self.physics_timeline.pop_front(), - StepInstruction::Timeout=>match &self.buffer_state{ - BufferState::Unbuffered=>None, - BufferState::Initializing(time,mouse_state) - |BufferState::Buffered(time,mouse_state)=>{ - // convert to BufferState::Unbuffered - // use the first instruction which should be a mouse instruction - // to push a ReplaceMouse instruction - // duplicate the current mouse - self.buffer_state=BufferState::Unbuffered; - Some(TimedInstruction{ - // This should be simulation_timer.time(timeout) - // but the timer is not accessible from this scope - // and it's just here to say that the mouse isn't moving anyways. - time:mouse_state.time, - instruction:PhysicsInputInstruction::Mouse( - MouseInstruction::SetNextMouse(MouseState{pos:mouse_state.pos,time:mouse_state.time}) - ), - }) - }, - }, + StepInstruction::Timeout=>replace_with::replace_with_or_abort_and_return(&mut self.buffer_state,|buffer_state|{ + match buffer_state{ + BufferState::Unbuffered=>(None,BufferState::Unbuffered), + BufferState::Initializing(_time,mouse_state) + |BufferState::Buffered(_time,mouse_state)=>{ + // convert to BufferState::Unbuffered + // use the first instruction which should be a mouse instruction + // to push a ReplaceMouse instruction + // duplicate the current mouse + (Some(TimedInstruction{ + // This should be simulation_timer.time(timeout) + // but the timer is not accessible from this scope + // and it's just here to say that the mouse isn't moving anyways. + time:mouse_state.time, + instruction:PhysicsInputInstruction::Mouse( + MouseInstruction::SetNextMouse(MouseState{pos:mouse_state.pos,time:mouse_state.time}) + ), + }),BufferState::Unbuffered) + }, + } + }), } } }