Use PropertyDescriptorWrapper for json output
Some checks failed
Rust / build-macos (push) Has been cancelled
Rust / build-windows (push) Has been cancelled
Rust / build-linux (push) Failing after 14s
Rust / publish-aur (push) Has been skipped

This commit is contained in:
2026-05-14 13:45:38 +00:00
parent aa6168126d
commit 0af9feaa40
3 changed files with 90 additions and 57 deletions

View File

@@ -234,37 +234,52 @@ fn main() {
let properties = &device.get_device_state().device_properties;
let mut headset_info_string = "{\n".to_string();
macro_rules! append_json_property {
($val:expr, $name:ident) => {
if let Some($name) = $val {
headset_info_string +=
&format!(" \"{}\": \"{}\",\n", stringify!($name), $name);
let mut json_properties: Vec<String> = properties
.get_properties()
.iter()
.map(|property| match property {
hyper_headset::devices::PropertyDescriptorWrapper::Int(
property_descriptor,
_items,
) => match property_descriptor.data {
Some(data) => format!(" \"{}\": {},\n", property_descriptor.name, data),
_ => "".to_string(),
},
hyper_headset::devices::PropertyDescriptorWrapper::Bool(
property_descriptor,
) => match property_descriptor.data {
Some(data) => format!(" \"{}\": {},\n", property_descriptor.name, data),
_ => "".to_string(),
},
hyper_headset::devices::PropertyDescriptorWrapper::String(
property_descriptor,
) => match &property_descriptor.data {
Some(data) => {
format!(" \"{}\": \"{}\",\n", property_descriptor.name, data)
}
_ => "".to_string(),
},
})
.collect();
// The last property needs to end without a comma
match json_properties.last_mut() {
#[allow(unused_assignments)]
Some(mut json_property) => {
let mut last_property = json_property[0..(json_property.len() - 2)].to_string();
last_property += "\n";
json_property = &mut last_property;
}
None => {
// Unreachable:
// The program exits if no device is found
// but also has a property for the device being connected
unreachable!();
}
};
}
append_json_property!(&properties.device_name, device_name);
append_json_property!(properties.battery_level, battery_level);
append_json_property!(properties.charging, charging);
append_json_property!(properties.muted, muted);
append_json_property!(properties.mic_connected, mic_connected);
append_json_property!(properties.pairing_info, pairing_info);
append_json_property!(properties.product_color, product_color);
append_json_property!(properties.side_tone_on, side_tone_on);
append_json_property!(properties.side_tone_volume, side_tone_volume);
append_json_property!(properties.surround_sound, surround_sound);
append_json_property!(properties.voice_prompt_on, voice_prompt_on);
append_json_property!(properties.connected, connected);
append_json_property!(properties.silent, silent);
append_json_property!(properties.noise_gate_active, noise_gate_active);
// This is the last property so it shouldn't have a comma at the end
// Durations also do not implement `Display` so this needs to be output manually
if let Some(automatic_shutdown_interval) = properties.automatic_shutdown_after {
headset_info_string += &format!(
" \"automatic_shutdown_interval\": \"{}\"\n",
automatic_shutdown_interval.as_secs()
);
for json_property in json_properties {
headset_info_string += &json_property;
}
headset_info_string += "}";

View File

@@ -379,7 +379,8 @@ pub enum PropertyDescriptorWrapper {
}
pub struct PropertyDescriptor<T: 'static> {
pub prefix: &'static str,
pub name: &'static str,
pub pretty_name: &'static str,
pub data: Option<T>,
pub suffix: &'static str,
pub property_type: PropertyType,
@@ -389,7 +390,7 @@ pub struct PropertyDescriptor<T: 'static> {
impl<T: Debug> Debug for PropertyDescriptor<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PropertyDescriptor")
.field("prefix", &self.prefix)
.field("pretty_name", &self.pretty_name)
.field("data", &self.data)
.field("suffix", &self.suffix)
.field("property_type", &self.property_type)
@@ -432,7 +433,8 @@ impl DeviceProperties {
pub fn get_properties(&self) -> Vec<PropertyDescriptorWrapper> {
vec![
PropertyDescriptorWrapper::String(PropertyDescriptor {
prefix: "Charging status:",
name: "charging_status",
pretty_name: "Charging status",
data: self.charging.map(|c| c.to_string()),
suffix: "",
property_type: PropertyType::AlwaysReadOnly,
@@ -440,7 +442,8 @@ impl DeviceProperties {
}),
PropertyDescriptorWrapper::Int(
PropertyDescriptor {
prefix: "Battery level:",
name: "battery_level",
pretty_name: "Battery level:",
data: self.battery_level,
suffix: "%",
property_type: PropertyType::AlwaysReadOnly,
@@ -449,7 +452,8 @@ impl DeviceProperties {
&[],
),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Muted:",
name: "mic_muted",
pretty_name: "Muted:",
data: self.muted,
suffix: "",
property_type: if self.can_set_mute {
@@ -460,7 +464,8 @@ impl DeviceProperties {
create_event: &move |mute| Some(DeviceEvent::Muted(mute)),
}),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Mic connected:",
name: "mic_connected",
pretty_name: "Mic connected:",
data: self.mic_connected,
suffix: "",
property_type: PropertyType::AlwaysReadOnly,
@@ -468,7 +473,8 @@ impl DeviceProperties {
}),
PropertyDescriptorWrapper::Int(
PropertyDescriptor {
prefix: "Automatic shutdown after:",
name: "automatic_shutdown_interval",
pretty_name: "Automatic shutdown after:",
data: self
.automatic_shutdown_after
.map(|t| (t.as_secs() / 60) as u8),
@@ -488,7 +494,8 @@ impl DeviceProperties {
),
PropertyDescriptorWrapper::Int(
PropertyDescriptor {
prefix: "Pairing info:",
name: "pairing_info",
pretty_name: "Pairing info:",
data: self.pairing_info,
suffix: "",
property_type: PropertyType::AlwaysReadOnly,
@@ -497,14 +504,16 @@ impl DeviceProperties {
&[],
),
PropertyDescriptorWrapper::String(PropertyDescriptor {
prefix: "Product color:",
name: "product_color",
pretty_name: "Product color:",
data: self.product_color.map(|c| c.to_string()),
suffix: "",
property_type: PropertyType::AlwaysReadOnly,
create_event: &|_| None,
}),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Side tone:",
name: "side_tone_enabled",
pretty_name: "Side tone:",
data: self.side_tone_on,
suffix: "",
property_type: if self.can_set_side_tone {
@@ -516,7 +525,8 @@ impl DeviceProperties {
}),
PropertyDescriptorWrapper::Int(
PropertyDescriptor {
prefix: "Side tone volume:",
name: "side_tone_volume",
pretty_name: "Side tone volume:",
data: self.side_tone_volume,
suffix: "",
property_type: if self.can_set_side_tone_volume {
@@ -529,7 +539,8 @@ impl DeviceProperties {
&[0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250],
),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Surround sound:",
name: "surrond_sound_enabled",
pretty_name: "Surround sound:",
data: self.surround_sound,
suffix: "",
property_type: if self.can_set_surround_sound {
@@ -540,7 +551,8 @@ impl DeviceProperties {
create_event: &move |enable| Some(DeviceEvent::SurroundSound(enable)),
}),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Voice prompt:",
name: "voice_prompt_enabled",
pretty_name: "Voice prompt:",
data: self.voice_prompt_on,
suffix: "",
property_type: if self.can_set_voice_prompt {
@@ -551,7 +563,8 @@ impl DeviceProperties {
create_event: &move |enable| Some(DeviceEvent::VoicePrompt(enable)),
}),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Playback muted:",
name: "playback_muted",
pretty_name: "Playback muted:",
data: self.silent,
suffix: "",
property_type: if self.can_set_silent_mode {
@@ -562,7 +575,8 @@ impl DeviceProperties {
create_event: &move |enable| Some(DeviceEvent::Silent(enable)),
}),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Noise gate active:",
name: "noise_gate_enabled",
pretty_name: "Noise gate active:",
data: self.noise_gate_active,
suffix: "",
property_type: if self.can_set_noise_gate {
@@ -573,7 +587,8 @@ impl DeviceProperties {
create_event: &move |enable| Some(DeviceEvent::NoiseGateActive(enable)),
}),
PropertyDescriptorWrapper::Bool(PropertyDescriptor {
prefix: "Connected:",
name: "connected",
pretty_name: "Connected:",
data: self.connected,
suffix: "",
property_type: PropertyType::AlwaysReadOnly,
@@ -588,17 +603,17 @@ impl DeviceProperties {
.filter_map(|prop| {
let (prefix, data, suffix) = match prop {
PropertyDescriptorWrapper::Int(property_descriptor, _) => (
property_descriptor.prefix,
property_descriptor.pretty_name,
&property_descriptor.data.map(|v| v.to_string()),
property_descriptor.suffix,
),
PropertyDescriptorWrapper::Bool(property_descriptor) => (
property_descriptor.prefix,
property_descriptor.pretty_name,
&property_descriptor.data.map(|v| v.to_string()),
property_descriptor.suffix,
),
PropertyDescriptorWrapper::String(property_descriptor) => (
property_descriptor.prefix,
property_descriptor.pretty_name,
&property_descriptor.data,
property_descriptor.suffix,
),
@@ -616,19 +631,19 @@ impl DeviceProperties {
.filter_map(|prop| {
let (prefix, data, suffix, property_type) = match prop {
PropertyDescriptorWrapper::Int(property_descriptor, _) => (
property_descriptor.prefix,
property_descriptor.pretty_name,
&property_descriptor.data.map(|v| v.to_string()),
property_descriptor.suffix,
property_descriptor.property_type,
),
PropertyDescriptorWrapper::Bool(property_descriptor) => (
property_descriptor.prefix,
property_descriptor.pretty_name,
&property_descriptor.data.map(|v| v.to_string()),
property_descriptor.suffix,
property_descriptor.property_type,
),
PropertyDescriptorWrapper::String(property_descriptor) => (
property_descriptor.prefix,
property_descriptor.pretty_name,
&property_descriptor.data,
property_descriptor.suffix,
property_descriptor.property_type,
@@ -641,7 +656,10 @@ impl DeviceProperties {
} else {
""
};
format!("{:<padding$} {}{}{}", prefix, data, suffix, readonly_marker)
format!(
"{:<padding$}: {}{}{}",
prefix, data, suffix, readonly_marker
)
})
})
.collect::<Vec<String>>()

View File

@@ -140,8 +140,8 @@ impl Tray for StatusTray {
menu_items.push(
StandardItem {
label: format!(
"{} {}{}",
property.prefix, current_value, property.suffix
"{}: {}{}",
property.pretty_name, current_value, property.suffix
),
enabled: false,
activate: Box::new(move |_| {
@@ -179,7 +179,7 @@ impl Tray for StatusTray {
SubMenu {
label: format!(
"{} {}{}",
property.prefix, current_value, property.suffix
property.pretty_name, current_value, property.suffix
),
enabled: property.property_type == PropertyType::ReadWrite
&& property.data.is_some(),
@@ -199,7 +199,7 @@ impl Tray for StatusTray {
StandardItem {
label: format!(
"{} {}{}",
property.prefix, current_value, property.suffix
property.pretty_name, current_value, property.suffix
),
enabled: property.property_type == PropertyType::ReadWrite
&& property.data.is_some(),
@@ -222,7 +222,7 @@ impl Tray for StatusTray {
StandardItem {
label: format!(
"{} {}{}",
property.prefix, current_value, property.suffix
property.pretty_name, current_value, property.suffix
),
enabled: false,
activate: Box::new(move |_| {