1
0
Fork 0
forked from wry/wry

output: pre-compute OutputId hash

This commit is contained in:
Julian Orth 2026-04-05 14:15:38 +02:00 committed by kossLAN
parent 9bd7e14b08
commit 6e9adc487e
No known key found for this signature in database
8 changed files with 88 additions and 40 deletions

View file

@ -1311,12 +1311,7 @@ fn create_connector_display_data(
}
}
}
let output_id = Rc::new(OutputId::new(
connector_id.to_string(),
manufacturer,
name,
serial_number,
));
let output_id = OutputId::new(connector_id.to_string(), manufacturer, name, serial_number);
let first_mode = info
.modes
.first()

View file

@ -591,12 +591,12 @@ impl XBackend {
.push(BackendEvent::NewConnector(output.clone()));
output.events.push(ConnectorEvent::Connected(MonitorInfo {
modes: Some(vec![]),
output_id: Rc::new(OutputId::new(
String::new(),
"X.Org Foundation".to_string(),
output_id: OutputId::new(
"",
"X.Org Foundation",
format!("X-Window-{}", output.window),
output.window.to_string(),
)),
),
width_mm: output.width.get(),
height_mm: output.height.get(),
non_desktop: false,

View file

@ -686,12 +686,7 @@ fn init_fd_limit() {
}
fn create_dummy_output(state: &Rc<State>) {
let output_id = Rc::new(OutputId {
connector: Some("jay-dummy-connector".to_string()),
manufacturer: "jay".to_string(),
model: "jay-dummy-output".to_string(),
serial_number: "".to_string(),
});
let output_id = OutputId::new("jay-dummy-connector", "jay", "jay-dummy-output", "");
let persistent_state = Rc::new(PersistentOutputState::default());
let id = state.connector_ids.next();
let connector = Rc::new(DummyOutput { id }) as Rc<dyn Connector>;

View file

@ -33,6 +33,7 @@ use {
std::{
cell::{Cell, RefCell},
collections::hash_map::Entry,
hash::{Hash, Hasher},
rc::Rc,
},
thiserror::Error,
@ -164,27 +165,67 @@ impl Default for PersistentOutputState {
}
}
#[derive(Eq, PartialEq, Hash, Debug)]
#[derive(Eq, Debug)]
pub struct OutputId {
pub connector: Option<String>,
pub _connector: Option<String>,
pub manufacturer: String,
pub model: String,
pub serial_number: String,
pub hash: OutputIdHash,
}
hash_type!(OutputIdHash);
impl PartialEq for OutputId {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl Hash for OutputId {
fn hash<H: Hasher>(&self, state: &mut H) {
self.hash.hash(state);
}
}
impl OutputId {
pub fn new(
connector: impl Into<String>,
manufacturer: impl Into<String>,
model: impl Into<String>,
serial_number: impl Into<String>,
) -> Rc<Self> {
let connector = connector.into();
let manufacturer = manufacturer.into();
let model = model.into();
let serial_number = serial_number.into();
Self::new_(connector, manufacturer, model, serial_number)
}
fn new_(
connector: String,
manufacturer: String,
model: String,
serial_number: String,
) -> Self {
Self {
connector: serial_number.is_empty().then_some(connector),
) -> Rc<Self> {
let connector = serial_number.is_empty().then_some(connector);
let mut hasher = blake3::Hasher::new();
hasher.update(&[connector.is_some() as u8]);
let mut hash = |s: &str| {
hasher.update(&(s.len() as u64).to_le_bytes());
hasher.update(s.as_bytes());
};
connector.as_deref().map(&mut hash);
hash(&manufacturer);
hash(&model);
hash(&serial_number);
Rc::new(Self {
_connector: connector,
manufacturer,
model,
serial_number,
}
hash: OutputIdHash(*hasher.finalize().as_bytes()),
})
}
}

View file

@ -154,12 +154,7 @@ impl TestBackend {
});
let default_monitor_info = MonitorInfo {
modes: Some(vec![mode]),
output_id: Rc::new(OutputId {
connector: None,
manufacturer: "jay".to_string(),
model: "TestConnector".to_string(),
serial_number: default_connector.id.to_string(),
}),
output_id: OutputId::new("", "jay", "TestConnector", default_connector.id.to_string()),
width_mm: 80,
height_mm: 60,
non_desktop: false,

View file

@ -54,12 +54,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
});
let new_monitor_info = MonitorInfo {
modes: Some(vec![]),
output_id: Rc::new(OutputId {
connector: None,
manufacturer: "jay".to_string(),
model: "jay second connector".to_string(),
serial_number: "".to_string(),
}),
output_id: OutputId::new("", "jay", "jay second connector", ""),
width_mm: 0,
height_mm: 0,
non_desktop: false,

View file

@ -933,3 +933,35 @@ macro_rules! opaque {
}
};
}
macro_rules! hash_type {
($name:ident) => {
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct $name(pub [u8; 32]);
impl $name {
#[allow(clippy::allow_attributes, dead_code)]
pub fn hash(t: impl AsRef<[u8]>) -> Self {
Self(*blake3::hash(t.as_ref()).as_bytes())
}
}
impl serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<[u8; 32]>::deserialize(deserializer).map(Self)
}
}
};
}

View file

@ -258,12 +258,7 @@ impl VirtualOutputs {
state: state.clone(),
id,
kernel_id,
output_id: Rc::new(OutputId::new(
kernel_id.to_string(),
"Jay".to_string(),
"VirtualOutput".to_string(),
name.to_string(),
)),
output_id: OutputId::new(kernel_id.to_string(), "Jay", "VirtualOutput", name),
name: format!("VO-{}", name),
frontend_state: Default::default(),
needs_format_update: Default::default(),