From 2b50e7d31aa6678a8dbf2014b3711352c2cd6a6d Mon Sep 17 00:00:00 2001 From: Seaotatop Date: Thu, 29 Jun 2023 17:41:08 -0500 Subject: [PATCH] Add unwrap warning, deal with some unwraps --- src/api.rs | 27 ++++--- src/api/msg.rs | 8 -- src/backend/udev.rs | 1 + src/backend/winit.rs | 9 ++- src/handlers.rs | 41 ++++++---- src/input.rs | 155 +++++++++++++++++++++++-------------- src/main.rs | 1 + src/output.rs | 5 +- src/state.rs | 96 +++++++++++++---------- src/window.rs | 5 +- src/window/window_state.rs | 2 +- 11 files changed, 210 insertions(+), 140 deletions(-) diff --git a/src/api.rs b/src/api.rs index a0988d1..effabef 100644 --- a/src/api.rs +++ b/src/api.rs @@ -54,14 +54,17 @@ use self::msg::{Msg, OutgoingMsg}; const SOCKET_PATH: &str = "/tmp/pinnacle_socket"; -fn handle_client(mut stream: UnixStream, sender: Sender) { +fn handle_client( + mut stream: UnixStream, + sender: Sender, +) -> Result<(), Box> { loop { let mut len_marker_bytes = [0u8; 4]; if let Err(err) = stream.read_exact(&mut len_marker_bytes) { if err.kind() == io::ErrorKind::UnexpectedEof { tracing::warn!("stream closed: {}", err); - stream.shutdown(std::net::Shutdown::Both).unwrap(); - break; + stream.shutdown(std::net::Shutdown::Both)?; + break Ok(()); } }; @@ -71,15 +74,14 @@ fn handle_client(mut stream: UnixStream, sender: Sender) { if let Err(err) = stream.read_exact(msg_bytes.as_mut_slice()) { if err.kind() == io::ErrorKind::UnexpectedEof { tracing::warn!("stream closed: {}", err); - stream.shutdown(std::net::Shutdown::Both).unwrap(); - break; + stream.shutdown(std::net::Shutdown::Both)?; + break Ok(()); } }; - let msg: Msg = rmp_serde::from_slice(msg_bytes.as_slice()).unwrap(); // TODO: handle error + let msg: Msg = rmp_serde::from_slice(msg_bytes.as_slice())?; // TODO: handle error - sender.send(msg).unwrap(); + sender.send(msg)?; } - tracing::info!("end of handle_client"); } pub struct PinnacleSocketSource { @@ -151,10 +153,15 @@ impl EventSource for PinnacleSocketSource { .process_events(readiness, token, |_readiness, listener| { while let Ok((stream, _sock_addr)) = listener.accept() { let sender = self.sender.clone(); - let callback_stream = stream.try_clone().unwrap(); // TODO: error + let callback_stream = match stream.try_clone() { + Ok(callback_stream) => callback_stream, + Err(err) => return Err(err), + }; callback(callback_stream, &mut ()); std::thread::spawn(move || { - handle_client(stream, sender); + if let Err(err) = handle_client(stream, sender) { + tracing::error!("handle_client errored: {err}"); + } }); } diff --git a/src/api/msg.rs b/src/api/msg.rs index 65346d6..8eef078 100644 --- a/src/api/msg.rs +++ b/src/api/msg.rs @@ -52,14 +52,6 @@ pub enum Msg { callback_id: Option, }, - /// Run a command using the optionally specified shell and callback. - SpawnShell { - shell: Option, - command: Vec, - #[serde(default)] - callback_id: Option, - }, - // Pinnacle management /// Quit the compositor. Quit, diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 55be019..44f9cb2 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -7,6 +7,7 @@ // from anvil // TODO: figure out what this stuff does +#![allow(clippy::unwrap_used)] // I don't know what this stuff does yet use std::{ collections::{HashMap, HashSet}, error::Error, diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 9ec6b17..d740e25 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -142,7 +142,7 @@ pub fn run_winit() -> Result<(), Box> { .collect::>(); let dmabuf_default_feedback = DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats) .build() - .unwrap(); + .expect("DmabufFeedbackBuilder error"); Some(dmabuf_default_feedback) } Ok(None) => { @@ -260,9 +260,9 @@ pub fn run_winit() -> Result<(), Box> { states .data_map .get::>() - .unwrap() + .expect("Mutex wasn't in the data map") .lock() - .unwrap() + .expect("Failed to lock Mutex") .hotspot }) } else { @@ -291,7 +291,8 @@ pub fn run_winit() -> Result<(), Box> { // render_output() let space_render_elements = - space::space_render_elements(renderer, [&state.space], &output, 1.0).unwrap(); + space::space_render_elements(renderer, [&state.space], &output, 1.0) + .expect("Failed to get render elements"); let mut output_render_elements = Vec::< OutputRenderElements>, diff --git a/src/handlers.rs b/src/handlers.rs index 6715ac9..900a7e2 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -77,7 +77,9 @@ impl CompositorHandler for State { }); if let Some(dmabuf) = maybe_dmabuf { if let Ok((blocker, source)) = dmabuf.generate_blocker(Interest::READ) { - let client = surface.client().unwrap(); + let client = surface + .client() + .expect("Surface has no client/is no longer alive"); let res = state.loop_handle.insert_source(source, move |_, _, data| { data.state .client_compositor_state(&client) @@ -124,7 +126,10 @@ impl CompositorHandler for State { } fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState { - &client.get_data::().unwrap().compositor_state + &client + .get_data::() + .expect("ClientState wasn't in client's data map") + .compositor_state } } delegate_compositor!(@ State); @@ -135,9 +140,9 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State() - .unwrap() + .expect("XdgToplevelSurfaceData wasn't in surface's data map") .lock() - .unwrap() + .expect("Failed to lock Mutex") .initial_configure_sent }); // println!("initial_configure_sent is {}", initial_configure_sent); @@ -155,9 +160,9 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State() - .unwrap() + .expect("XdgPopupSurfaceData wasn't in popup's data map") .lock() - .unwrap() + .expect("Failed to lock Mutex") .initial_configure_sent }); if !initial_configure_sent { @@ -221,11 +226,15 @@ impl XdgShellHandler for State { self.space.map_element(window.clone(), (0, 0), true); self.loop_handle.insert_idle(move |data| { - data.state.seat.get_keyboard().unwrap().set_focus( - &mut data.state, - Some(window.toplevel().wl_surface().clone()), - SERIAL_COUNTER.next_serial(), - ); + data.state + .seat + .get_keyboard() + .expect("Seat had no keyboard") // FIXME: actually handle error + .set_focus( + &mut data.state, + Some(window.toplevel().wl_surface().clone()), + SERIAL_COUNTER.next_serial(), + ); }); let windows: Vec = self.space.elements().cloned().collect(); @@ -245,11 +254,11 @@ impl XdgShellHandler for State { .map(|win| win.toplevel().wl_surface().clone()); self.seat .get_keyboard() - .unwrap() + .expect("Seat had no keyboard") .set_focus(self, focus, SERIAL_COUNTER.next_serial()); } - fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) { + fn new_popup(&mut self, surface: PopupSurface, _positioner: PositionerState) { if let Err(err) = self.popup_manager.track_popup(PopupKind::from(surface)) { tracing::warn!("failed to track popup: {}", err); } @@ -259,7 +268,7 @@ impl XdgShellHandler for State { crate::xdg::request::move_request( self, &surface, - &Seat::from_resource(&seat).unwrap(), + &Seat::from_resource(&seat).expect("Couldn't get seat from WlSeat"), serial, ); } @@ -275,7 +284,7 @@ impl XdgShellHandler for State { crate::xdg::request::resize_request( self, &surface, - &Seat::from_resource(&seat).unwrap(), + &Seat::from_resource(&seat).expect("Couldn't get seat from WlSeat"), serial, edges, BUTTON_LEFT, @@ -296,7 +305,7 @@ impl XdgShellHandler for State { } fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) { - let seat: Seat = Seat::from_resource(&seat).unwrap(); + let seat: Seat = Seat::from_resource(&seat).expect("Couldn't get seat from WlSeat"); let popup_kind = PopupKind::Xdg(surface); if let Some(root) = find_popup_root_surface(&popup_kind) .ok() diff --git a/src/input.rs b/src/input.rs index 309f654..ae1f52d 100644 --- a/src/input.rs +++ b/src/input.rs @@ -53,8 +53,8 @@ impl State { } fn pointer_button(&mut self, event: I::PointerButtonEvent) { - let pointer = self.seat.get_pointer().unwrap(); - let keyboard = self.seat.get_keyboard().unwrap(); + let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err + let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard"); // FIXME: handle err // A serial is a number sent with a event that is sent back to the // server by the clients in further requests. This allows the server to @@ -198,7 +198,10 @@ impl State { frame = frame.stop(Axis::Vertical); } - self.seat.get_pointer().unwrap().axis(self, frame); + self.seat + .get_pointer() + .expect("Seat has no pointer") + .axis(self, frame); // FIXME: handle err } fn keyboard(&mut self, event: I::KeyboardKeyEvent) { @@ -206,58 +209,62 @@ impl State { let time = event.time_msec(); let press_state = event.state(); let mut move_mode = false; - let action = self.seat.get_keyboard().unwrap().input( - self, - event.key_code(), - press_state, - serial, - time, - |state, modifiers, keysym| { - if press_state == KeyState::Pressed { - let mut modifier_mask = Vec::::new(); - if modifiers.alt { - modifier_mask.push(Modifiers::Alt); + let action = self + .seat + .get_keyboard() + .expect("Seat has no keyboard") // FIXME: handle err + .input( + self, + event.key_code(), + press_state, + serial, + time, + |state, modifiers, keysym| { + if press_state == KeyState::Pressed { + let mut modifier_mask = Vec::::new(); + if modifiers.alt { + modifier_mask.push(Modifiers::Alt); + } + if modifiers.shift { + modifier_mask.push(Modifiers::Shift); + } + if modifiers.ctrl { + modifier_mask.push(Modifiers::Ctrl); + } + if modifiers.logo { + modifier_mask.push(Modifiers::Super); + } + if let Some(callback_id) = state + .input_state + .keybinds + .get(&(modifier_mask.into(), keysym.modified_sym())) + { + return FilterResult::Intercept(*callback_id); + } } - if modifiers.shift { - modifier_mask.push(Modifiers::Shift); - } - if modifiers.ctrl { - modifier_mask.push(Modifiers::Ctrl); - } - if modifiers.logo { - modifier_mask.push(Modifiers::Super); - } - if let Some(callback_id) = state - .input_state - .keybinds - .get(&(modifier_mask.into(), keysym.modified_sym())) - { - return FilterResult::Intercept(*callback_id); - } - } - if keysym.modified_sym() == keysyms::KEY_Control_L { - match press_state { - KeyState::Pressed => { - move_mode = true; - } - KeyState::Released => { - move_mode = false; + if keysym.modified_sym() == keysyms::KEY_Control_L { + match press_state { + KeyState::Pressed => { + move_mode = true; + } + KeyState::Released => { + move_mode = false; + } } + FilterResult::Forward + } else { + FilterResult::Forward } - FilterResult::Forward - } else { - FilterResult::Forward - } - }, - ); + }, + ); self.move_mode = move_mode; if let Some(callback_id) = action { if let Some(stream) = self.api_state.stream.as_ref() { if let Err(err) = crate::api::send_to_client( - &mut stream.lock().unwrap(), + &mut stream.lock().expect("Could not lock stream mutex"), &OutgoingMsg::CallCallback { callback_id, args: None, @@ -288,11 +295,14 @@ impl State { } fn pointer_motion_absolute(&mut self, event: I::PointerMotionAbsoluteEvent) { - let output = self.space.outputs().next().unwrap(); - let output_geo = self.space.output_geometry(output).unwrap(); + let Some(output) = self.space.outputs().next() else { return; }; + let output_geo = self + .space + .output_geometry(output) + .expect("Output geometry doesn't exist"); let pointer_loc = event.position_transformed(output_geo.size) + output_geo.loc.to_f64(); let serial = SERIAL_COUNTER.next_serial(); - let pointer = self.seat.get_pointer().unwrap(); + let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err // tracing::info!("pointer_loc: {:?}", pointer_loc); @@ -407,16 +417,35 @@ impl State { let serial = SERIAL_COUNTER.next_serial(); let max_x = self.space.outputs().fold(0, |acc, o| { - acc + self.space.output_geometry(o).unwrap().size.w + acc + self + .space + .output_geometry(o) + .expect("Output geometry doesn't exist") + .size + .w }); - let max_h_output = self + let Some(max_h_output) = self .space .outputs() - .max_by_key(|o| self.space.output_geometry(o).unwrap().size.h) - .unwrap(); + .max_by_key(|o| { + self.space + .output_geometry(o) + .expect("Output geometry doesn't exist") + .size + .h + }) + else { + tracing::warn!("Pointer moved, but there was no output"); + return; + }; - let max_y = self.space.output_geometry(max_h_output).unwrap().size.h; + let max_y = self + .space + .output_geometry(max_h_output) + .expect("Output geometry doesn't exist") + .size + .h; self.pointer_location.x = event.x_transformed(max_x); self.pointer_location.y = event.y_transformed(max_y); @@ -447,17 +476,31 @@ impl State { let (pos_x, pos_y) = pos.into(); let max_x = self.space.outputs().fold(0, |acc, o| { - acc + self.space.output_geometry(o).unwrap().size.w + acc + self + .space + .output_geometry(o) + .expect("Output geometry doesn't exist") + .size + .w }); let clamped_x = pos_x.clamp(0.0, max_x as f64); let max_y = self .space .outputs() .find(|o| { - let geo = self.space.output_geometry(o).unwrap(); + let geo = self + .space + .output_geometry(o) + .expect("Output geometry doesn't exist"); geo.contains((clamped_x as i32, 0)) }) - .map(|o| self.space.output_geometry(o).unwrap().size.h); + .map(|o| { + self.space + .output_geometry(o) + .expect("Output geometry doesn't exist") + .size + .h + }); if let Some(max_y) = max_y { let clamped_y = pos_y.clamp(0.0, max_y as f64); diff --git a/src/main.rs b/src/main.rs index c0c0702..2cc04a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ //! contribute or learn how building something like this works. #![deny(unused_imports)] // gonna force myself to keep stuff clean +#![warn(clippy::unwrap_used)] mod api; mod backend; diff --git a/src/output.rs b/src/output.rs index cec9c3f..6466c13 100644 --- a/src/output.rs +++ b/src/output.rs @@ -24,7 +24,10 @@ impl OutputState { .user_data() .insert_if_missing(|| RefCell::::default); - let state = output.user_data().get::>().unwrap(); + let state = output + .user_data() + .get::>() + .expect("RefCell doesn't exist in data map (This should NEVER happen. If you see this, something oofed big-time.)"); func(&mut state.borrow_mut()) } diff --git a/src/state.rs b/src/state.rs index 00b558e..b8f9742 100644 --- a/src/state.rs +++ b/src/state.rs @@ -115,18 +115,19 @@ impl State { // // To fix this, I just set the limit to be higher. As Pinnacle is the whole graphical // environment, I *think* this is ok. - smithay::reexports::nix::sys::resource::setrlimit( - smithay::reexports::nix::sys::resource::Resource::RLIMIT_NOFILE, - 65536, - 65536 * 2, - ) - .unwrap(); + if let Err(err) = smithay::reexports::nix::sys::resource::setrlimit( + smithay::reexports::nix::sys::resource::Resource::RLIMIT_NOFILE, + 65536, + 65536 * 2, + ) { + tracing::error!("Could not raise fd limit: errno {err}"); + } loop_handle.insert_source(socket, |stream, _metadata, data| { data.display .handle() .insert_client(stream, Arc::new(ClientState::default())) - .unwrap(); + .expect("Could not insert client into loop handle"); })?; loop_handle.insert_source( @@ -180,11 +181,6 @@ impl State { } => { data.state.handle_spawn(command, callback_id); } - Msg::SpawnShell { - shell, - command, - callback_id, - } => todo!(), Msg::MoveToTag { tag } => todo!(), Msg::ToggleTag { tag } => todo!(), @@ -215,9 +211,9 @@ impl State { let lock = states. data_map .get::() - .unwrap() + .expect("XdgToplevelSurfaceData doesn't exist") .lock() - .unwrap(); + .expect("Couldn't lock XdgToplevelSurfaceData"); (lock.app_id.clone(), lock.title.clone()) } ); @@ -234,8 +230,8 @@ impl State { location: location.into(), floating, }; - let stream = data.state.api_state.stream.as_ref().unwrap(); - let mut stream = stream.lock().unwrap(); + let stream = data.state.api_state.stream.as_ref().expect("Stream doesn't exist"); + let mut stream = stream.lock().expect("Couldn't lock stream"); crate::api::send_to_client( &mut stream, &OutgoingMsg::RequestResponse { @@ -243,7 +239,7 @@ impl State { response: RequestResponse::Window { window: props } } ) - .unwrap(); + .expect("Send to client failed"); }, Request::GetAllWindows { id } => { let window_props = data.state.space.elements().map(|win| { @@ -254,9 +250,9 @@ impl State { let lock = states. data_map .get::() - .unwrap() + .expect("XdgToplevelSurfaceData doesn't exist") .lock() - .unwrap(); + .expect("Couldn't lock XdgToplevelSurfaceData"); (lock.app_id.clone(), lock.title.clone()) } ); @@ -264,7 +260,7 @@ impl State { (state.id, state.floating.is_floating()) }); // TODO: unwrap - let location = data.state.space.element_location(win).unwrap(); + let location = data.state.space.element_location(win).expect("Window location doesn't exist"); WindowProperties { id: window_id, app_id, @@ -275,8 +271,9 @@ impl State { } }).collect::>(); - let stream = data.state.api_state.stream.as_ref().unwrap(); - let mut stream = stream.lock().unwrap(); + // FIXME: figure out what to do if error + let stream = data.state.api_state.stream.as_ref().expect("Stream doesn't exist"); + let mut stream = stream.lock().expect("Couldn't lock stream"); crate::api::send_to_client( &mut stream, &OutgoingMsg::RequestResponse { @@ -284,7 +281,7 @@ impl State { response: RequestResponse::GetAllWindows { windows: window_props }, } ) - .unwrap(); + .expect("Couldn't send to client"); } }, }; @@ -305,13 +302,13 @@ impl State { { old_stream .lock() - .unwrap() + .expect("Couldn't lock old stream") .shutdown(std::net::Shutdown::Both) - .unwrap(); + .expect("Couldn't shutdown old stream"); } })?; - let (executor, sched) = calloop::futures::executor::<()>().unwrap(); + let (executor, sched) = calloop::futures::executor::<()>().expect("Couldn't create executor"); loop_handle.insert_source(executor, |_, _, _| {})?; // TODO: move all this into the lua api @@ -324,7 +321,7 @@ impl State { let lua_path = std::env::var("LUA_PATH").expect("Lua is not installed!"); let mut local_lua_path = std::env::current_dir() - .unwrap() + .expect("Couldn't get current dir") .to_string_lossy() .to_string(); local_lua_path.push_str("/api/lua"); // TODO: get from crate root and do dynamically @@ -339,7 +336,7 @@ impl State { .env("LUA_PATH", new_lua_path) .env("LUA_CPATH", new_lua_cpath) .spawn() - .unwrap(); + .expect("Could not start config process"); let display_handle = display.handle(); let mut seat_state = SeatState::new(); @@ -381,13 +378,14 @@ impl State { } pub fn handle_spawn(&self, command: Vec, callback_id: Option) { - let mut command = command.into_iter().peekable(); - if command.peek().is_none() { + let mut command = command.into_iter(); + let Some(program) = command.next() else { // TODO: notify that command was nothing return; - } + }; - let mut child = async_process::Command::new(OsString::from(command.next().unwrap())) + let program = OsString::from(program); + let Ok(mut child) = async_process::Command::new(&program) .env("WAYLAND_DISPLAY", self.socket_name.clone()) .stdin(if callback_id.is_some() { Stdio::piped() @@ -408,13 +406,17 @@ impl State { }) .args(command) .spawn() - .unwrap(); // TODO: handle unwrap + else { + // TODO: notify user that program doesn't exist + tracing::warn!("tried to run {}, but it doesn't exist", program.to_string_lossy()); + return; + }; // TODO: find a way to make this hellish code look better, deal with unwraps if let Some(callback_id) = callback_id { let stdout = child.stdout.take(); let stderr = child.stderr.take(); - let stream_out = self.api_state.stream.as_ref().unwrap().clone(); + let stream_out = self.api_state.stream.as_ref().expect("Stream doesn't exist").clone(); let stream_err = stream_out.clone(); let stream_exit = stream_out.clone(); @@ -427,7 +429,7 @@ impl State { match reader.read_line(&mut buf).await { Ok(0) => break, Ok(_) => { - let mut stream = stream_out.lock().unwrap(); + let mut stream = stream_out.lock().expect("Couldn't lock stream"); crate::api::send_to_client( &mut stream, &OutgoingMsg::CallCallback { @@ -440,7 +442,7 @@ impl State { }), }, ) - .unwrap(); + .expect("Send to client failed"); // TODO: notify instead of crash } Err(err) => { tracing::warn!("child read err: {err}"); @@ -449,7 +451,11 @@ impl State { } } }; - self.async_scheduler.schedule(future).unwrap(); + + // This is not important enough to crash on error, so just print the error instead + if let Err(err) = self.async_scheduler.schedule(future) { + tracing::error!("Failed to schedule future: {err}"); + } } if let Some(stderr) = stderr { let future = async move { @@ -459,7 +465,7 @@ impl State { match reader.read_line(&mut buf).await { Ok(0) => break, Ok(_) => { - let mut stream = stream_err.lock().unwrap(); + let mut stream = stream_err.lock().expect("Couldn't lock stream"); crate::api::send_to_client( &mut stream, &OutgoingMsg::CallCallback { @@ -472,7 +478,7 @@ impl State { }), }, ) - .unwrap(); + .expect("Send to client failed"); // TODO: notify instead of crash } Err(err) => { tracing::warn!("child read err: {err}"); @@ -481,13 +487,15 @@ impl State { } } }; - self.async_scheduler.schedule(future).unwrap(); + if let Err(err) = self.async_scheduler.schedule(future) { + tracing::error!("Failed to schedule future: {err}"); + } } let future = async move { match child.status().await { Ok(exit_status) => { - let mut stream = stream_exit.lock().unwrap(); + let mut stream = stream_exit.lock().expect("Couldn't lock stream"); crate::api::send_to_client( &mut stream, &OutgoingMsg::CallCallback { @@ -500,14 +508,16 @@ impl State { }), }, ) - .unwrap() + .expect("Send to client failed"); // TODO: notify instead of crash } Err(err) => { tracing::warn!("child wait() err: {err}"); } } }; - self.async_scheduler.schedule(future).unwrap(); + if let Err(err) = self.async_scheduler.schedule(future) { + tracing::error!("Failed to schedule future: {err}"); + } } } } diff --git a/src/window.rs b/src/window.rs index b7cba99..71d54e7 100644 --- a/src/window.rs +++ b/src/window.rs @@ -34,7 +34,10 @@ pub trait SurfaceState: Default + 'static { { compositor::with_states(wl_surface, |states| { states.data_map.insert_if_missing(RefCell::::default); - let state = states.data_map.get::>().unwrap(); + let state = states + .data_map + .get::>() + .expect("This should never happen"); function(&mut state.borrow_mut()) }) diff --git a/src/window/window_state.rs b/src/window/window_state.rs index b2b05cf..5e521a0 100644 --- a/src/window/window_state.rs +++ b/src/window/window_state.rs @@ -119,7 +119,7 @@ impl WindowState { let mut state = window .user_data() .get::>() - .unwrap() + .expect("This should never happen") .borrow_mut(); func(&mut state) }