Skip to content

Commit efeefb7

Browse files
committed
refactor(bar): add extend_enum! macro
This commit adds an extend_enum! macro and some unit tests to provide an ergonomic way to specialize configs for specific (sub)widgets. The macro takes the name of the existing enum, the desired name of the new, extended enum, and a list of variants which should be added to the extended enum. The macro will add new variants to a new enum definition first, before wrapping the existing enum in an Existing variant and tagging it with the `#[serde(untagged)]` annotation. From is also implemented for ergonomic from/into calls between shared variants of the existing and extended enums.
1 parent 2bbc269 commit efeefb7

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

komorebi-bar/src/config.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,90 @@ pub enum DisplayFormat {
416416
/// Show an icon and text for the selected element, and icons on the rest
417417
IconAndTextOnSelected,
418418
}
419+
420+
macro_rules! extend_enum {
421+
($existing_enum:ident, $new_enum:ident, { $($(#[$meta:meta])* $variant:ident),* $(,)? }) => {
422+
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema, PartialEq)]
423+
pub enum $new_enum {
424+
// Add new variants
425+
$(
426+
$(#[$meta])*
427+
$variant,
428+
)*
429+
// Include a variant that wraps the existing enum and flatten in when deserializing
430+
#[serde(untagged)]
431+
Existing($existing_enum),
432+
}
433+
434+
// Implement From for the existing enum
435+
impl From<$existing_enum> for $new_enum {
436+
fn from(value: $existing_enum) -> Self {
437+
$new_enum::Existing(value)
438+
}
439+
}
440+
};
441+
}
442+
443+
extend_enum!(DisplayFormat, WorkspacesDisplayFormat, {
444+
/// Show all icons only
445+
AllIcons,
446+
/// Show both all icons and text
447+
AllIconsAndText,
448+
/// Show all icons and text for the selected element, and all icons on the rest
449+
AllIconsAndTextOnSelected,
450+
});
451+
452+
#[cfg(test)]
453+
mod tests {
454+
use schemars::JsonSchema;
455+
use serde::Deserialize;
456+
use serde::Serialize;
457+
use serde_json::json;
458+
459+
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
460+
pub enum OriginalDisplayFormat {
461+
/// Show None Of The Things
462+
NoneOfTheThings,
463+
}
464+
465+
extend_enum!(OriginalDisplayFormat, ExtendedDisplayFormat, {
466+
/// Show Some Of The Things
467+
SomeOfTheThings,
468+
});
469+
470+
#[derive(serde::Deserialize)]
471+
struct ExampleConfig {
472+
#[allow(unused)]
473+
format: ExtendedDisplayFormat,
474+
}
475+
476+
#[test]
477+
pub fn extend_new_variant() {
478+
let raw = json!({
479+
"format": "SomeOfTheThings",
480+
})
481+
.to_string();
482+
483+
assert!(serde_json::from_str::<ExampleConfig>(&raw).is_ok())
484+
}
485+
486+
#[test]
487+
pub fn extend_existing_variant() {
488+
let raw = json!({
489+
"format": "NoneOfTheThings",
490+
})
491+
.to_string();
492+
493+
assert!(serde_json::from_str::<ExampleConfig>(&raw).is_ok())
494+
}
495+
496+
#[test]
497+
pub fn extend_invalid_variant() {
498+
let raw = json!({
499+
"format": "ALLOFTHETHINGS",
500+
})
501+
.to_string();
502+
503+
assert!(serde_json::from_str::<ExampleConfig>(&raw).is_err())
504+
}
505+
}

0 commit comments

Comments
 (0)