auv-cli-invoke 0.0.22

Application Use Via... script-able OS automation library
use std::collections::HashSet;

use crate::{CommandGroup, CommandNode, InvokeCommand, commands};

pub struct InvokeRegistry {
  groups: Vec<CommandGroup>,
  commands: Vec<InvokeCommand>,
}

impl InvokeRegistry {
  pub fn from_groups(groups: Vec<CommandGroup>) -> Self {
    let mut commands = Vec::new();
    for group in &groups {
      flatten_group(group, &mut commands);
    }
    assert_unique_command_ids(&commands);
    Self { groups, commands }
  }

  pub fn resolve(&self, command_id: &str) -> Option<&InvokeCommand> {
    self.commands.iter().find(|command| command.id == command_id)
  }

  pub fn all(&self) -> &[InvokeCommand] {
    &self.commands
  }

  pub fn groups(&self) -> &[CommandGroup] {
    &self.groups
  }
}

fn assert_unique_command_ids(commands: &[InvokeCommand]) {
  let mut ids = HashSet::new();
  for command in commands {
    assert!(ids.insert(command.id), "duplicate invoke command id registered: {}", command.id);
  }
}

pub fn default_registry() -> InvokeRegistry {
  InvokeRegistry::from_groups(vec![
    commands::display::group(),
    commands::screen::group(),
    commands::window::group(),
    commands::input::group(),
    commands::app::group(),
    commands::overlay::group(),
    commands::media_control::group(),
    commands::scan::group(),
  ])
}

fn flatten_group(group: &CommandGroup, commands: &mut Vec<InvokeCommand>) {
  for child in &group.children {
    match child {
      CommandNode::Command(command) => commands.push(command.clone()),
      CommandNode::Group(group) => flatten_group(group, commands),
    }
  }
}