diff --git a/mm-server/src/compositor.rs b/mm-server/src/compositor.rs index 7e3db61..c3f1555 100644 --- a/mm-server/src/compositor.rs +++ b/mm-server/src/compositor.rs @@ -22,6 +22,7 @@ mod video; mod xwayland; use std::{ + collections::BTreeMap, ffi::{OsStr, OsString}, fs::File, io::{BufRead, BufReader}, @@ -36,7 +37,6 @@ use child::*; pub use control::*; use crossbeam_channel as crossbeam; pub use handle::*; -use hashbrown::HashMap; pub use input::GamepadLayout; use lazy_static::lazy_static; use protocols::*; @@ -121,7 +121,7 @@ pub struct State { default_seat: seat::Seat, input_manager: input::InputDeviceManager, - gamepads: HashMap, + gamepads: BTreeMap, app_config: AppConfig, display_params: DisplayParams, @@ -138,7 +138,7 @@ pub struct State { audio_pipeline: audio::EncodePipeline, xwm: Option, - xwayland_surface_lookup: HashMap, + xwayland_surface_lookup: BTreeMap, // At the bottom for drop order. vk: Arc, @@ -226,7 +226,7 @@ impl Compositor { // Set up input emulation (this is just for gamepads). let mut input_manager = input::InputDeviceManager::new(&mut container)?; - let mut gamepads = HashMap::new(); + let mut gamepads = BTreeMap::new(); for (pad_id, layout) in permanent_gamepads { let dev = input_manager.plug_gamepad(pad_id, layout, true)?; @@ -265,7 +265,7 @@ impl Compositor { audio_pipeline, xwm: None, - xwayland_surface_lookup: HashMap::default(), + xwayland_surface_lookup: BTreeMap::default(), vk, }; @@ -1007,19 +1007,17 @@ impl Compositor { self.state.default_seat.lift_pointer(&self.state.serial); } ControlMessage::GamepadAvailable(id) => { - if !self.state.gamepads.contains_key(&id) { - self.state.gamepads.insert( + use std::collections::btree_map::Entry; + if let Entry::Vacant(e) = self.state.gamepads.entry(id) { + e.insert(self.state.input_manager.plug_gamepad( id, - self.state.input_manager.plug_gamepad( - id, - input::GamepadLayout::GenericDualStick, - false, - )?, - ); + input::GamepadLayout::GenericDualStick, + false, + )?); } } ControlMessage::GamepadUnavailable(id) => { - use hashbrown::hash_map::Entry; + use std::collections::btree_map::Entry; match self.state.gamepads.entry(id) { Entry::Occupied(v) if !v.get().permanent => { v.remove(); diff --git a/mm-server/src/compositor/audio/pulse.rs b/mm-server/src/compositor/audio/pulse.rs index fa2f0a6..ad6ef3e 100644 --- a/mm-server/src/compositor/audio/pulse.rs +++ b/mm-server/src/compositor/audio/pulse.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: BUSL-1.1 use std::{ - collections::VecDeque, + collections::{BTreeMap, VecDeque}, ffi::{CStr, CString}, io::{prelude::*, Cursor}, path::Path, @@ -15,7 +15,6 @@ use anyhow::{bail, Context}; use bytes::BytesMut; use crossbeam_channel as crossbeam; use cstr::cstr; -use hashbrown::HashMap; use mio::net::UnixListener; use pulseaudio::protocol::{self as pulse, ClientInfoList}; use tracing::{debug, error, trace, warn}; @@ -62,7 +61,7 @@ struct Client { protocol_version: u16, props: Option, incoming: BytesMut, - playback_streams: HashMap, + playback_streams: BTreeMap, } struct ServerState { @@ -82,7 +81,7 @@ pub struct PulseServer { unencoded_tx: crossbeam::Sender, done_rx: crossbeam::Receiver, - clients: HashMap, + clients: BTreeMap, server_state: ServerState, } @@ -188,7 +187,7 @@ impl PulseServer { unencoded_tx, done_rx, close_rx, - clients: HashMap::new(), + clients: BTreeMap::new(), server_state: ServerState { server_info, cards: vec![], // vec![dummy_card], @@ -258,7 +257,7 @@ impl PulseServer { protocol_version: pulse::MAX_VERSION, props: None, incoming: BytesMut::new(), - playback_streams: HashMap::new(), + playback_streams: BTreeMap::new(), }, ); } diff --git a/mm-server/src/compositor/child/container.rs b/mm-server/src/compositor/child/container.rs index 16f6e60..10b46e2 100644 --- a/mm-server/src/compositor/child/container.rs +++ b/mm-server/src/compositor/child/container.rs @@ -825,7 +825,7 @@ fn sync_barrier(barrier: &ipc::EventfdBarrier) -> rustix::io::Result<()> { #[cfg(test)] mod test { - use std::{collections::HashMap, fs::File, io::Read as _}; + use std::{fs::File, io::Read as _}; use rustix::pipe::{pipe_with, PipeFlags}; @@ -839,7 +839,7 @@ mod test { let app_config = AppConfig { description: None, command: vec!["echo".to_owned().into(), "done".to_owned().into()], - env: HashMap::new(), + env: Default::default(), xwayland: false, force_1x_scale: false, home_isolation_mode: HomeIsolationMode::Unisolated, diff --git a/mm-server/src/compositor/handle.rs b/mm-server/src/compositor/handle.rs index 4ec0fac..87b5f9d 100644 --- a/mm-server/src/compositor/handle.rs +++ b/mm-server/src/compositor/handle.rs @@ -2,16 +2,18 @@ // // SPDX-License-Identifier: BUSL-1.1 -use std::sync::{Arc, RwLock}; +use std::{ + collections::BTreeMap, + sync::{Arc, RwLock}, +}; use crossbeam_channel as crossbeam; -use hashbrown::HashMap; use super::CompositorEvent; #[derive(Debug, Clone)] struct Inner { - attachments: HashMap>, + attachments: BTreeMap>, } #[derive(Debug, Clone)] @@ -21,7 +23,7 @@ impl CompositorHandle { pub fn new(waker: Arc) -> Self { Self( Arc::new(RwLock::new(Inner { - attachments: HashMap::new(), + attachments: BTreeMap::new(), })), waker, ) @@ -52,7 +54,7 @@ impl CompositorHandle { pub fn kick_clients(&self) { let attachments = &mut self.0.write().unwrap().attachments; - for (_, sender) in attachments.drain() { + for (_, sender) in std::mem::take(attachments) { sender.send(CompositorEvent::Shutdown).ok(); } } diff --git a/mm-server/src/compositor/input.rs b/mm-server/src/compositor/input.rs index 9af2549..2ecce0a 100644 --- a/mm-server/src/compositor/input.rs +++ b/mm-server/src/compositor/input.rs @@ -232,7 +232,7 @@ impl InputDeviceManager { #[cfg(test)] mod test { - use std::{collections::HashMap, fs::File, io::Read as _}; + use std::{fs::File, io::Read as _}; use rustix::pipe::{pipe_with, PipeFlags}; @@ -255,7 +255,7 @@ mod test { let app_config = AppConfig { description: None, command, - env: HashMap::new(), + env: Default::default(), xwayland: false, force_1x_scale: false, home_isolation_mode: HomeIsolationMode::Unisolated, diff --git a/mm-server/src/compositor/input/udevfs.rs b/mm-server/src/compositor/input/udevfs.rs index 794f5b0..9996abe 100644 --- a/mm-server/src/compositor/input/udevfs.rs +++ b/mm-server/src/compositor/input/udevfs.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: BUSL-1.1 -use std::{collections::HashMap, path::PathBuf, str::FromStr as _, sync::Arc, time}; +use std::{collections::BTreeMap, path::PathBuf, str::FromStr as _, sync::Arc, time}; use fuser as fuse; use libc::EBADF; @@ -125,14 +125,14 @@ impl TryFrom for DeviceInode { /// device. pub struct UdevFs { state: Arc>, - static_inodes: HashMap, // Indexed by inode. + static_inodes: BTreeMap, // Indexed by inode. } impl UdevFs { pub fn new(state: Arc>) -> Self { let ctime = time::SystemTime::now(); - let mut static_inodes: HashMap = HashMap::new(); + let mut static_inodes: BTreeMap = BTreeMap::new(); for (idx, entry) in STATIC_DIRS.iter().enumerate() { let mut relpath = PathBuf::from_str(entry).unwrap(); diff --git a/mm-server/src/compositor/video/vulkan_encode/dpb.rs b/mm-server/src/compositor/video/vulkan_encode/dpb.rs index 3b3803c..ed479dd 100644 --- a/mm-server/src/compositor/video/vulkan_encode/dpb.rs +++ b/mm-server/src/compositor/video/vulkan_encode/dpb.rs @@ -2,10 +2,9 @@ // // SPDX-License-Identifier: BUSL-1.1 -use std::sync::Arc; +use std::{collections::BTreeMap, sync::Arc}; use ash::vk; -use hashbrown::HashMap; use crate::vulkan::*; @@ -22,7 +21,7 @@ pub struct DpbPicture { pub struct DpbPool { _store: Vec, slots: Vec, - ids: HashMap, + ids: BTreeMap, } impl DpbPool { @@ -58,7 +57,7 @@ impl DpbPool { Ok(Self { _store: vec![image], slots, - ids: HashMap::new(), + ids: BTreeMap::new(), }) } @@ -93,7 +92,7 @@ impl DpbPool { Ok(Self { _store: store, slots, - ids: HashMap::new(), + ids: BTreeMap::new(), }) } diff --git a/mm-server/src/compositor/xwayland/xwm.rs b/mm-server/src/compositor/xwayland/xwm.rs index cc41e73..be68530 100644 --- a/mm-server/src/compositor/xwayland/xwm.rs +++ b/mm-server/src/compositor/xwayland/xwm.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: BUSL-1.1 use std::{ - collections::HashMap, + collections::BTreeMap, os::fd::{AsFd as _, BorrowedFd}, }; @@ -116,8 +116,8 @@ pub struct Xwm { client_list: Vec, client_list_stacking: Vec, - pub xwindows: HashMap, - pub serials: HashMap, + pub xwindows: BTreeMap, + pub serials: BTreeMap, } impl Xwm { @@ -219,8 +219,8 @@ impl Xwm { client_list: Vec::new(), client_list_stacking: Vec::new(), - xwindows: HashMap::new(), - serials: HashMap::new(), + xwindows: BTreeMap::new(), + serials: BTreeMap::new(), }) } diff --git a/mm-server/src/config.rs b/mm-server/src/config.rs index e76f8d7..49d1477 100644 --- a/mm-server/src/config.rs +++ b/mm-server/src/config.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: BUSL-1.1 use std::{ - collections::HashMap, + collections::BTreeMap, ffi::{OsStr, OsString}, net::ToSocketAddrs, num::NonZeroU32, @@ -23,7 +23,7 @@ lazy_static! { /// Serde representations of the configuration files. mod parsed { - use std::{collections::HashMap, num::NonZeroU32, path::PathBuf}; + use std::{collections::BTreeMap, num::NonZeroU32, path::PathBuf}; use converge::Converge; use serde::Deserialize; @@ -65,7 +65,7 @@ mod parsed { #[derive(Debug, Clone, PartialEq, Deserialize, Converge)] pub(super) struct Config { pub(super) include_apps: Option>, - pub(super) apps: Option>, + pub(super) apps: Option>, pub(super) data_home: Option, @@ -100,7 +100,7 @@ mod parsed { pub(super) struct AppConfig { pub(super) description: Option, pub(super) command: Vec, - pub(super) environment: Option>, + pub(super) environment: Option>, pub(super) xwayland: Option, pub(super) force_1x_scale: Option, pub(super) isolate_home: Option, @@ -112,7 +112,7 @@ mod parsed { #[derive(Debug, Clone, PartialEq)] pub struct Config { pub server: ServerConfig, - pub apps: HashMap, + pub apps: BTreeMap, pub data_home: PathBuf, pub bug_report_dir: Option, @@ -132,7 +132,7 @@ pub struct ServerConfig { pub struct AppConfig { pub description: Option, pub command: Vec, - pub env: HashMap, + pub env: BTreeMap, pub xwayland: bool, pub force_1x_scale: bool, pub home_isolation_mode: HomeIsolationMode, @@ -218,8 +218,8 @@ impl Config { }, }, data_home: data_home.clone(), - apps: HashMap::new(), // Handled below. - bug_report_dir: None, // This is only set from the command line. + apps: BTreeMap::new(), // Handled below. + bug_report_dir: None, // This is only set from the command line. }; // Collect additional app definitions from app_dirs. @@ -409,7 +409,7 @@ mod test { static ref EXAMPLE_APP: AppConfig = AppConfig { description: None, command: vec!["echo".to_owned().into(), "hello".to_owned().into()], - env: HashMap::new(), + env: Default::default(), xwayland: true, force_1x_scale: false, home_isolation_mode: HomeIsolationMode::Unisolated, diff --git a/mm-server/src/server.rs b/mm-server/src/server.rs index 65509b1..271eaa7 100644 --- a/mm-server/src/server.rs +++ b/mm-server/src/server.rs @@ -5,7 +5,7 @@ mod handlers; mod sendmmsg; -use std::collections::{HashMap, VecDeque}; +use std::collections::{BTreeMap, VecDeque}; use std::net::SocketAddr; use std::sync::Arc; @@ -14,6 +14,7 @@ use anyhow::bail; use anyhow::Context; use bytes::{Buf, Bytes, BytesMut}; use crossbeam_channel::{Receiver, Sender, TryRecvError}; +use hashbrown::HashMap; use mm_protocol as protocol; use protocol::error::ErrorCode; use ring::rand::{self, SecureRandom}; @@ -69,9 +70,9 @@ pub struct ClientConnection { conn: quiche::Connection, timer: mio_timerfd::TimerFd, timeout_token: mio::Token, - partial_reads: HashMap, - partial_writes: HashMap, - in_flight: HashMap, + partial_reads: BTreeMap, + partial_writes: BTreeMap, + in_flight: BTreeMap, dgram_recv: Receiver, dgram_send: WakingSender, } @@ -448,7 +449,7 @@ impl Server { mio::Interest::READABLE, )?; - let streams = HashMap::new(); + let streams = BTreeMap::new(); let (dgram_send, dgram_recv) = crossbeam_channel::unbounded(); let dgram_send = WakingSender::new(self.waker.clone(), dgram_send); @@ -460,8 +461,8 @@ impl Server { timer, timeout_token, in_flight: streams, - partial_reads: HashMap::new(), - partial_writes: HashMap::new(), + partial_reads: BTreeMap::new(), + partial_writes: BTreeMap::new(), dgram_recv, dgram_send, }; @@ -723,7 +724,7 @@ impl ClientConnection { /// Flushes previous partial writes. fn flush_partial_write(&mut self, sid: u64) -> anyhow::Result { - use std::collections::hash_map::Entry; + use std::collections::btree_map::Entry; match self.partial_writes.entry(sid) { Entry::Vacant(_) => Ok(true), diff --git a/mm-server/src/server/handlers.rs b/mm-server/src/server/handlers.rs index ad5ca52..72dac67 100644 --- a/mm-server/src/server/handlers.rs +++ b/mm-server/src/server/handlers.rs @@ -2,10 +2,9 @@ // // SPDX-License-Identifier: BUSL-1.1 -use std::time; +use std::{collections::BTreeMap, time}; use crossbeam_channel::{select, Receiver}; -use hashbrown::HashMap; use mm_protocol as protocol; use protocol::error::ErrorCode; use tracing::{debug, debug_span, error, trace}; @@ -387,7 +386,7 @@ fn attach( let mut pointer_lock = None; let mut debug_outputs = if bug_report_dir.is_some() { - Some(HashMap::::new()) + Some(BTreeMap::::new()) } else { None }; diff --git a/mm-server/src/state.rs b/mm-server/src/state.rs index 3102774..aae53ad 100644 --- a/mm-server/src/state.rs +++ b/mm-server/src/state.rs @@ -16,6 +16,8 @@ pub type SharedState = Arc>; const DEFAULT_SESSION_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10 * 60); pub struct ServerState { + // TODO: we'd rather use a BTreeMap, but we want + // hash_brown::HashMap::extract_if. pub sessions: HashMap, pub cfg: Config, pub vk: Arc,