Add unwrap warning, deal with some unwraps

This commit is contained in:
Seaotatop 2023-06-29 17:41:08 -05:00
parent d6504b0b82
commit 2b50e7d31a
11 changed files with 210 additions and 140 deletions

View file

@ -54,14 +54,17 @@ use self::msg::{Msg, OutgoingMsg};
const SOCKET_PATH: &str = "/tmp/pinnacle_socket";
fn handle_client(mut stream: UnixStream, sender: Sender<Msg>) {
fn handle_client(
mut stream: UnixStream,
sender: Sender<Msg>,
) -> Result<(), Box<dyn std::error::Error>> {
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<Msg>) {
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}");
}
});
}

View file

@ -52,14 +52,6 @@ pub enum Msg {
callback_id: Option<CallbackId>,
},
/// Run a command using the optionally specified shell and callback.
SpawnShell {
shell: Option<String>,
command: Vec<String>,
#[serde(default)]
callback_id: Option<CallbackId>,
},
// Pinnacle management
/// Quit the compositor.
Quit,

View file

@ -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,

View file

@ -142,7 +142,7 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
.collect::<Vec<_>>();
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<dyn Error>> {
states
.data_map
.get::<Mutex<CursorImageAttributes>>()
.unwrap()
.expect("Mutex<CursorImageAttributes> wasn't in the data map")
.lock()
.unwrap()
.expect("Failed to lock Mutex<CursorImageAttributes>")
.hotspot
})
} else {
@ -291,7 +291,8 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
// 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<GlesRenderer, WaylandSurfaceRenderElement<GlesRenderer>>,

View file

@ -77,7 +77,9 @@ impl<B: Backend> CompositorHandler for State<B> {
});
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<B: Backend> CompositorHandler for State<B> {
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
&client.get_data::<ClientState>().unwrap().compositor_state
&client
.get_data::<ClientState>()
.expect("ClientState wasn't in client's data map")
.compositor_state
}
}
delegate_compositor!(@<B: Backend> State<B>);
@ -135,9 +140,9 @@ fn ensure_initial_configure<B: Backend>(surface: &WlSurface, state: &mut State<B
states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
.lock()
.unwrap()
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.initial_configure_sent
});
// println!("initial_configure_sent is {}", initial_configure_sent);
@ -155,9 +160,9 @@ fn ensure_initial_configure<B: Backend>(surface: &WlSurface, state: &mut State<B
states
.data_map
.get::<XdgPopupSurfaceData>()
.unwrap()
.expect("XdgPopupSurfaceData wasn't in popup's data map")
.lock()
.unwrap()
.expect("Failed to lock Mutex<XdgPopupSurfaceData>")
.initial_configure_sent
});
if !initial_configure_sent {
@ -221,11 +226,15 @@ impl<B: Backend> XdgShellHandler for State<B> {
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<Window> = self.space.elements().cloned().collect();
@ -245,11 +254,11 @@ impl<B: Backend> XdgShellHandler for State<B> {
.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<B: Backend> XdgShellHandler for State<B> {
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<B: Backend> XdgShellHandler for State<B> {
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<B: Backend> XdgShellHandler for State<B> {
}
fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) {
let seat: Seat<Self> = Seat::from_resource(&seat).unwrap();
let seat: Seat<Self> = 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()

View file

@ -53,8 +53,8 @@ impl<B: Backend> State<B> {
}
fn pointer_button<I: InputBackend>(&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<B: Backend> State<B> {
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<I: InputBackend>(&mut self, event: I::KeyboardKeyEvent) {
@ -206,58 +209,62 @@ impl<B: Backend> State<B> {
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::<Modifiers>::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::<Modifiers>::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<WinitData> {
}
fn pointer_motion_absolute<I: InputBackend>(&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<UdevData> {
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<UdevData> {
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);

View file

@ -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;

View file

@ -24,7 +24,10 @@ impl OutputState {
.user_data()
.insert_if_missing(|| RefCell::<Self>::default);
let state = output.user_data().get::<RefCell<Self>>().unwrap();
let state = output
.user_data()
.get::<RefCell<Self>>()
.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())
}

View file

@ -115,18 +115,19 @@ impl<B: Backend> State<B> {
//
// 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<B: Backend> State<B> {
} => {
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<B: Backend> State<B> {
let lock = states.
data_map
.get::<XdgToplevelSurfaceData>()
.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<B: Backend> State<B> {
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<B: Backend> State<B> {
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<B: Backend> State<B> {
let lock = states.
data_map
.get::<XdgToplevelSurfaceData>()
.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<B: Backend> State<B> {
(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<B: Backend> State<B> {
}
}).collect::<Vec<_>>();
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<B: Backend> State<B> {
response: RequestResponse::GetAllWindows { windows: window_props },
}
)
.unwrap();
.expect("Couldn't send to client");
}
},
};
@ -305,13 +302,13 @@ impl<B: Backend> State<B> {
{
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<B: Backend> State<B> {
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<B: Backend> State<B> {
.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<B: Backend> State<B> {
}
pub fn handle_spawn(&self, command: Vec<String>, callback_id: Option<CallbackId>) {
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<B: Backend> State<B> {
})
.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<B: Backend> State<B> {
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<B: Backend> State<B> {
}),
},
)
.unwrap();
.expect("Send to client failed"); // TODO: notify instead of crash
}
Err(err) => {
tracing::warn!("child read err: {err}");
@ -449,7 +451,11 @@ impl<B: Backend> State<B> {
}
}
};
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<B: Backend> State<B> {
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<B: Backend> State<B> {
}),
},
)
.unwrap();
.expect("Send to client failed"); // TODO: notify instead of crash
}
Err(err) => {
tracing::warn!("child read err: {err}");
@ -481,13 +487,15 @@ impl<B: Backend> State<B> {
}
}
};
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<B: Backend> State<B> {
}),
},
)
.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}");
}
}
}
}

View file

@ -34,7 +34,10 @@ pub trait SurfaceState: Default + 'static {
{
compositor::with_states(wl_surface, |states| {
states.data_map.insert_if_missing(RefCell::<Self>::default);
let state = states.data_map.get::<RefCell<Self>>().unwrap();
let state = states
.data_map
.get::<RefCell<Self>>()
.expect("This should never happen");
function(&mut state.borrow_mut())
})

View file

@ -119,7 +119,7 @@ impl WindowState {
let mut state = window
.user_data()
.get::<RefCell<Self>>()
.unwrap()
.expect("This should never happen")
.borrow_mut();
func(&mut state)
}