hydro_lang/
forward_handle.rs

1//! Mechanisms for introducing forward references and cycles in Hydro.
2
3use sealed::sealed;
4
5use crate::location::Location;
6use crate::location::dynamic::LocationId;
7use crate::staging_util::Invariant;
8
9#[sealed]
10pub(crate) trait ReceiverKind {}
11
12/// Marks that the [`ForwardHandle`] is for a "forward reference" to a later-defined collection.
13///
14/// When the handle is completed, the provided collection must not depend _synchronously_
15/// (in the same tick) on the forward reference that was created earlier.
16pub enum ForwardRef {}
17
18#[sealed]
19impl ReceiverKind for ForwardRef {}
20
21/// Marks that the [`ForwardHandle`] will send a live collection to the next tick.
22///
23/// Dependency cycles are permitted for this handle type, because the collection used
24/// to complete this handle will appear on the source-side on the _next_ tick.
25pub enum TickCycle {}
26
27#[sealed]
28impl ReceiverKind for TickCycle {}
29
30pub(crate) trait ReceiverComplete<'a, Marker>
31where
32    Marker: ReceiverKind,
33{
34    fn complete(self, ident: syn::Ident, expected_location: LocationId);
35}
36
37pub(crate) trait CycleCollection<'a, Kind>: ReceiverComplete<'a, Kind>
38where
39    Kind: ReceiverKind,
40{
41    type Location: Location<'a>;
42
43    fn create_source(ident: syn::Ident, location: Self::Location) -> Self;
44}
45
46pub(crate) trait CycleCollectionWithInitial<'a, Kind>: ReceiverComplete<'a, Kind>
47where
48    Kind: ReceiverKind,
49{
50    type Location: Location<'a>;
51
52    fn create_source_with_initial(
53        ident: syn::Ident,
54        initial: Self,
55        location: Self::Location,
56    ) -> Self;
57}
58
59#[expect(
60    private_bounds,
61    reason = "only Hydro collections can implement ReceiverComplete"
62)]
63/// A handle that can be used to fulfill a forward reference.
64///
65/// The `C` type parameter specifies the collection type that can be used to complete the handle.
66pub struct ForwardHandle<'a, C: ReceiverComplete<'a, ForwardRef>> {
67    pub(crate) completed: bool,
68    pub(crate) ident: syn::Ident,
69    pub(crate) expected_location: LocationId,
70    pub(crate) _phantom: Invariant<'a, C>,
71}
72
73impl<'a, C: ReceiverComplete<'a, ForwardRef>> Drop for ForwardHandle<'a, C> {
74    fn drop(&mut self) {
75        if !self.completed {
76            panic!("ForwardHandle dropped without being completed");
77        }
78    }
79}
80
81#[expect(
82    private_bounds,
83    reason = "only Hydro collections can implement ReceiverComplete"
84)]
85impl<'a, C: ReceiverComplete<'a, ForwardRef>> ForwardHandle<'a, C> {
86    /// Completes the forward reference with the given live collection. The initial forward reference
87    /// collection created in [`Location::forward_ref`] will resolve to this value.
88    ///
89    /// The provided value **must not** depend _synchronously_ (in the same tick) on the forward reference
90    /// collection, as doing so would create a dependency cycle. Asynchronous cycles (outside a tick) are
91    /// allowed, since the program can continue running while the cycle is processed.
92    pub fn complete(mut self, stream: impl Into<C>) {
93        self.completed = true;
94        let ident = self.ident.clone();
95        C::complete(stream.into(), ident, self.expected_location.clone())
96    }
97}
98
99#[expect(
100    private_bounds,
101    reason = "only Hydro collections can implement ReceiverComplete"
102)]
103/// A handle that can be used to complete a tick cycle by sending a collection to the next tick.
104///
105/// The `C` type parameter specifies the collection type that can be used to complete the handle.
106pub struct TickCycleHandle<'a, C: ReceiverComplete<'a, TickCycle>> {
107    pub(crate) completed: bool,
108    pub(crate) ident: syn::Ident,
109    pub(crate) expected_location: LocationId,
110    pub(crate) _phantom: Invariant<'a, C>,
111}
112
113impl<'a, C: ReceiverComplete<'a, TickCycle>> Drop for TickCycleHandle<'a, C> {
114    fn drop(&mut self) {
115        if !self.completed {
116            panic!("TickCycleHandle dropped without being completed");
117        }
118    }
119}
120
121#[expect(
122    private_bounds,
123    reason = "only Hydro collections can implement ReceiverComplete"
124)]
125impl<'a, C: ReceiverComplete<'a, TickCycle>> TickCycleHandle<'a, C> {
126    /// Sends the provided collection to the next tick, where it will be materialized
127    /// in the collection returned by [`crate::location::Tick::cycle`] or
128    /// [`crate::location::Tick::cycle_with_initial`].
129    pub fn complete_next_tick(mut self, stream: impl Into<C>) {
130        self.completed = true;
131        let ident = self.ident.clone();
132        C::complete(stream.into(), ident, self.expected_location.clone())
133    }
134}