azriel91/peace

Consolidate Item Spec functions into single trait

azriel91 opened this issue · 0 comments

What

Currently ItemSpec has a number of associated types to split up the logic into different trait implementations.

Consolidating this into the top level ItemSpec trait should reduce the cognitive load on maintainers for:

  • Keeping the data associated types in sync
  • Reducing the number of traits to learn and track.

Details

Current traits
pub trait ItemSpec: DynClone {
    // Data types
    type Error: std::error::Error;
    type State: Clone + fmt::Display + Serialize + DeserializeOwned;
    type StateDiff: Clone + fmt::Display + Serialize + DeserializeOwned;

    // Logic types
    type StateCurrentFnSpec: TryFnSpec<Error = Self::Error, Output = Self::State>;
    type StateDesiredFnSpec: TryFnSpec<Error = Self::Error, Output = Self::State>;
    type StateDiffFnSpec: StateDiffFnSpec<Error = Self::Error, State = Self::State, StateDiff = Self::StateDiff>;
    type EnsureOpSpec: EnsureOpSpec<Error = Self::Error, State = Self::State, StateDiff = Self::StateDiff>;
    type CleanOpSpec: CleanOpSpec<Error = Self::Error, State = Self::State>;
}

pub trait TryFnSpec {
    type Output;
    type Data<'op>: Data<'op>
    where
        Self: 'op;
    type Error: std::error::Error;

    async fn try_exec(data: Self::Data<'_>) -> Result<Option<Self::Output>, Self::Error>;
    async fn exec(data: Self::Data<'_>) -> Result<Self::Output, Self::Error>;
}

pub trait StateDiffFnSpec {
    type State: Clone + Serialize + DeserializeOwned;
    type StateDiff;
    type Data<'op>: Data<'op>
    where
        Self: 'op;
    type Error: std::error::Error;

    async fn exec(
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
    ) -> Result<Self::StateDiff, Self::Error>;
}

pub trait EnsureOpSpec {
    type Error: std::error::Error;
    type State: Clone + Serialize + DeserializeOwned;
    type StateDiff: Clone + Serialize + DeserializeOwned;
    type Data<'op>: Data<'op>
    where
        Self: 'op;

    async fn check(
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
        diff: &Self::StateDiff,
    ) -> Result<OpCheckStatus, Self::Error>;

    async fn exec_dry(
        ctx: OpCtx<'_>,
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
        diff: &Self::StateDiff,
    ) -> Result<Self::State, Self::Error>;

    async fn exec(
        ctx: OpCtx<'_>,
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
        diff: &Self::StateDiff,
    ) -> Result<Self::State, Self::Error>;
}

pub trait CleanOpSpec {
    type Error: std::error::Error;
    type State: Clone + Serialize + DeserializeOwned;
    type Data<'op>: Data<'op>
    where
        Self: 'op;

    async fn check(data: Self::Data<'_>, state: &Self::State)
    -> Result<OpCheckStatus, Self::Error>;
    async fn exec_dry(data: Self::Data<'_>, state: &Self::State) -> Result<(), Self::Error>;
    async fn exec(data: Self::Data<'_>, state: &Self::State) -> Result<(), Self::Error>;
}
Consolidated trait
pub trait ItemSpec: DynClone {
    // Data types
    type Error: std::error::Error;
    type State: Clone + fmt::Display + Serialize + DeserializeOwned;
    type StateDiff: Clone + fmt::Display + Serialize + DeserializeOwned;

    async fn state_current_try(data: Self::Data<'_>) -> Result<Option<Self::Output>, Self::Error>;
    async fn state_current(data: Self::Data<'_>) -> Result<Self::Output, Self::Error>;
    async fn state_desired_try(data: Self::Data<'_>) -> Result<Option<Self::Output>, Self::Error>;
    async fn state_desired(data: Self::Data<'_>) -> Result<Self::Output, Self::Error>;
    async fn state_diff(
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
    ) -> Result<Self::StateDiff, Self::Error>;

    async fn ensure_check(
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
        diff: &Self::StateDiff,
    ) -> Result<OpCheckStatus, Self::Error>;

    async fn ensure_exec_dry(
        ctx: OpCtx<'_>,
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
        diff: &Self::StateDiff,
    ) -> Result<Self::State, Self::Error>;

    async fn ensure_exec(
        ctx: OpCtx<'_>,
        data: Self::Data<'_>,
        state_current: &Self::State,
        state_desired: &Self::State,
        diff: &Self::StateDiff,
    ) -> Result<Self::State, Self::Error>;

    async fn clean_check(data: Self::Data<'_>, state: &Self::State)
    -> Result<OpCheckStatus, Self::Error>;
    async fn clean_exec_dry(data: Self::Data<'_>, state: &Self::State) -> Result<(), Self::Error>;
    async fn clean_exec(data: Self::Data<'_>, state: &Self::State) -> Result<(), Self::Error>;
}

See also #67.