use crate::host::{
HostExternalPayloadBuilder, HostProfile, HostStoredType, HostStoredValue, HostType, HostTypeAt,
HostTypeSequence,
};
use crate::provider::ProviderExternalItem;
use crate::provider::advanced::{Retained, StoredDynamic};
use std::marker::PhantomData;
#[doc(hidden)]
pub trait ProviderStoredOwner: 'static {}
#[doc(hidden)]
pub fn retain_argument<Profile, Arguments, Owner, Index>(
builder: &mut HostExternalPayloadBuilder<'_, Profile, Arguments>,
value: <<Arguments as HostTypeAt<Index>>::Type as HostType>::Value<'_>,
) -> Retained<Owner, Index>
where
Profile: HostProfile,
Arguments: HostTypeSequence + HostTypeAt<Index>,
Owner: ProviderStoredOwner,
{
Retained::new(builder.store_argument::<Index>(value))
}
#[doc(hidden)]
pub fn retain_dynamic<Profile, Arguments, Owner, Type>(
builder: &mut HostExternalPayloadBuilder<'_, Profile, Arguments>,
value: Type::Value<'_>,
) -> StoredDynamic<Owner>
where
Profile: HostProfile,
Arguments: HostTypeSequence,
Owner: ProviderStoredOwner,
Type: HostType,
{
StoredDynamic::new(builder.store_dynamic::<Type>(value))
}
pub struct Stored<Type, Context = MissingStoredContext> {
context: Context,
type_: PhantomData<fn() -> Type>,
}
#[doc(hidden)]
pub struct MissingStoredContext;
#[doc(hidden)]
pub struct ProviderStoredOutput<'call, Owner, Index, Host> {
value: HostStoredValue<HostStoredType<Index>>,
call: PhantomData<&'call ()>,
owner: PhantomData<fn() -> (Owner, Host)>,
}
#[doc(hidden)]
pub struct ProviderStoredInput<'value, Owner, Index, Host> {
value: &'value HostStoredValue<HostStoredType<Index>>,
context: PhantomData<fn() -> (Owner, Host)>,
}
#[doc(hidden)]
pub struct ProviderExternalInputContext<'call, Payload, Arguments>
where
Arguments: HostTypeSequence,
{
value: ProviderExternalItem<Payload>,
context: PhantomData<&'call Arguments>,
}
#[doc(hidden)]
pub struct MissingExternalInputContext;
#[doc(hidden)]
pub struct ProviderExternalOutput<Payload> {
value: Result<Payload, ProviderExternalItem<Payload>>,
}
#[doc(hidden)]
pub struct MissingExternalOutputContext;
impl<Type, Owner, Index, Host> Stored<Type, ProviderStoredOutput<'_, Owner, Index, Host>>
where
Owner: ProviderStoredOwner,
{
#[doc(hidden)]
pub fn from_output(value: HostStoredValue<HostStoredType<Index>>) -> Self {
Self {
context: ProviderStoredOutput {
value,
call: PhantomData,
owner: PhantomData,
},
type_: PhantomData,
}
}
#[doc(hidden)]
pub fn into_host(self) -> HostStoredValue<HostStoredType<Index>> {
self.context.value
}
pub fn into_retained(self) -> Retained<Owner, Index> {
Retained::new(self.context.value)
}
}
impl<'value, Type, Owner, Index, Host> Stored<Type, ProviderStoredInput<'value, Owner, Index, Host>>
where
Owner: ProviderStoredOwner,
{
#[doc(hidden)]
pub fn from_input(value: &'value HostStoredValue<HostStoredType<Index>>) -> Self {
Self {
context: ProviderStoredInput {
value,
context: PhantomData,
},
type_: PhantomData,
}
}
#[doc(hidden)]
pub fn from_retained(value: &'value Retained<Owner, Index>) -> Self {
Self::from_input(value.host())
}
pub(crate) fn host(&self) -> &'value HostStoredValue<HostStoredType<Index>> {
self.context.value
}
}
impl<Payload> ProviderExternalOutput<Payload> {
#[doc(hidden)]
pub fn new(payload: Payload) -> Self {
Self { value: Ok(payload) }
}
#[doc(hidden)]
pub fn from_input(value: ProviderExternalItem<Payload>) -> Self {
Self { value: Err(value) }
}
#[doc(hidden)]
pub fn into_value(self) -> Result<Payload, ProviderExternalItem<Payload>> {
self.value
}
}
impl<'call, Payload, Arguments> ProviderExternalInputContext<'call, Payload, Arguments>
where
Arguments: HostTypeSequence,
{
#[doc(hidden)]
pub fn from_host(value: ProviderExternalItem<Payload>) -> Self {
Self {
value,
context: PhantomData,
}
}
#[doc(hidden)]
pub fn payload(&self) -> &Payload {
&self.value
}
#[doc(hidden)]
pub fn into_output(self) -> ProviderExternalOutput<Payload> {
ProviderExternalOutput::from_input(self.value)
}
}
#[cfg(test)]
mod tests {
use super::{ProviderStoredOwner, retain_argument, retain_dynamic};
use crate::host::test::{TestHostCallRuntime, TestHostProfile, TestRunState};
use crate::host::{
CallArguments, HostExternalPayloadBuilder, HostTypeIndex0, HostTypeList, HostTypeListEnd,
};
use crate::plan::ValueType;
use crate::provider::advanced::{DynamicKind, Retained, StoredDynamic};
use num_bigint::BigInt;
struct Payload;
impl ProviderStoredOwner for Payload {}
#[test]
fn retention_bridges_preserve_the_declared_owner_and_runtime_type() {
type Arguments = HostTypeList<BigInt, HostTypeListEnd>;
let mut state = TestRunState::default();
let arguments = CallArguments::new(Vec::new(), Vec::new());
let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
let mut builder =
HostExternalPayloadBuilder::<TestHostProfile, Arguments>::new(&mut runtime);
let retained: Retained<Payload, HostTypeIndex0> =
retain_argument(&mut builder, BigInt::from(7));
let dynamic: StoredDynamic<Payload> =
retain_dynamic::<_, Arguments, _, BigInt>(&mut builder, BigInt::from(8));
assert_eq!(retained.host().value.type_(), &ValueType::Int);
assert_eq!(dynamic.kind(), DynamicKind::Int);
}
}