rust-actions 0.2.1

BDD testing framework with GitHub Actions YAML syntax
Documentation
use crate::args::RawArgs;
use crate::outputs::StepOutputs;
use crate::world::World;
use crate::Result;
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;

pub type StepFn<W> =
    for<'a> fn(&'a mut W, RawArgs) -> Pin<Box<dyn Future<Output = Result<StepOutputs>> + Send + 'a>>;

pub type ErasedStepFn = for<'a> fn(
    &'a mut dyn Any,
    RawArgs,
) -> Pin<Box<dyn Future<Output = Result<StepOutputs>> + Send + 'a>>;

pub struct ErasedStepDef {
    pub name: &'static str,
    pub world_type_id: TypeId,
    pub func: ErasedStepFn,
}

impl ErasedStepDef {
    pub const fn new(
        name: &'static str,
        world_type_id: TypeId,
        func: ErasedStepFn,
    ) -> Self {
        Self {
            name,
            world_type_id,
            func,
        }
    }
}

inventory::collect!(ErasedStepDef);

pub struct StepRegistry {
    steps: HashMap<String, ErasedStepFn>,
}

impl StepRegistry {
    pub fn new() -> Self {
        Self {
            steps: HashMap::new(),
        }
    }

    pub fn collect_for<W: World + 'static>(&mut self) {
        let target_type_id = TypeId::of::<W>();

        for step in inventory::iter::<ErasedStepDef> {
            if step.world_type_id == target_type_id {
                self.steps.insert(step.name.to_string(), step.func);
            }
        }
    }

    pub fn register(&mut self, name: impl Into<String>, func: ErasedStepFn) {
        self.steps.insert(name.into(), func);
    }

    pub fn get(&self, name: &str) -> Option<&ErasedStepFn> {
        self.steps.get(name)
    }

    pub fn len(&self) -> usize {
        self.steps.len()
    }

    pub fn is_empty(&self) -> bool {
        self.steps.is_empty()
    }
}

impl Default for StepRegistry {
    fn default() -> Self {
        Self::new()
    }
}