Skip to main content

hydro_lang/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![cfg_attr(not(stageleft_trybuild), warn(missing_docs))]
3
4//! Hydro is a high-level distributed programming framework for Rust.
5//! Hydro can help you quickly write scalable distributed services that are correct by construction.
6//! Much like Rust helps with memory safety, Hydro helps with [distributed safety](https://hydro.run/docs/hydro/reference/correctness).
7//!
8//! The core Hydro API involves [live collections](https://hydro.run/docs/hydro/reference/live-collections/), which represent asynchronously
9//! updated sources of data such as incoming network requests and application state. The most common live collection is
10//! [`live_collections::stream::Stream`]; other live collections can be found in [`live_collections`].
11//!
12//! Hydro uses a unique compilation approach where you define deployment logic as Rust code alongside your distributed system implementation.
13//! For more details on this API, see the [Hydro docs](https://hydro.run/docs/hydro/reference/deploy/) and the [`deploy`] module.
14
15stageleft::stageleft_no_entry_crate!();
16
17#[cfg(feature = "runtime_support")]
18#[cfg_attr(docsrs, doc(cfg(feature = "runtime_support")))]
19#[doc(hidden)]
20pub mod runtime_support {
21    #[cfg(feature = "sim")]
22    pub use colored;
23    #[cfg(feature = "deploy_integration")]
24    pub use hydro_deploy_integration;
25    pub use {bincode, dfir_rs, slotmap, stageleft, tokio};
26
27    #[cfg(any(feature = "deploy_integration", feature = "docker_runtime"))]
28    pub mod launch;
29}
30
31#[doc(hidden)]
32pub mod macro_support {
33    pub use copy_span;
34}
35
36pub mod prelude {
37    // taken from `tokio`
38    //! A "prelude" for users of the `hydro_lang` crate.
39    //!
40    //! This prelude is similar to the standard library's prelude in that you'll almost always want to import its entire contents, but unlike the standard library's prelude you'll have to do so manually:
41    //! ```
42    //! # #![allow(warnings)]
43    //! use hydro_lang::prelude::*;
44    //! ```
45    //!
46    //! The prelude may grow over time as additional items see ubiquitous use.
47
48    pub use stageleft::q;
49
50    pub use crate::compile::builder::FlowBuilder;
51    pub use crate::live_collections::boundedness::{Bounded, Unbounded};
52    pub use crate::live_collections::keyed_singleton::KeyedSingleton;
53    pub use crate::live_collections::keyed_stream::KeyedStream;
54    pub use crate::live_collections::optional::Optional;
55    pub use crate::live_collections::singleton::Singleton;
56    pub use crate::live_collections::sliced::sliced;
57    pub use crate::live_collections::stream::Stream;
58    pub use crate::location::{Cluster, External, Location as _, Process, Tick};
59    pub use crate::networking::TCP;
60    pub use crate::nondet::{NonDet, nondet};
61    pub use crate::properties::ManualProof;
62
63    /// A macro to set up a Hydro crate.
64    #[macro_export]
65    macro_rules! setup {
66        () => {
67            stageleft::stageleft_no_entry_crate!();
68
69            #[cfg(test)]
70            mod test_init {
71                #[ctor::ctor]
72                fn init() {
73                    $crate::compile::init_test();
74                }
75            }
76        };
77    }
78}
79
80#[cfg(feature = "dfir_context")]
81#[cfg_attr(docsrs, doc(cfg(feature = "dfir_context")))]
82pub mod runtime_context;
83
84pub mod nondet;
85
86pub mod live_collections;
87
88pub mod location;
89
90pub mod networking;
91
92pub mod properties;
93
94pub mod telemetry;
95
96#[cfg(any(
97    feature = "deploy",
98    feature = "deploy_integration" // hidden internal feature enabled in the trybuild
99))]
100#[cfg_attr(docsrs, doc(cfg(feature = "deploy")))]
101pub mod deploy;
102
103#[cfg(feature = "sim")]
104#[cfg_attr(docsrs, doc(cfg(feature = "sim")))]
105pub mod sim;
106
107pub mod forward_handle;
108
109pub mod compile;
110
111mod manual_expr;
112
113#[cfg(stageleft_runtime)]
114#[cfg(feature = "viz")]
115#[cfg_attr(docsrs, doc(cfg(feature = "viz")))]
116#[expect(missing_docs, reason = "TODO")]
117pub mod viz;
118
119#[cfg_attr(
120    feature = "stageleft_macro_entrypoint",
121    expect(missing_docs, reason = "staging internals")
122)]
123mod staging_util;
124
125#[cfg(feature = "deploy")]
126#[cfg_attr(docsrs, doc(cfg(feature = "deploy")))]
127pub mod test_util;
128
129#[cfg(feature = "build")]
130#[ctor::ctor]
131fn init_rewrites() {
132    stageleft::add_private_reexport(
133        vec!["tokio_util", "codec", "lines_codec"],
134        vec!["tokio_util", "codec"],
135    );
136}
137
138#[cfg(all(test, feature = "trybuild"))]
139mod test_init {
140    #[ctor::ctor]
141    fn init() {
142        crate::compile::init_test();
143    }
144}
145
146/// Creates a newtype wrapper around an integer type.
147///
148/// Usage:
149/// ```rust
150/// hydro_lang::newtype_counter! {
151///     /// My counter.
152///     pub struct MyCounter(u32);
153///
154///     /// My secret counter.
155///     struct SecretCounter(u64);
156/// }
157/// ```
158#[doc(hidden)]
159#[macro_export]
160macro_rules! newtype_counter {
161    (
162        $(
163            $( #[$attr:meta] )*
164            $vis:vis struct $name:ident($typ:ty);
165        )*
166    ) => {
167        $(
168            $( #[$attr] )*
169            #[repr(transparent)]
170            #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
171            $vis struct $name($typ);
172
173            #[allow(clippy::allow_attributes, dead_code, reason = "macro-generated methods may be unused")]
174            impl $name {
175                /// Gets the current ID and increments for the next.
176                pub fn get_and_increment(&mut self) -> Self {
177                    let id = self.0;
178                    self.0 += 1;
179                    Self(id)
180                }
181
182                /// Returns an iterator from zero up to (but excluding) `self`.
183                ///
184                /// This is useful for iterating already-allocated values.
185                pub fn range_up_to(&self) -> impl std::iter::DoubleEndedIterator<Item = Self>
186                    + std::iter::FusedIterator
187                {
188                    (0..self.0).map(Self)
189                }
190
191                /// Reveals the inner ID.
192                pub fn into_inner(self) -> $typ {
193                    self.0
194                }
195            }
196
197            impl std::fmt::Display for $name {
198                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199                    write!(f, "{}", self.0)
200                }
201            }
202
203            impl serde::ser::Serialize for $name {
204                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
205                where
206                    S: serde::Serializer
207                {
208                    serde::ser::Serialize::serialize(&self.0, serializer)
209                }
210            }
211
212            impl<'de> serde::de::Deserialize<'de> for $name {
213                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
214                where
215                    D: serde::Deserializer<'de>
216                {
217                    serde::de::Deserialize::deserialize(deserializer).map(Self)
218                }
219            }
220        )*
221    };
222}