1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
//! Convert.
use super::*;
impl<P: Copy> I<ValidH<P, ()>, { Dep::Demanding }> {
/// Converts the dependency type of a valid interface back into [`Dep::Helpful`].
///
/// When applying some combinator, the dependency type of a valid interface could be changed to [`Dep::Demanding`].
/// This function is used to convert the dependency type back to [`Dep::Helpful`].
///
/// - Payload: Preserved.
/// - Resolver: The resolver carries no information.
///
/// | Interface | Ingress | Egress |
/// | :-------: | ------------ | ------------ |
/// | **Fwd** | `HOption<P>` | `HOption<P>` |
/// | **Bwd** | `()` | `()` |
pub fn into_helpful(self) -> Valid<P> {
// # Safety
//
// `Valid<P, D>` interface has unit(`()`) resolver signal by definition.
// Hence, the `Valid` interface doesn't refer to the resolver signal to determine the valid signal, which is identical to `Dep::Helpful`.
unsafe { self.fsm::<(), { Dep::Helpful }, ValidH<P, ()>>((), |ip, (), ()| (ip, (), ())) }
}
}
impl<P: Copy, R: Copy> I<ValidH<P, R>, { Dep::Helpful }> {
/// Converts a `ValidH` interface into a `VrH` interface, by allowing the payload to be discarded.
///
/// Note that the ingress ready condition `ValidH::ready` is always `true`, but the egress ready condition
/// `VrH::ready` is `er.ready`. This means if `er.ready` is false, the payload will be discarded/ignored by
/// combinators after this one even if it is valid.
///
/// - Payload: Preserved, but may be discarded by combinators after this one.
/// - Resolver: The ready signal is stripped.
///
/// | Interface | Ingress | Egress |
/// | :-------: | ------------ | ------------ |
/// | **Fwd** | `HOption<P>` | `HOption<P>` |
/// | **Bwd** | `R` | `Ready<R>` |
pub fn discard_into_vr(self) -> I<VrH<P, R>, { Dep::Helpful }> {
unsafe { self.fsm((), |ip, er: Ready<R>, ()| (ip, er.inner, ())) }
}
}
impl<P: Copy, R: Copy, const D: Dep> I<VrH<P, R>, D> {
/// Converts a `VrH` hazard interface into a `ValidH` hazard interface, by setting the ingress ready signal to be
/// always true.
///
/// - Payload: Preserved.
/// - Resolver: Wrapped in an always ready [`Ready`].
///
/// | Interface | Ingress | Egress |
/// | :-------: | ------------ | ------------ |
/// | **Fwd** | `HOption<P>` | `HOption<P>` |
/// | **Bwd** | `Ready<R>` | `R` |
pub fn always_into_valid(self) -> I<ValidH<P, R>, D> {
unsafe { self.fsm((), |ip, er, ()| (ip, Ready::valid(er), ())) }
}
}
impl<H: Hazard> I<H, { Dep::Helpful }> {
/// Converts a [`Dep::Helpful`] hazard interface into a [`Dep::Demanding`] one, by dropping the payload if
/// `H::ready` is false.
///
/// - Payload: Dropped if `H::ready` is false.
/// - Resolver: Preserved.
///
/// | Interface | Ingress | Egress |
/// | :-------: | --------------- | --------------- |
/// | **Fwd** | `HOption<H::P>` | `HOption<H::P>` |
/// | **Bwd** | `H::R` | `H::R` |
pub fn drop_into_demanding(self) -> I<H, { Dep::Demanding }> {
self.drop_into_hazard::<H>()
}
}
impl<H: Hazard, const D: Dep> I<H, D> {
/// Converts a hazard interface into another one with the same payload/resolver types.
///
/// In effect, this changes the ready condition from the ingress side `H::ready` to the egress side `EH::ready`.
///
/// - Payload: Dropped if `H::ready` or `EH::ready` is false.
/// - Resolver: Preserved.
///
/// | Interface | Ingress | Egress |
/// | :-------: | --------------- | --------------- |
/// | **Fwd** | `HOption<H::P>` | `HOption<H::P>` |
/// | **Bwd** | `H::R` | `H::R` |
pub fn drop_into_hazard<EH: Hazard<P = H::P, R = H::R>>(self) -> I<EH, { Dep::Demanding }> {
self.map_drop(|p| p)
}
}
impl<H: Hazard> I<AndH<H>, { Dep::Helpful }> {
/// Converts a hazard interface wrapped in an `AndH` into another one with the same payload/resolver types.
///
/// In effect, this changes the ready condition from the ingress side `<AndH<H>>::ready` to the egress side
/// `EH::ready`.
///
/// - Payload: Preserved.
/// - Resolver: An additional ready signal is attached to the ingress resolver, which will be turned off to block
/// ingress transfers if the egress ready condition `EH::ready` is false. The egress resolver `H::R` is
/// preserved.
///
/// | Interface | Ingress | Egress |
/// | :-------: | --------------- | --------------- |
/// | **Fwd** | `HOption<H::P>` | `HOption<H::P>` |
/// | **Bwd** | `Ready<H::R>` | `H::R` |
pub fn block_into_hazard<EH: Hazard<P = H::P, R = H::R>>(self) -> I<EH, { Dep::Demanding }> {
self.map_resolver_block::<EH>(|er| er)
}
}
impl<P: Copy> Vr<P> {
/// A variation of [`I::block_into_hazard`] for a valid-ready interface that drops the resolver.
///
/// - Payload: Preserved.
/// - Resolver: The ingress ready signal will be turned off to block ingress transfers if the egress ready condition
/// `EH::ready` is false. The egress resolver `EH::R` is dropped.
///
/// | Interface | Ingress | Egress |
/// | :-------: | ------------ | ------------ |
/// | **Fwd** | `HOption<P>` | `HOption<P>` |
/// | **Bwd** | `Ready<()>` | `EH::R` |
pub fn block_into_hazard_vr<EH: Hazard<P = P>>(self) -> I<EH, { Dep::Demanding }> {
self.map_resolver::<EH::R>(|_| ()).block_into_hazard::<EH>()
}
}