1use crate::host::{
2 HostExternalPayloadBuilder, HostProfile, HostStoredType, HostStoredValue, HostType, HostTypeAt,
3 HostTypeSequence,
4};
5use crate::provider::ProviderExternalItem;
6use crate::provider::advanced::{Retained, StoredDynamic};
7use std::marker::PhantomData;
8
9#[doc(hidden)]
11pub trait ProviderStoredOwner: 'static {}
12
13#[doc(hidden)]
18pub fn retain_argument<Profile, Arguments, Owner, Index>(
19 builder: &mut HostExternalPayloadBuilder<'_, Profile, Arguments>,
20 value: <<Arguments as HostTypeAt<Index>>::Type as HostType>::Value<'_>,
21) -> Retained<Owner, Index>
22where
23 Profile: HostProfile,
24 Arguments: HostTypeSequence + HostTypeAt<Index>,
25 Owner: ProviderStoredOwner,
26{
27 Retained::new(builder.store_argument::<Index>(value))
28}
29
30#[doc(hidden)]
32pub fn retain_dynamic<Profile, Arguments, Owner, Type>(
33 builder: &mut HostExternalPayloadBuilder<'_, Profile, Arguments>,
34 value: Type::Value<'_>,
35) -> StoredDynamic<Owner>
36where
37 Profile: HostProfile,
38 Arguments: HostTypeSequence,
39 Owner: ProviderStoredOwner,
40 Type: HostType,
41{
42 StoredDynamic::new(builder.store_dynamic::<Type>(value))
43}
44
45pub struct Stored<Type, Context = MissingStoredContext> {
52 context: Context,
53 type_: PhantomData<fn() -> Type>,
54}
55
56#[doc(hidden)]
57pub struct MissingStoredContext;
58
59#[doc(hidden)]
61pub struct ProviderStoredOutput<'call, Owner, Index, Host> {
62 value: HostStoredValue<HostStoredType<Index>>,
63 call: PhantomData<&'call ()>,
64 owner: PhantomData<fn() -> (Owner, Host)>,
65}
66
67#[doc(hidden)]
69pub struct ProviderStoredInput<'value, Owner, Index, Host> {
70 value: &'value HostStoredValue<HostStoredType<Index>>,
71 context: PhantomData<fn() -> (Owner, Host)>,
72}
73
74#[doc(hidden)]
76pub struct ProviderExternalInputContext<'call, Payload, Arguments>
77where
78 Arguments: HostTypeSequence,
79{
80 value: ProviderExternalItem<Payload>,
81 context: PhantomData<&'call Arguments>,
82}
83
84#[doc(hidden)]
85pub struct MissingExternalInputContext;
86
87#[doc(hidden)]
88pub struct ProviderExternalOutput<Payload> {
89 value: Result<Payload, ProviderExternalItem<Payload>>,
90}
91
92#[doc(hidden)]
93pub struct MissingExternalOutputContext;
94
95impl<Type, Owner, Index, Host> Stored<Type, ProviderStoredOutput<'_, Owner, Index, Host>>
96where
97 Owner: ProviderStoredOwner,
98{
99 #[doc(hidden)]
100 pub fn from_output(value: HostStoredValue<HostStoredType<Index>>) -> Self {
101 Self {
102 context: ProviderStoredOutput {
103 value,
104 call: PhantomData,
105 owner: PhantomData,
106 },
107 type_: PhantomData,
108 }
109 }
110
111 #[doc(hidden)]
112 pub fn into_host(self) -> HostStoredValue<HostStoredType<Index>> {
113 self.context.value
114 }
115
116 pub fn into_retained(self) -> Retained<Owner, Index> {
118 Retained::new(self.context.value)
119 }
120}
121
122impl<'value, Type, Owner, Index, Host> Stored<Type, ProviderStoredInput<'value, Owner, Index, Host>>
123where
124 Owner: ProviderStoredOwner,
125{
126 #[doc(hidden)]
127 pub fn from_input(value: &'value HostStoredValue<HostStoredType<Index>>) -> Self {
128 Self {
129 context: ProviderStoredInput {
130 value,
131 context: PhantomData,
132 },
133 type_: PhantomData,
134 }
135 }
136
137 #[doc(hidden)]
138 pub fn from_retained(value: &'value Retained<Owner, Index>) -> Self {
139 Self::from_input(value.host())
140 }
141
142 pub(crate) fn host(&self) -> &'value HostStoredValue<HostStoredType<Index>> {
143 self.context.value
144 }
145}
146
147impl<Payload> ProviderExternalOutput<Payload> {
148 #[doc(hidden)]
149 pub fn new(payload: Payload) -> Self {
150 Self { value: Ok(payload) }
151 }
152
153 #[doc(hidden)]
154 pub fn from_input(value: ProviderExternalItem<Payload>) -> Self {
155 Self { value: Err(value) }
156 }
157
158 #[doc(hidden)]
159 pub fn into_value(self) -> Result<Payload, ProviderExternalItem<Payload>> {
160 self.value
161 }
162}
163
164impl<'call, Payload, Arguments> ProviderExternalInputContext<'call, Payload, Arguments>
165where
166 Arguments: HostTypeSequence,
167{
168 #[doc(hidden)]
169 pub fn from_host(value: ProviderExternalItem<Payload>) -> Self {
170 Self {
171 value,
172 context: PhantomData,
173 }
174 }
175
176 #[doc(hidden)]
177 pub fn payload(&self) -> &Payload {
178 &self.value
179 }
180
181 #[doc(hidden)]
182 pub fn into_output(self) -> ProviderExternalOutput<Payload> {
183 ProviderExternalOutput::from_input(self.value)
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::{ProviderStoredOwner, retain_argument, retain_dynamic};
190 use crate::host::test::{TestHostCallRuntime, TestHostProfile, TestRunState};
191 use crate::host::{
192 CallArguments, HostExternalPayloadBuilder, HostTypeIndex0, HostTypeList, HostTypeListEnd,
193 };
194 use crate::plan::ValueType;
195 use crate::provider::advanced::{DynamicKind, Retained, StoredDynamic};
196 use num_bigint::BigInt;
197
198 struct Payload;
199
200 impl ProviderStoredOwner for Payload {}
201
202 #[test]
203 fn retention_bridges_preserve_the_declared_owner_and_runtime_type() {
204 type Arguments = HostTypeList<BigInt, HostTypeListEnd>;
205
206 let mut state = TestRunState::default();
207 let arguments = CallArguments::new(Vec::new(), Vec::new());
208 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
209 let mut builder =
210 HostExternalPayloadBuilder::<TestHostProfile, Arguments>::new(&mut runtime);
211
212 let retained: Retained<Payload, HostTypeIndex0> =
213 retain_argument(&mut builder, BigInt::from(7));
214 let dynamic: StoredDynamic<Payload> =
215 retain_dynamic::<_, Arguments, _, BigInt>(&mut builder, BigInt::from(8));
216
217 assert_eq!(retained.host().value.type_(), &ValueType::Int);
218 assert_eq!(dynamic.kind(), DynamicKind::Int);
219 }
220}