1use crate::host::{
2 HostCallArguments, HostCallCompletion, HostConstruction, HostCustom, HostCustomArgumentSlot,
3 HostCustomConstructor, HostCustomType, HostExternal, HostExternalArgumentSlot,
4 HostExternalBinding, HostExternalPayloadBuilder, HostExternalPayloadView, HostExternalSchema,
5 HostExternalStorage, HostExternalType, HostFunctionArgumentSlot, HostList,
6 HostListArgumentSlot, HostListType, HostStoredValue, HostTuple, HostTupleArgumentSlot,
7 HostTupleType, HostType, HostTypeSequence, HostValue, HostValueArgumentSlot,
8};
9use crate::provider::{
10 List, ProviderExternalPayloadAccess, ProviderListContext, ProviderListItemDecoder,
11};
12use std::marker::PhantomData;
13
14mod runtime;
15
16pub(crate) use runtime::HostCallRuntime;
17#[cfg(test)]
18pub(crate) use runtime::test;
19
20pub trait HostProfile: Send + Sync + 'static {
21 type RunState;
22 type ExternalStores: Default + 'static;
23}
24
25pub trait HostProvider<Profile: HostProfile>: Send + Sync + 'static {
26 type State;
27
28 fn project(state: &mut Profile::RunState) -> &mut Self::State;
29}
30
31type BoundExternalStorage<Profile, Provider, Schema> =
32 <Provider as HostExternalBinding<Profile, Schema>>::Storage;
33type BoundExternalPayload<Profile, Provider, Schema> = <BoundExternalStorage<
34 Profile,
35 Provider,
36 Schema,
37> as HostExternalStorage<Profile, Schema>>::Payload;
38
39#[derive(Debug, Clone, Copy, Default)]
40pub struct StatelessHostProfile;
41
42pub struct HostCall<'call, Profile, Provider, Return>
43where
44 Profile: HostProfile,
45 Provider: HostProvider<Profile>,
46 Return: HostType,
47{
48 runtime: &'call mut dyn HostCallRuntime<Profile>,
49 marker: PhantomData<(Provider, Return)>,
50}
51
52impl HostProfile for StatelessHostProfile {
53 type RunState = ();
54 type ExternalStores = ();
55}
56
57impl<'call, Profile, Provider, Return> HostCall<'call, Profile, Provider, Return>
58where
59 Profile: HostProfile,
60 Provider: HostProvider<Profile>,
61 Return: HostType,
62{
63 pub(crate) fn new(runtime: &'call mut dyn HostCallRuntime<Profile>) -> Self {
64 Self {
65 runtime,
66 marker: PhantomData,
67 }
68 }
69
70 pub fn state(&mut self) -> &mut Provider::State {
71 Provider::project(self.runtime.state())
72 }
73
74 pub fn return_value(self, value: Return::Value<'call>) -> HostCallCompletion<'call, Return> {
75 HostCallCompletion::new(
76 self.runtime
77 .complete(crate::host::type_::into_scoped::<Return>(value)),
78 )
79 }
80
81 pub fn equal<Type: HostType>(
82 &self,
83 left: Type::Value<'call>,
84 right: Type::Value<'call>,
85 ) -> bool {
86 self.runtime.equal(
87 crate::host::type_::into_scoped::<Type>(left),
88 crate::host::type_::into_scoped::<Type>(right),
89 )
90 }
91
92 pub fn source_hash<Type: HostType>(&self, value: Type::Value<'call>) -> u64 {
97 self.runtime
98 .source_hash(crate::host::type_::into_scoped::<Type>(value))
99 }
100
101 pub fn inspect<Type: HostType>(&self, value: Type::Value<'call>) -> ecow::EcoString {
103 self.runtime
104 .inspect(crate::host::type_::into_scoped::<Type>(value))
105 }
106
107 pub(crate) fn arguments(&self) -> &dyn HostCallArguments {
108 self.runtime.arguments()
109 }
110
111 pub(crate) fn value<Type>(&self, slot: HostValueArgumentSlot) -> HostValue<'call, Type> {
112 HostValue::new(self.runtime.value(slot))
113 }
114
115 pub(crate) fn list<Item>(&self, slot: HostListArgumentSlot) -> HostList<'call, Item> {
116 HostList::new(self.runtime.list(slot))
117 }
118
119 pub(crate) fn tuple<Elements>(
120 &self,
121 slot: HostTupleArgumentSlot,
122 ) -> HostTuple<'call, Elements> {
123 HostTuple::new(self.runtime.tuple(slot))
124 }
125
126 pub(crate) fn custom<Custom>(&self, slot: HostCustomArgumentSlot) -> HostCustom<'call, Custom> {
127 HostCustom::new(self.runtime.custom(slot))
128 }
129
130 pub(crate) fn external<Type>(
131 &self,
132 slot: HostExternalArgumentSlot,
133 ) -> HostExternal<'call, Type> {
134 HostExternal::new(self.runtime.external(slot))
135 }
136
137 pub(crate) fn function<Arguments, FunctionReturn>(
138 &self,
139 slot: HostFunctionArgumentSlot,
140 ) -> crate::host::HostCallable<'call, Arguments, FunctionReturn> {
141 crate::host::HostCallable::new(self.runtime.function(slot))
142 }
143
144 pub fn list_len<Item>(&self, value: HostList<'call, Item>) -> usize {
145 self.runtime.list_len(value.token)
146 }
147
148 pub fn list_item<Item: HostType>(
149 &mut self,
150 value: HostList<'call, Item>,
151 index: usize,
152 ) -> Option<Item::Value<'call>> {
153 self.runtime
154 .list_item(value.token, index)
155 .map(|token| crate::host::type_::from_token::<Item, Profile>(self.runtime, token))
156 }
157
158 #[doc(hidden)]
159 pub fn provider_list<Item, HostItem, Decoder>(
160 &self,
161 value: HostList<'call, HostItem>,
162 decoder: Decoder,
163 ) -> List<Item, ProviderListContext<'call, HostItem, Decoder>>
164 where
165 HostItem: HostType,
166 Decoder: ProviderListItemDecoder<Item>,
167 {
168 let retained = self.runtime.retain_list(value.token);
169 ProviderListContext::new(value, retained, decoder).into_list()
170 }
171
172 #[doc(hidden)]
173 pub fn provider_input_list<Item, HostItem, Decoder>(
174 &self,
175 value: HostList<'call, HostItem>,
176 decoder: Decoder,
177 ) -> List<Item, crate::provider::ProviderInputListContext<Decoder>>
178 where
179 HostItem: HostType,
180 Decoder: ProviderListItemDecoder<Item>,
181 {
182 crate::provider::ProviderInputListContext::new(
183 self.runtime.retain_list(value.token),
184 decoder,
185 )
186 }
187
188 #[doc(hidden)]
189 pub fn provider_external_item_with<Binding, Schema, Arguments>(
190 &self,
191 value: HostExternal<'call, HostExternalType<Schema, Arguments>>,
192 ) -> crate::provider::ProviderExternalItem<BoundExternalPayload<Profile, Binding, Schema>>
193 where
194 Schema: HostExternalSchema,
195 Binding: HostExternalBinding<Profile, Schema>,
196 Arguments: HostTypeSequence,
197 {
198 let lease = self.runtime.external_lease(value.token);
199 crate::provider::ProviderExternalItem::new(
200 BoundExternalStorage::<Profile, Binding, Schema>::store(self.runtime.external_stores())
201 .view(&lease),
202 lease,
203 )
204 }
205
206 #[doc(hidden)]
207 pub fn provider_external_from_item<Schema, Arguments, Payload>(
208 &mut self,
209 value: crate::provider::ProviderExternalItem<Payload>,
210 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
211 where
212 Schema: HostExternalSchema,
213 Arguments: HostTypeSequence,
214 {
215 HostExternal::new(self.runtime.build_external(
216 &crate::host::HostTypeDescriptor::of::<HostExternalType<Schema, Arguments>>(),
217 value.into_lease(),
218 ))
219 }
220
221 #[doc(hidden)]
222 pub fn provider_external_payload_access_with<Binding, Schema>(
223 &self,
224 ) -> ProviderExternalPayloadAccess<BoundExternalPayload<Profile, Binding, Schema>>
225 where
226 Schema: HostExternalSchema,
227 Binding: HostExternalBinding<Profile, Schema>,
228 {
229 ProviderExternalPayloadAccess::new(BoundExternalStorage::<Profile, Binding, Schema>::store(
230 self.runtime.external_stores(),
231 ))
232 }
233
234 pub fn construct_list<Item: HostType>(
236 &mut self,
237 _construction: HostConstruction<'call, HostListType<Item>>,
238 values: impl IntoIterator<Item = Item::Value<'call>>,
239 ) -> HostList<'call, Item> {
240 let values = values
241 .into_iter()
242 .map(crate::host::type_::into_scoped::<Item>)
243 .collect::<Vec<_>>()
244 .into_boxed_slice();
245 let value = self.runtime.build_list(
246 &crate::host::HostTypeDescriptor::of::<HostListType<Item>>(),
247 values,
248 );
249 HostList::new(self.runtime.list_token(value))
250 }
251
252 pub fn tuple_len<Elements>(&self, value: HostTuple<'call, Elements>) -> usize {
253 self.runtime.tuple_len(value.token)
254 }
255
256 pub fn tuple_values<Elements: HostTypeSequence>(
257 &mut self,
258 value: HostTuple<'call, Elements>,
259 ) -> Elements::Values<'call> {
260 let values = self.runtime.tuple_values(value.token);
261 crate::host::type_::from_tokens::<Elements, Profile>(self.runtime, &values)
262 }
263
264 pub fn construct_tuple<Elements: HostTypeSequence>(
266 &mut self,
267 _construction: HostConstruction<'call, HostTupleType<Elements>>,
268 values: Elements::Values<'call>,
269 ) -> HostTuple<'call, Elements> {
270 let mut output = Vec::new();
271 crate::host::type_::into_scoped_values::<Elements>(values, &mut output);
272 let value = self.runtime.build_tuple(output.into_boxed_slice());
273 HostTuple::new(self.runtime.tuple_token(value))
274 }
275
276 pub fn custom_constructor<Custom>(&self, value: HostCustom<'call, Custom>) -> usize {
277 self.runtime.custom_constructor(value.token)
278 }
279
280 pub fn custom_fields<Constructor>(
281 &mut self,
282 value: HostCustom<'call, Constructor::Custom>,
283 ) -> Option<<Constructor::Fields as HostTypeSequence>::Values<'call>>
284 where
285 Constructor: HostCustomConstructor,
286 {
287 if self.runtime.custom_constructor(value.token)
288 != crate::host::type_::custom_constructor_index::<Constructor>()
289 {
290 return None;
291 }
292 let fields = self.runtime.custom_fields(value.token);
293 Some(crate::host::type_::from_tokens::<
294 Constructor::Fields,
295 Profile,
296 >(self.runtime, &fields))
297 }
298
299 #[doc(hidden)]
300 pub fn provider_custom_fields<Constructor>(
301 &mut self,
302 value: HostCustom<'call, Constructor::Custom>,
303 ) -> Option<<Constructor::Fields as HostTypeSequence>::Values<'call>>
304 where
305 Constructor: HostCustomConstructor,
306 {
307 if self.runtime.custom_constructor(value.token)
308 != crate::host::type_::custom_constructor_index::<Constructor>()
309 {
310 return None;
311 }
312 let fields = self.runtime.take_custom_fields(value.token);
313 Some(crate::host::type_::from_tokens::<
314 Constructor::Fields,
315 Profile,
316 >(self.runtime, &fields))
317 }
318
319 #[doc(hidden)]
322 pub fn provider_remaining_custom_fields<Constructor>(
323 &mut self,
324 value: HostCustom<'call, Constructor::Custom>,
325 ) -> <Constructor::Fields as HostTypeSequence>::Values<'call>
326 where
327 Constructor: HostCustomConstructor,
328 {
329 let fields = self.runtime.take_custom_fields(value.token);
330 crate::host::type_::from_tokens::<Constructor::Fields, Profile>(self.runtime, &fields)
331 }
332
333 pub fn construct_custom<Constructor>(
335 &mut self,
336 _construction: HostConstruction<'call, Constructor::Custom>,
337 fields: <Constructor::Fields as HostTypeSequence>::Values<'call>,
338 ) -> HostCustom<'call, Constructor::Custom>
339 where
340 Constructor: HostCustomConstructor,
341 Constructor::Fields: HostTypeSequence,
342 {
343 let mut output = Vec::new();
344 crate::host::type_::into_scoped_values::<Constructor::Fields>(fields, &mut output);
345 let value = self.runtime.build_custom(
346 &crate::host::HostTypeDescriptor::of::<Constructor::Custom>(),
347 crate::host::type_::custom_constructor_index::<Constructor>(),
348 output.into_boxed_slice(),
349 );
350 HostCustom::new(self.runtime.custom_token(value))
351 }
352
353 pub fn external_payload<Schema, Arguments>(
355 &self,
356 value: HostExternal<'call, HostExternalType<Schema, Arguments>>,
357 ) -> HostExternalPayloadView<'call, BoundExternalPayload<Profile, Provider, Schema>, Arguments>
358 where
359 Schema: HostExternalSchema,
360 Provider: HostExternalBinding<Profile, Schema>,
361 Arguments: HostTypeSequence,
362 {
363 self.external_payload_with::<Provider, Schema, Arguments>(value)
364 }
365
366 #[doc(hidden)]
367 pub fn external_payload_with<Binding, Schema, Arguments>(
368 &self,
369 value: HostExternal<'call, HostExternalType<Schema, Arguments>>,
370 ) -> HostExternalPayloadView<'call, BoundExternalPayload<Profile, Binding, Schema>, Arguments>
371 where
372 Schema: HostExternalSchema,
373 Binding: HostExternalBinding<Profile, Schema>,
374 Arguments: HostTypeSequence,
375 {
376 let lease = self.runtime.external_lease(value.token);
377 HostExternalPayloadView::new(
378 BoundExternalStorage::<Profile, Binding, Schema>::store(self.runtime.external_stores())
379 .view(&lease),
380 )
381 }
382
383 pub(crate) fn restore_stored<Type, Stored>(
384 &mut self,
385 value: &HostStoredValue<Stored>,
386 ) -> Type::Value<'call>
387 where
388 Type: HostType,
389 {
390 self.restore_runtime_value::<Type>(&value.value)
391 }
392
393 #[doc(hidden)]
394 pub fn provider_store<Stored, Type>(
395 &mut self,
396 value: Type::Value<'call>,
397 ) -> HostStoredValue<Stored>
398 where
399 Type: HostType,
400 {
401 HostStoredValue::new(
402 self.runtime
403 .retain_stored(crate::host::type_::into_scoped::<Type>(value)),
404 )
405 }
406
407 #[doc(hidden)]
408 pub fn provider_restore<Type, Stored>(
409 &mut self,
410 value: &HostStoredValue<Stored>,
411 ) -> Type::Value<'call>
412 where
413 Type: HostType,
414 {
415 self.restore_stored::<Type, Stored>(value)
416 }
417
418 #[doc(hidden)]
419 pub fn provider_store_dynamic<Type>(
420 &mut self,
421 value: Type::Value<'call>,
422 ) -> crate::HostStoredDynamic
423 where
424 Type: HostType,
425 {
426 crate::HostStoredDynamic::new(
427 self.runtime
428 .retain_stored(crate::host::type_::into_scoped::<Type>(value)),
429 )
430 }
431
432 #[doc(hidden)]
433 pub fn provider_restore_dynamic<Type>(
434 &mut self,
435 value: &crate::HostStoredDynamic,
436 ) -> Option<Type::Value<'call>>
437 where
438 Type: HostType,
439 {
440 value.decode::<Profile, Provider, Return, Type>(self)
441 }
442
443 pub(in crate::host) fn restore_runtime_value<Type>(
444 &mut self,
445 value: &crate::runtime::StoredRuntimeValue,
446 ) -> Type::Value<'call>
447 where
448 Type: HostType,
449 {
450 let token = self.runtime.restore_stored(value);
451 crate::host::type_::from_token::<Type, Profile>(self.runtime, token)
452 }
453
454 pub(in crate::host) fn resolve_host_type<Type: HostType>(
455 &self,
456 ) -> Option<crate::plan::ValueType> {
457 self.runtime
458 .resolve_host_type(&crate::host::HostTypeDescriptor::of::<Type>())
459 }
460
461 pub fn invoke<Arguments, FunctionReturn>(
501 &mut self,
502 function: crate::host::HostCallable<'call, Arguments, FunctionReturn>,
503 arguments: Arguments::Values<'call>,
504 ) -> Result<FunctionReturn::Value<'call>, crate::HostCallError>
505 where
506 Arguments: HostTypeSequence,
507 FunctionReturn: HostType,
508 {
509 let mut values = Vec::new();
510 crate::host::type_::into_scoped_values::<Arguments>(arguments, &mut values);
511 let returned = self
512 .runtime
513 .invoke(function.token, values.into_boxed_slice())?;
514 Ok(crate::host::type_::from_token::<FunctionReturn, Profile>(
515 self.runtime,
516 returned,
517 ))
518 }
519
520 pub fn construct_external_with<Schema, Arguments>(
522 &mut self,
523 _construction: HostConstruction<'call, HostExternalType<Schema, Arguments>>,
524 build: impl FnOnce(
525 &mut HostExternalPayloadBuilder<'_, Profile, Arguments>,
526 ) -> BoundExternalPayload<Profile, Provider, Schema>,
527 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
528 where
529 Schema: HostExternalSchema,
530 Provider: HostExternalBinding<Profile, Schema>,
531 Arguments: HostTypeSequence,
532 HostExternalType<Schema, Arguments>: HostType,
533 {
534 let value = {
535 let mut builder = HostExternalPayloadBuilder::new(self.runtime);
536 build(&mut builder)
537 };
538 let lease = self.insert_external_payload_with::<Provider, Schema, Arguments>(value);
539 HostExternal::new(self.runtime.build_external(
540 &crate::host::HostTypeDescriptor::of::<HostExternalType<Schema, Arguments>>(),
541 lease,
542 ))
543 }
544
545 #[doc(hidden)]
548 pub fn construct_retained_external_with_binding<Binding, Schema, Arguments>(
549 &mut self,
550 _construction: HostConstruction<'call, HostExternalType<Schema, Arguments>>,
551 build: impl FnOnce(
552 &mut HostExternalPayloadBuilder<'_, Profile, Arguments>,
553 ) -> BoundExternalPayload<Profile, Binding, Schema>,
554 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
555 where
556 Schema: HostExternalSchema,
557 Binding: HostExternalBinding<Profile, Schema>,
558 Arguments: HostTypeSequence,
559 HostExternalType<Schema, Arguments>: HostType,
560 {
561 let value = {
562 let mut builder = HostExternalPayloadBuilder::new(self.runtime);
563 build(&mut builder)
564 };
565 self.seal_constructed_external_with::<Binding, Schema, Arguments>(value)
566 }
567}
568
569impl<'call, Profile, Provider, Schema, Arguments>
570 HostCall<'call, Profile, Provider, HostExternalType<Schema, Arguments>>
571where
572 Profile: HostProfile,
573 Provider: HostProvider<Profile>,
574 Schema: HostExternalSchema,
575 Arguments: HostTypeSequence,
576 HostExternalType<Schema, Arguments>: HostType,
577{
578 pub fn create_external(
579 &mut self,
580 value: BoundExternalPayload<Profile, Provider, Schema>,
581 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
582 where
583 Provider: HostExternalBinding<Profile, Schema>,
584 {
585 self.create_external_with_binding::<Provider>(value)
586 }
587
588 #[doc(hidden)]
589 pub fn create_external_with_binding<Binding>(
590 &mut self,
591 value: BoundExternalPayload<Profile, Binding, Schema>,
592 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
593 where
594 Binding: HostExternalBinding<Profile, Schema>,
595 {
596 self.seal_external_payload_with::<Binding>(value)
597 }
598
599 pub fn create_external_with(
601 &mut self,
602 build: impl FnOnce(
603 &mut HostExternalPayloadBuilder<'_, Profile, Arguments>,
604 ) -> BoundExternalPayload<Profile, Provider, Schema>,
605 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
606 where
607 Provider: HostExternalBinding<Profile, Schema>,
608 {
609 let value = {
610 let mut builder = HostExternalPayloadBuilder::new(self.runtime);
611 build(&mut builder)
612 };
613 self.seal_external_payload_with::<Provider>(value)
614 }
615
616 fn seal_external_payload_with<Binding>(
617 &mut self,
618 value: BoundExternalPayload<Profile, Binding, Schema>,
619 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
620 where
621 Binding: HostExternalBinding<Profile, Schema>,
622 {
623 let lease = self.insert_external_payload_with::<Binding, Schema, Arguments>(value);
624 HostExternal::new(self.runtime.build_external(
625 &crate::host::HostTypeDescriptor::of::<HostExternalType<Schema, Arguments>>(),
626 lease,
627 ))
628 }
629}
630
631impl<'call, Profile, Provider, Return> HostCall<'call, Profile, Provider, Return>
632where
633 Profile: HostProfile,
634 Provider: HostProvider<Profile>,
635 Return: HostType,
636{
637 pub fn construct_external<Schema, Arguments>(
639 &mut self,
640 _construction: HostConstruction<'call, HostExternalType<Schema, Arguments>>,
641 value: BoundExternalPayload<Profile, Provider, Schema>,
642 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
643 where
644 Schema: HostExternalSchema,
645 Provider: HostExternalBinding<Profile, Schema>,
646 Arguments: HostTypeSequence,
647 HostExternalType<Schema, Arguments>: HostType,
648 {
649 self.construct_external_with_binding::<Provider, Schema, Arguments>(_construction, value)
650 }
651
652 #[doc(hidden)]
653 pub fn construct_external_with_binding<Binding, Schema, Arguments>(
654 &mut self,
655 _construction: HostConstruction<'call, HostExternalType<Schema, Arguments>>,
656 value: BoundExternalPayload<Profile, Binding, Schema>,
657 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
658 where
659 Schema: HostExternalSchema,
660 Binding: HostExternalBinding<Profile, Schema>,
661 Arguments: HostTypeSequence,
662 HostExternalType<Schema, Arguments>: HostType,
663 {
664 self.seal_constructed_external_with::<Binding, Schema, Arguments>(value)
665 }
666
667 fn seal_constructed_external_with<Binding, Schema, Arguments>(
668 &mut self,
669 value: BoundExternalPayload<Profile, Binding, Schema>,
670 ) -> HostExternal<'call, HostExternalType<Schema, Arguments>>
671 where
672 Schema: HostExternalSchema,
673 Binding: HostExternalBinding<Profile, Schema>,
674 Arguments: HostTypeSequence,
675 HostExternalType<Schema, Arguments>: HostType,
676 {
677 let lease = self.insert_external_payload_with::<Binding, Schema, Arguments>(value);
678 HostExternal::new(self.runtime.build_external(
679 &crate::host::HostTypeDescriptor::of::<HostExternalType<Schema, Arguments>>(),
680 lease,
681 ))
682 }
683
684 fn insert_external_payload_with<Binding, Schema, Arguments>(
685 &self,
686 value: BoundExternalPayload<Profile, Binding, Schema>,
687 ) -> crate::host::ExternalPayloadLease
688 where
689 Schema: HostExternalSchema,
690 Binding: HostExternalBinding<Profile, Schema>,
691 Arguments: HostTypeSequence,
692 HostExternalType<Schema, Arguments>: HostType,
693 {
694 BoundExternalStorage::<Profile, Binding, Schema>::store(self.runtime.external_stores())
695 .insert(
696 value,
697 BoundExternalStorage::<Profile, Binding, Schema>::source_equal,
698 BoundExternalStorage::<Profile, Binding, Schema>::source_hash,
699 BoundExternalStorage::<Profile, Binding, Schema>::inspect,
700 )
701 }
702}
703
704impl<'call, Profile, Provider, Item> HostCall<'call, Profile, Provider, HostListType<Item>>
705where
706 Profile: HostProfile,
707 Provider: HostProvider<Profile>,
708 Item: HostType,
709{
710 pub fn return_list(
711 self,
712 values: impl IntoIterator<Item = Item::Value<'call>>,
713 ) -> HostCallCompletion<'call, HostListType<Item>> {
714 let values = values
715 .into_iter()
716 .map(crate::host::type_::into_scoped::<Item>)
717 .collect::<Vec<_>>()
718 .into_boxed_slice();
719 HostCallCompletion::new(self.runtime.build_list(
720 &crate::host::HostTypeDescriptor::of::<HostListType<Item>>(),
721 values,
722 ))
723 }
724}
725
726impl<'call, Profile, Provider, Elements> HostCall<'call, Profile, Provider, HostTupleType<Elements>>
727where
728 Profile: HostProfile,
729 Provider: HostProvider<Profile>,
730 Elements: HostTypeSequence,
731{
732 pub fn return_tuple(
733 self,
734 values: <Elements as crate::host::HostTypeSequence>::Values<'call>,
735 ) -> HostCallCompletion<'call, HostTupleType<Elements>> {
736 let mut output = Vec::new();
737 crate::host::type_::into_scoped_values::<Elements>(values, &mut output);
738 HostCallCompletion::new(self.runtime.build_tuple(output.into_boxed_slice()))
739 }
740}
741
742impl<'call, Profile, Provider, Schema, Arguments>
743 HostCall<'call, Profile, Provider, HostCustomType<Schema, Arguments>>
744where
745 Profile: HostProfile,
746 Provider: HostProvider<Profile>,
747 Schema: crate::host::HostCustomSchema,
748 Arguments: HostTypeSequence,
749{
750 pub fn return_custom<Constructor>(
751 self,
752 fields: <Constructor::Fields as crate::host::HostTypeSequence>::Values<'call>,
753 ) -> HostCallCompletion<'call, HostCustomType<Schema, Arguments>>
754 where
755 Constructor: HostCustomConstructor<Custom = HostCustomType<Schema, Arguments>>,
756 Constructor::Fields: HostTypeSequence,
757 {
758 let mut output = Vec::new();
759 crate::host::type_::into_scoped_values::<Constructor::Fields>(fields, &mut output);
760 HostCallCompletion::new(self.runtime.build_custom(
761 &crate::host::HostTypeDescriptor::of::<HostCustomType<Schema, Arguments>>(),
762 crate::host::type_::custom_constructor_index::<Constructor>(),
763 output.into_boxed_slice(),
764 ))
765 }
766}
767
768#[cfg(test)]
769mod tests {
770 use super::{HostCall, HostProvider};
771 use crate::BitArrayValue;
772 use crate::host::function::CallArguments;
773 use crate::host::test::{
774 StatelessTestProvider, TestHostCallRuntime, TestHostProfile, TestRunState,
775 };
776 use crate::host::{
777 HostCallable, HostConstructions, HostCustom, HostCustomConstructorAt,
778 HostCustomConstructorDefinition, HostCustomConstructorList, HostCustomConstructorListEnd,
779 HostCustomConstructorSchema, HostCustomFieldListEnd, HostCustomFieldSchema,
780 HostCustomIndex0, HostCustomIndexNext, HostCustomSchema, HostCustomToken, HostCustomType,
781 HostCustomTypeSchema, HostFunctionToken, HostFunctionType, HostList, HostListToken,
782 HostListType, HostScopedValue, HostTuple, HostTupleToken, HostTupleType, HostTypeIndex0,
783 HostTypeIndexNext, HostTypeList, HostTypeListEnd, HostTypeParameter, HostValue,
784 HostValueFamily, HostValueToken, StatelessHostProfile,
785 };
786 use crate::provider::{ProviderListItemDecoder, ProviderListItemValue};
787 use ecow::EcoString;
788 use num_bigint::BigInt;
789
790 struct Counter;
791
792 struct IntListDecoder;
793
794 impl ProviderListItemDecoder<BigInt> for IntListDecoder {
795 type View = BigInt;
796
797 fn decode(&self, value: ProviderListItemValue) -> Self::View {
798 value.into_scalar()
799 }
800 }
801
802 impl HostProvider<TestHostProfile> for Counter {
803 type State = usize;
804
805 fn project(state: &mut TestRunState) -> &mut Self::State {
806 &mut state.counter
807 }
808 }
809
810 struct MarkerSchema;
811
812 struct MarkerConstructor;
813
814 impl HostCustomConstructorDefinition for MarkerConstructor {
815 const NAME: &'static str = "Marker";
816
817 type Fields = HostCustomFieldListEnd;
818 }
819
820 struct OtherConstructor;
821
822 impl HostCustomConstructorDefinition for OtherConstructor {
823 const NAME: &'static str = "Other";
824
825 type Fields = HostCustomFieldListEnd;
826 }
827
828 impl HostCustomSchema for MarkerSchema {
829 const PACKAGE: &'static str = "domain";
830 const MODULE: &'static str = "domain/marker";
831 const NAME: &'static str = "Marker";
832 const PARAMETER_COUNT: usize = 0;
833
834 type Constructors = HostCustomConstructorList<
835 MarkerConstructor,
836 HostCustomConstructorList<OtherConstructor, HostCustomConstructorListEnd>,
837 >;
838 }
839
840 type MarkerType = HostCustomType<MarkerSchema>;
841 type Marker = HostCustomConstructorAt<MarkerType, HostCustomIndex0, MarkerConstructor>;
842 type Other = HostCustomConstructorAt<
843 MarkerType,
844 HostCustomIndexNext<HostCustomIndex0>,
845 OtherConstructor,
846 >;
847
848 #[test]
849 fn host_call_exposes_only_the_selected_provider_state() {
850 let mut state = TestRunState {
851 counter: 1,
852 unrelated: true,
853 };
854 let arguments = crate::host::function::CallArguments::new(Vec::new(), Vec::new());
855 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
856
857 *HostCall::<TestHostProfile, Counter, bool>::new(&mut runtime).state() += 1;
858
859 assert_eq!(state.counter, 2);
860 assert!(state.unrelated);
861 }
862
863 #[test]
864 fn stateless_provider_projects_the_complete_run_state() {
865 let mut state = ();
866
867 let projected =
868 <StatelessTestProvider as HostProvider<StatelessHostProfile>>::project(&mut state);
869
870 assert_eq!(*projected, ());
871 }
872
873 #[test]
874 fn host_call_reads_and_compares_call_scoped_values() {
875 type EmptyTuple = HostTupleType<HostTypeListEnd>;
876
877 assert_eq!(
878 HostCustomTypeSchema::of::<MarkerSchema>(),
879 HostCustomTypeSchema::new(
880 "domain",
881 "domain/marker",
882 "Marker",
883 0,
884 [
885 HostCustomConstructorSchema::new("Marker", Vec::<HostCustomFieldSchema>::new(),),
886 HostCustomConstructorSchema::new("Other", Vec::<HostCustomFieldSchema>::new(),),
887 ],
888 ),
889 );
890 let mut state = TestRunState::default();
891 let arguments = CallArguments::new(Vec::new(), Vec::new());
892 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
893 let mut call = HostCall::<TestHostProfile, Counter, bool>::new(&mut runtime);
894 let list = HostList::<BigInt>::new(HostListToken::Stored(0));
895 let tuple = HostTuple::<HostTypeListEnd>::new(HostTupleToken(0));
896 let custom = HostCustom::<MarkerType>::new(HostCustomToken(0));
897
898 assert_eq!(call.list_len(list), 0);
899 assert_eq!(call.list_item(list, 0), None);
900 assert_eq!(call.tuple_len(tuple), 0);
901 assert_eq!(call.tuple_values::<HostTypeListEnd>(tuple), ());
902 assert_eq!(call.custom_constructor(custom), 0);
903 assert_eq!(call.custom_fields::<Marker>(custom), Some(()),);
904 assert_eq!(call.custom_fields::<Other>(custom), None,);
905 assert_eq!(call.provider_custom_fields::<Marker>(custom), Some(()),);
906 assert_eq!(call.provider_custom_fields::<Other>(custom), None,);
907 assert_eq!(call.provider_remaining_custom_fields::<Marker>(custom), ());
908 assert!(!call.equal::<BigInt>(1.into(), 1.into()));
909 assert!(!call.equal::<HostListType<BigInt>>(list, list));
910 assert!(!call.equal::<EmptyTuple>(tuple, tuple));
911 assert!(!call.equal::<MarkerType>(custom, custom));
912 assert_eq!(call.source_hash::<BigInt>(1.into()), 17);
913 assert_eq!(call.inspect::<BigInt>(1.into()), "inspected");
914 }
915
916 #[test]
917 fn host_call_completes_every_scalar_and_scoped_handle_family() {
918 type Parameter = HostTypeParameter<0>;
919 type List = HostListType<BigInt>;
920 type Tuple = HostTupleType<HostTypeListEnd>;
921
922 let mut state = TestRunState::default();
923 let arguments = CallArguments::new(Vec::new(), Vec::new());
924 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
925 let parameter = HostValue::<Parameter>::new(HostValueToken {
926 family: HostValueFamily::Bool,
927 index: 4,
928 });
929 let list = HostList::<BigInt>::new(HostListToken::Stored(0));
930 let tuple = HostTuple::<HostTypeListEnd>::new(HostTupleToken(0));
931 let custom = HostCustom::<MarkerType>::new(HostCustomToken(0));
932
933 let tokens = [
934 HostCall::<TestHostProfile, Counter, BigInt>::new(&mut runtime)
935 .return_value(1.into())
936 .token,
937 HostCall::<TestHostProfile, Counter, f64>::new(&mut runtime)
938 .return_value(1.5)
939 .token,
940 HostCall::<TestHostProfile, Counter, EcoString>::new(&mut runtime)
941 .return_value("text".into())
942 .token,
943 HostCall::<TestHostProfile, Counter, BitArrayValue>::new(&mut runtime)
944 .return_value(BitArrayValue::from_bytes(vec![1]))
945 .token,
946 HostCall::<TestHostProfile, Counter, char>::new(&mut runtime)
947 .return_value('A')
948 .token,
949 HostCall::<TestHostProfile, Counter, bool>::new(&mut runtime)
950 .return_value(true)
951 .token,
952 HostCall::<TestHostProfile, Counter, ()>::new(&mut runtime)
953 .return_value(())
954 .token,
955 HostCall::<TestHostProfile, Counter, Parameter>::new(&mut runtime)
956 .return_value(parameter)
957 .token,
958 HostCall::<TestHostProfile, Counter, List>::new(&mut runtime)
959 .return_value(list)
960 .token,
961 HostCall::<TestHostProfile, Counter, Tuple>::new(&mut runtime)
962 .return_value(tuple)
963 .token,
964 HostCall::<TestHostProfile, Counter, MarkerType>::new(&mut runtime)
965 .return_value(custom)
966 .token,
967 ];
968
969 assert_eq!(
970 tokens.map(|token| token.family),
971 [
972 HostValueFamily::Int,
973 HostValueFamily::Float,
974 HostValueFamily::String,
975 HostValueFamily::BitArray,
976 HostValueFamily::UtfCodepoint,
977 HostValueFamily::Bool,
978 HostValueFamily::Nil,
979 HostValueFamily::Bool,
980 HostValueFamily::List,
981 HostValueFamily::Tuple,
982 HostValueFamily::Custom,
983 ],
984 );
985 assert_eq!(tokens[7].index, 4);
986 }
987
988 #[test]
989 fn host_call_builds_typed_compound_returns() {
990 type List = HostListType<BigInt>;
991 type Tuple = HostTupleType<HostTypeListEnd>;
992 type Constructions =
993 HostTypeList<List, HostTypeList<Tuple, HostTypeList<MarkerType, HostTypeListEnd>>>;
994 type TupleIndex = HostTypeIndexNext<HostTypeIndex0>;
995 type CustomIndex = HostTypeIndexNext<TupleIndex>;
996
997 let mut state = TestRunState::default();
998 let arguments = CallArguments::new(Vec::new(), Vec::new());
999 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
1000
1001 let list = HostCall::<TestHostProfile, Counter, List>::new(&mut runtime)
1002 .return_list([BigInt::from(1), BigInt::from(2)])
1003 .token;
1004 let mut call = HostCall::<TestHostProfile, Counter, Tuple>::new(&mut runtime);
1005 let constructions = HostConstructions::<Constructions>::new();
1006 let nested_list =
1007 call.construct_list(constructions.at::<HostTypeIndex0>(), [BigInt::from(3)]);
1008 let nested_tuple = call.construct_tuple(constructions.at::<TupleIndex>(), ());
1009 let nested_custom = call.construct_custom::<Marker>(constructions.at::<CustomIndex>(), ());
1010 assert_eq!(nested_list.token, HostListToken::Stored(0));
1011 assert_eq!(nested_tuple.token, HostTupleToken(0));
1012 assert_eq!(nested_custom.token, HostCustomToken(0));
1013 let tuple = call.return_tuple(()).token;
1014 let custom = HostCall::<TestHostProfile, Counter, MarkerType>::new(&mut runtime)
1015 .return_custom::<Marker>(())
1016 .token;
1017
1018 assert_eq!(list.family, HostValueFamily::List);
1019 assert_eq!(tuple.family, HostValueFamily::Tuple);
1020 assert_eq!(custom.family, HostValueFamily::Custom);
1021 assert_eq!(runtime.list_builds(), 2);
1022 }
1023
1024 #[test]
1025 fn returning_an_existing_list_does_not_build_a_new_list() {
1026 type List = HostListType<BigInt>;
1027
1028 let mut state = TestRunState::default();
1029 {
1030 let arguments = CallArguments::new(Vec::new(), Vec::new());
1031 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
1032 let existing = HostList::<BigInt>::new(HostListToken::Stored(0));
1033 let retained = HostCall::<TestHostProfile, Counter, List>::new(&mut runtime)
1034 .provider_list(existing, IntListDecoder);
1035
1036 assert_eq!(retained.len(), 1);
1037 assert_eq!(retained.get(0), Some(BigInt::from(1)));
1038 }
1039
1040 let arguments = CallArguments::new(Vec::new(), Vec::new());
1041 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
1042 let existing = HostList::<BigInt>::new(HostListToken::Stored(0));
1043
1044 let returned = HostCall::<TestHostProfile, Counter, List>::new(&mut runtime)
1045 .return_value(existing)
1046 .token;
1047
1048 assert_eq!(returned.family, HostValueFamily::List);
1049 assert_eq!(runtime.list_builds(), 0);
1050
1051 HostCall::<TestHostProfile, Counter, List>::new(&mut runtime)
1052 .return_list([BigInt::from(1), BigInt::from(2)]);
1053 assert_eq!(runtime.list_builds(), 1);
1054 }
1055
1056 #[test]
1057 fn host_call_invokes_and_completes_typed_function_handles() {
1058 type Arguments = HostTypeList<BigInt, HostTypeListEnd>;
1059 type Function = HostFunctionType<Arguments, BigInt>;
1060
1061 let mut state = TestRunState::default();
1062 let arguments = CallArguments::new(Vec::new(), Vec::new());
1063 let mut runtime = TestHostCallRuntime::new(&mut state, arguments);
1064 let callable = HostCallable::<Arguments, BigInt>::new(HostFunctionToken(0));
1065 let returned = HostCall::<TestHostProfile, Counter, BigInt>::new(&mut runtime)
1066 .invoke(callable, (BigInt::from(7), ()))
1067 .expect("test runtime should return the first callback argument");
1068
1069 assert_eq!(returned, BigInt::from(0));
1070 assert_eq!(
1071 runtime.completed(),
1072 Some(&HostScopedValue::Int(BigInt::from(7))),
1073 );
1074
1075 let completion = HostCall::<TestHostProfile, Counter, Function>::new(&mut runtime)
1076 .return_value(callable)
1077 .token;
1078 assert_eq!(completion.family, HostValueFamily::Function);
1079 assert_eq!(
1080 runtime.completed(),
1081 Some(&HostScopedValue::Function(HostFunctionToken(0))),
1082 );
1083
1084 let empty = HostCallable::<HostTypeListEnd, ()>::new(HostFunctionToken(1));
1085 HostCall::<TestHostProfile, Counter, ()>::new(&mut runtime)
1086 .invoke(empty, ())
1087 .expect("zero-argument test callback should return Nil");
1088 }
1089}